[Spice-devel] [PATCH 02/17] Add reds_stream.[ch]

Christophe Fergeau cfergeau at redhat.com
Tue Jan 7 03:14:28 PST 2014


Gather common RedsStream code there rather than having it
in reds.c
---
 server/Makefile.am      |   2 +
 server/inputs_channel.c |   1 +
 server/red_channel.c    |   1 +
 server/red_channel.h    |   2 +-
 server/red_worker.c     |   1 +
 server/reds.c           | 181 +--------------------------------------
 server/reds.h           |  64 --------------
 server/reds_stream.c    | 220 ++++++++++++++++++++++++++++++++++++++++++++++++
 server/reds_stream.h    | 100 ++++++++++++++++++++++
 9 files changed, 327 insertions(+), 245 deletions(-)
 create mode 100644 server/reds_stream.c
 create mode 100644 server/reds_stream.h

diff --git a/server/Makefile.am b/server/Makefile.am
index 13c6223..34219c8 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -87,6 +87,8 @@ libspice_server_la_SOURCES =			\
 	reds.c					\
 	reds.h					\
 	reds-private.h				\
+	reds_stream.c				\
+	reds_stream.h				\
 	reds_sw_canvas.c			\
 	reds_sw_canvas.h			\
 	snd_worker.c				\
diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index dd8f5ae..8d4feab 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -37,6 +37,7 @@
 #include "spice.h"
 #include "red_common.h"
 #include "reds.h"
+#include "reds_stream.h"
 #include "red_channel.h"
 #include "main_channel.h"
 #include "inputs_channel.h"
diff --git a/server/red_channel.c b/server/red_channel.c
index 24a8b64..b81deeb 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -40,6 +40,7 @@
 #include "stat.h"
 #include "red_channel.h"
 #include "reds.h"
+#include "reds_stream.h"
 #include "main_dispatcher.h"
 #include "red_time.h"
 
diff --git a/server/red_channel.h b/server/red_channel.h
index 9e54dce..f638d3c 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -31,6 +31,7 @@
 #include "spice.h"
 #include "red_common.h"
 #include "demarshallers.h"
+#include "reds_stream.h"
 
 #define MAX_SEND_BUFS 1000
 #define CLIENT_ACK_WINDOW 20
@@ -131,7 +132,6 @@ typedef struct BufDescriptor {
     uint8_t *data;
 } BufDescriptor;
 
-typedef struct RedsStream RedsStream;
 typedef struct RedChannel RedChannel;
 typedef struct RedChannelClient RedChannelClient;
 typedef struct RedClient RedClient;
diff --git a/server/red_worker.c b/server/red_worker.c
index afbdd91..619f7bc 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -64,6 +64,7 @@
 
 #include "spice.h"
 #include "red_worker.h"
+#include "reds_stream.h"
 #include "reds_sw_canvas.h"
 #include "glz_encoder_dictionary.h"
 #include "glz_encoder.h"
diff --git a/server/reds.c b/server/reds.c
index 57791a0..81e90f3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -73,6 +73,7 @@
 #ifdef USE_SMARTCARD
 #include "smartcard.h"
 #endif
+#include "reds_stream.h"
 
 #include "reds-private.h"
 
@@ -184,11 +185,6 @@ static ChannelSecurityOptions *find_channel_security(int id)
     return now;
 }
 
-static void reds_stream_push_channel_event(RedsStream *s, int event)
-{
-    main_dispatcher_channel_event(event, s->info);
-}
-
 void reds_handle_channel_event(int event, SpiceChannelEventInfo *info)
 {
     if (core->base.minor_version >= 3 && core->channel_event != NULL)
@@ -266,14 +262,6 @@ static ssize_t stream_ssl_read_cb(RedsStream *s, void *buf, size_t size)
     return return_code;
 }
 
