summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2013-10-07 13:50:20 +0200
committerChristophe Fergeau <cfergeau@redhat.com>2014-01-20 12:15:41 +0100
commit8b347a641c885fdc31a41a1b1a55da982b580265 (patch)
tree659abc85944ebd4c41fb12eaf34223d807991abc
parent73c56e5a2d952bf566c3fbff5e9aefff70ddd59a (diff)
Add reds_stream.[ch]
Gather common RedsStream code there rather than having it in reds.c
-rw-r--r--server/Makefile.am2
-rw-r--r--server/inputs_channel.c1
-rw-r--r--server/red_channel.c1
-rw-r--r--server/red_channel.h2
-rw-r--r--server/red_worker.c1
-rw-r--r--server/reds.c181
-rw-r--r--server/reds.h64
-rw-r--r--server/reds_stream.c220
-rw-r--r--server/reds_stream.h100
9 files changed, 327 insertions, 245 deletions
diff --git a/server/Makefile.am b/server/Makefile.am
index 13c6223b..34219c80 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 dd8f5ae2..8d4feaba 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 24a8b647..b81deeb0 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 9e54dcec..f638d3c7 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 afbdd914..619f7bcc 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 d79732c6..6e43feaa 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);
@@ -2000,92 +1988,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)
@@ -4509,84 +4411,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 3efea6ae..eabe0af9 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 00000000..7adc745f
--- /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 00000000..ca18f75b
--- /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