From 8b347a641c885fdc31a41a1b1a55da982b580265 Mon Sep 17 00:00:00 2001 From: Christophe Fergeau Date: Mon, 7 Oct 2013 13:50:20 +0200 Subject: Add reds_stream.[ch] 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 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 -#include #include #include #include -#if HAVE_SASL -#include -#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 . +*/ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "main_dispatcher.h" +#include "red_common.h" +#include "reds_stream.h" +#include "common/log.h" + +#include +#include +#include +#include + +#include + +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 . +*/ + +#ifndef _H_REDS_STREAM +#define _H_REDS_STREAM + +#include "spice.h" +#include "common/mem.h" + +#include + +#if HAVE_SASL +#include + +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 -- cgit