-static void reds_stream_remove_watch(RedsStream* s)
-{
-    if (s->watch) {
-        core->watch_remove(s->watch);
-        s->watch = NULL;
-    }
-}
-
 static void reds_link_free(RedLinkInfo *link)
 {
     reds_stream_free(link->stream);
@@ -1999,92 +1987,6 @@ static int sync_write_u32(RedsStream *s, uint32_t n)
 {
     return sync_write(s, &n, sizeof(uint32_t));
 }
-
-static ssize_t reds_stream_sasl_write(RedsStream *s, const void *buf, size_t nbyte)
-{
-    ssize_t ret;
-
-    if (!s->sasl.encoded) {
-        int err;
-        err = sasl_encode(s->sasl.conn, (char *)buf, nbyte,
-                          (const char **)&s->sasl.encoded,
-                          &s->sasl.encodedLength);
-        if (err != SASL_OK) {
-            spice_warning("sasl_encode error: %d", err);
-            return -1;
-        }
-
-        if (s->sasl.encodedLength == 0) {
-            return 0;
-        }
-
-        if (!s->sasl.encoded) {
-            spice_warning("sasl_encode didn't return a buffer!");
-            return 0;
-        }
-
-        s->sasl.encodedOffset = 0;
-    }
-
-    ret = s->write(s, s->sasl.encoded + s->sasl.encodedOffset,
-                   s->sasl.encodedLength - s->sasl.encodedOffset);
-
-    if (ret <= 0) {
-        return ret;
-    }
-
-    s->sasl.encodedOffset += ret;
-    if (s->sasl.encodedOffset == s->sasl.encodedLength) {
-        s->sasl.encoded = NULL;
-        s->sasl.encodedOffset = s->sasl.encodedLength = 0;
-        return nbyte;
-    }
-
-    /* we didn't flush the encoded buffer */
-    errno = EAGAIN;
-    return -1;
-}
-
-static ssize_t reds_stream_sasl_read(RedsStream *s, uint8_t *buf, size_t nbyte)
-{
-    uint8_t encoded[4096];
-    const char *decoded;
-    unsigned int decodedlen;
-    int err;
-    int n;
-
-    n = spice_buffer_copy(&s->sasl.inbuffer, buf, nbyte);
-    if (n > 0) {
-        spice_buffer_remove(&s->sasl.inbuffer, n);
-        if (n == nbyte)
-            return n;
-        nbyte -= n;
-        buf += n;
-    }
-
-    n = s->read(s, encoded, sizeof(encoded));
-    if (n <= 0) {
-        return n;
-    }
-
-    err = sasl_decode(s->sasl.conn,
-                      (char *)encoded, n,
-                      &decoded, &decodedlen);
-    if (err != SASL_OK) {
-        spice_warning("sasl_decode error: %d", err);
-        return -1;
-    }
-
-    if (decodedlen == 0) {
-        errno = EAGAIN;
-        return -1;
-    }
-
-    n = MIN(nbyte, decodedlen);
-    memcpy(buf, decoded, n);
-    spice_buffer_append(&s->sasl.inbuffer, decoded + n, decodedlen - n);
-    return n;
-}
 #endif
 
 static void async_read_handler(int fd, int event, void *data)
@@ -4508,84 +4410,3 @@ SPICE_GNUC_VISIBLE void spice_server_set_seamless_migration(SpiceServer *s, int
     reds->seamless_migration_enabled = enable && !reds->allow_multiple_clients;
     spice_debug("seamless migration enabled=%d", enable);
 }
-
-ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
-{
-    ssize_t ret;
-
-#if HAVE_SASL
-    if (s->sasl.conn && s->sasl.runSSF) {
-        ret = reds_stream_sasl_read(s, buf, nbyte);
-    } else
-#endif
-        ret = s->read(s, buf, nbyte);
-
-    return ret;
-}
-
-ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte)
-{
-    ssize_t ret;
-
-#if HAVE_SASL
-    if (s->sasl.conn && s->sasl.runSSF) {
-        ret = reds_stream_sasl_write(s, buf, nbyte);
-    } else
-#endif
-        ret = s->write(s, buf, nbyte);
-
-    return ret;
-}
-
-ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int iovcnt)
-{
-    int i;
-    int n;
-    ssize_t ret = 0;
-
-    if (s->writev != NULL) {
-        return s->writev(s, iov, iovcnt);
-    }
-
-    for (i = 0; i < iovcnt; ++i) {
-        n = reds_stream_write(s, iov[i].iov_base, iov[i].iov_len);
-        if (n <= 0)
-            return ret == 0 ? n : ret;
-        ret += n;
-    }
-
-    return ret;
-}
-
-void reds_stream_free(RedsStream *s)
-{
-    if (!s) {
-        return;
-    }
-
-    reds_stream_push_channel_event(s, SPICE_CHANNEL_EVENT_DISCONNECTED);
-
-#if HAVE_SASL
-    if (s->sasl.conn) {
-        s->sasl.runSSF = s->sasl.wantSSF = 0;
-        s->sasl.len = 0;
-        s->sasl.encodedLength = s->sasl.encodedOffset = 0;
-        s->sasl.encoded = NULL;
-        free(s->sasl.mechlist);
-        free(s->sasl.mechname);
-        s->sasl.mechlist = NULL;
-        sasl_dispose(&s->sasl.conn);
-        s->sasl.conn = NULL;
-    }
-#endif
-
-    if (s->ssl) {
-        SSL_free(s->ssl);
-    }
-
-    reds_stream_remove_watch(s);
-    spice_info("close socket fd %d", s->socket);
-    close(s->socket);
-
-    free(s);
-}
diff --git a/server/reds.h b/server/reds.h
index 3efea6a..eabe0af 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -19,14 +19,10 @@
 #define _H_REDS
 
 #include <stdint.h>
-#include <openssl/ssl.h>
 #include <sys/uio.h>
 #include <spice/vd_agent.h>
 #include <config.h>
 
-#if HAVE_SASL
-#include <sasl/sasl.h>
-#endif
 
 #include "common/marshaller.h"
 #include "common/messages.h"
@@ -34,60 +30,6 @@
 #include "red_channel.h"
 #include "migration_protocol.h"
 
-#if HAVE_SASL
-typedef struct RedsSASL {
-    sasl_conn_t *conn;
-
-    /* If we want to negotiate an SSF layer with client */
-    int wantSSF :1;
-    /* If we are now running the SSF layer */
-    int runSSF :1;
-
-    /*
-     * Buffering encoded data to allow more clear data
-     * to be stuffed onto the output buffer
-     */
-    const uint8_t *encoded;
-    unsigned int encodedLength;
-    unsigned int encodedOffset;
-
-    SpiceBuffer inbuffer;
-
-    char *username;
-    char *mechlist;
-    char *mechname;
-
-    /* temporary data during authentication */
-    unsigned int len;
-    char *data;
-} RedsSASL;
-#endif
-
-struct RedsStream {
-    int socket;
-    SpiceWatch *watch;
-
-    /* set it to TRUE if you shutdown the socket. shutdown read doesn't work as accepted -
-       receive may return data afterward. check the flag before calling receive*/
-    int shutdown;
-    SSL *ssl;
-
-#if HAVE_SASL
-    RedsSASL sasl;
-#endif
-
-    /* life time of info:
-     * allocated when creating RedsStream.
-     * deallocated when main_dispatcher handles the SPICE_CHANNEL_EVENT_DISCONNECTED
-     * event, either from same thread or by call back from main thread. */
-    SpiceChannelEventInfo* info;
-
-    /* private */
-    ssize_t (*read)(RedsStream *s, void *buf, size_t nbyte);
-    ssize_t (*write)(RedsStream *s, const void *buf, size_t nbyte);
-    ssize_t (*writev)(RedsStream *s, const struct iovec *iov, int iovcnt);
-};
-
 struct QXLState {
     QXLInterface          *qif;
     struct RedDispatcher  *dispatcher;
@@ -109,12 +51,6 @@ typedef struct RedsMigSpice {
     int sport;
 } RedsMigSpice;
 
-/* any thread */
-ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte);
-ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte);
-ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int iovcnt);
-void reds_stream_free(RedsStream *s);
-
 /* main thread only */
 void reds_handle_channel_event(int event, SpiceChannelEventInfo *info);
 
diff --git a/server/reds_stream.c b/server/reds_stream.c
new file mode 100644
index 0000000..7adc745
--- /dev/null
+++ b/server/reds_stream.c
@@ -0,0 +1,220 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009, 2013 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "main_dispatcher.h"
+#include "red_common.h"
+#include "reds_stream.h"
+#include "common/log.h"
+
+#include <errno.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <openssl/err.h>
+
+extern SpiceCoreInterface *core;
+
+void reds_stream_remove_watch(RedsStream* s)
+{
+    if (s->watch) {
+        core->watch_remove(s->watch);
+        s->watch = NULL;
+    }
+}
+
+static ssize_t reds_stream_sasl_read(RedsStream *s, uint8_t *buf, size_t nbyte);
+
+ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
+{
+    ssize_t ret;
+
+#if HAVE_SASL
+    if (s->sasl.conn && s->sasl.runSSF) {
+        ret = reds_stream_sasl_read(s, buf, nbyte);
+    } else
+#endif
+        ret = s->read(s, buf, nbyte);
+
+    return ret;
+}
+
+static ssize_t reds_stream_sasl_write(RedsStream *s, const void *buf, size_t nbyte);
+
+ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte)
+{
+    ssize_t ret;
+
+#if HAVE_SASL
+    if (s->sasl.conn && s->sasl.runSSF) {
+        ret = reds_stream_sasl_write(s, buf, nbyte);
+    } else
+#endif
+        ret = s->write(s, buf, nbyte);
+
+    return ret;
+}
+
+ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int iovcnt)
+{
+    int i;
+    int n;
+    ssize_t ret = 0;
+
+    if (s->writev != NULL) {
+        return s->writev(s, iov, iovcnt);
+    }
+
+    for (i = 0; i < iovcnt; ++i) {
+        n = reds_stream_write(s, iov[i].iov_base, iov[i].iov_len);
+        if (n <= 0)
+            return ret == 0 ? n : ret;
+        ret += n;
+    }
+
+    return ret;
+}
+
+void reds_stream_free(RedsStream *s)
+{
+    if (!s) {
+        return;
+    }
+
+    reds_stream_push_channel_event(s, SPICE_CHANNEL_EVENT_DISCONNECTED);
+
+#if HAVE_SASL
+    if (s->sasl.conn) {
+        s->sasl.runSSF = s->sasl.wantSSF = 0;
+        s->sasl.len = 0;
+        s->sasl.encodedLength = s->sasl.encodedOffset = 0;
+        s->sasl.encoded = NULL;
+        free(s->sasl.mechlist);
+        free(s->sasl.mechname);
+        s->sasl.mechlist = NULL;
+        sasl_dispose(&s->sasl.conn);
+        s->sasl.conn = NULL;
+    }
+#endif
+
+    if (s->ssl) {
+        SSL_free(s->ssl);
+    }
+
+    reds_stream_remove_watch(s);
+    spice_info("close socket fd %d", s->socket);
+    close(s->socket);
+
+    free(s);
+}
+
+void reds_stream_push_channel_event(RedsStream *s, int event)
+{
+    main_dispatcher_channel_event(event, s->info);
+}
+
+#if HAVE_SASL
+static ssize_t reds_stream_sasl_write(RedsStream *s, const void *buf, size_t nbyte)
+{
+    ssize_t ret;
+
+    if (!s->sasl.encoded) {
+        int err;
+        err = sasl_encode(s->sasl.conn, (char *)buf, nbyte,
+                          (const char **)&s->sasl.encoded,
+                          &s->sasl.encodedLength);
+        if (err != SASL_OK) {
+            spice_warning("sasl_encode error: %d", err);
+            return -1;
+        }
+
+        if (s->sasl.encodedLength == 0) {
+            return 0;
+        }
+
+        if (!s->sasl.encoded) {
+            spice_warning("sasl_encode didn't return a buffer!");
+            return 0;
+        }
+
+        s->sasl.encodedOffset = 0;
+    }
+
+    ret = s->write(s, s->sasl.encoded + s->sasl.encodedOffset,
+                   s->sasl.encodedLength - s->sasl.encodedOffset);
+
+    if (ret <= 0) {
+        return ret;
+    }
+
+    s->sasl.encodedOffset += ret;
+    if (s->sasl.encodedOffset == s->sasl.encodedLength) {
+        s->sasl.encoded = NULL;
+        s->sasl.encodedOffset = s->sasl.encodedLength = 0;
+        return nbyte;
+    }
+
+    /* we didn't flush the encoded buffer */
+    errno = EAGAIN;
+    return -1;
+}
+
+static ssize_t reds_stream_sasl_read(RedsStream *s, uint8_t *buf, size_t nbyte)
+{
+    uint8_t encoded[4096];
+    const char *decoded;
+    unsigned int decodedlen;
+    int err;
+    int n;
+
+    n = spice_buffer_copy(&s->sasl.inbuffer, buf, nbyte);
+    if (n > 0) {
+        spice_buffer_remove(&s->sasl.inbuffer, n);
+        if (n == nbyte)
+            return n;
+        nbyte -= n;
+        buf += n;
+    }
+
+    n = s->read(s, encoded, sizeof(encoded));
+    if (n <= 0) {
+        return n;
+    }
+
+    err = sasl_decode(s->sasl.conn,
+                      (char *)encoded, n,
+                      &decoded, &decodedlen);
+    if (err != SASL_OK) {
+        spice_warning("sasl_decode error: %d", err);
+        return -1;
+    }
+
+    if (decodedlen == 0) {
+        errno = EAGAIN;
+        return -1;
+    }
+
+    n = MIN(nbyte, decodedlen);
+    memcpy(buf, decoded, n);
+    spice_buffer_append(&s->sasl.inbuffer, decoded + n, decodedlen - n);
+    return n;
+}
+#endif
diff --git a/server/reds_stream.h b/server/reds_stream.h
new file mode 100644
index 0000000..ca18f75
--- /dev/null
+++ b/server/reds_stream.h
@@ -0,0 +1,100 @@
+/*
+   Copyright (C) 2009, 2013 Red Hat, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with this library; if not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _H_REDS_STREAM
+#define _H_REDS_STREAM
+
+#include "spice.h"
+#include "common/mem.h"
+
+#include <openssl/ssl.h>
+
+#if HAVE_SASL
+#include <sasl/sasl.h>
+
+typedef struct RedsSASL {
+    sasl_conn_t *conn;
+
+    /* If we want to negotiate an SSF layer with client */
+    int wantSSF :1;
+    /* If we are now running the SSF layer */
+    int runSSF :1;
+
+    /*
+     * Buffering encoded data to allow more clear data
+     * to be stuffed onto the output buffer
+     */
+    const uint8_t *encoded;
+    unsigned int encodedLength;
+    unsigned int encodedOffset;
+
+    SpiceBuffer inbuffer;
+
+    char *username;
+    char *mechlist;
+    char *mechname;
+
+    /* temporary data during authentication */
+    unsigned int len;
+    char *data;
+} RedsSASL;
+#endif
+
+typedef struct RedsStream RedsStream;
+
+struct RedsStream {
+    int socket;
+    SpiceWatch *watch;
+
+    /* set it to TRUE if you shutdown the socket. shutdown read doesn't work as accepted -
+       receive may return data afterward. check the flag before calling receive*/
+    int shutdown;
+    SSL *ssl;
+
+#if HAVE_SASL
+    RedsSASL sasl;
+#endif
+
+    /* life time of info:
+     * allocated when creating RedsStream.
+     * deallocated when main_dispatcher handles the SPICE_CHANNEL_EVENT_DISCONNECTED
+     * event, either from same thread or by call back from main thread. */
+    SpiceChannelEventInfo* info;
+
+    /* private */
+    ssize_t (*read)(RedsStream *s, void *buf, size_t nbyte);
+    ssize_t (*write)(RedsStream *s, const void *buf, size_t nbyte);
+    ssize_t (*writev)(RedsStream *s, const struct iovec *iov, int iovcnt);
+};
+
+typedef enum {
+    REDS_STREAM_SSL_STATUS_OK,
+    REDS_STREAM_SSL_STATUS_ERROR,
+    REDS_STREAM_SSL_STATUS_WAIT_FOR_READ,
+    REDS_STREAM_SSL_STATUS_WAIT_FOR_WRITE
+} RedsStreamSslStatus;
+
+/* any thread */
+ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte);
+ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte);
+ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int iovcnt);
+void reds_stream_free(RedsStream *s);
+
+void reds_stream_push_channel_event(RedsStream *s, int event);
+void reds_stream_remove_watch(RedsStream* s);
+
+#endif
-- 
1.8.4.2



More information about the Spice-devel mailing list