[Spice-commits] 18 commits - common/mem.c common/mem.h configure.ac server/inputs_channel.c server/main_channel.c server/Makefile.am server/red_channel.c server/red_channel.h server/red_dispatcher.c server/reds.c server/reds.h server/red_tunnel_worker.c server/red_worker.c server/smartcard.c server/snd_worker.c server/spice.h

Marc-André Lureau elmarco at kemper.freedesktop.org
Mon Feb 28 07:42:34 PST 2011


 common/mem.c               |   53 ++
 common/mem.h               |   17 
 configure.ac               |   55 ++
 server/Makefile.am         |    8 
 server/inputs_channel.c    |   10 
 server/main_channel.c      |   12 
 server/red_channel.c       |   55 +-
 server/red_channel.h       |    6 
 server/red_dispatcher.c    |    8 
 server/red_tunnel_worker.c |   12 
 server/red_worker.c        |   64 +-
 server/reds.c              | 1175 +++++++++++++++++++++++++++++++++++++--------
 server/reds.h              |   64 ++
 server/smartcard.c         |    4 
 server/snd_worker.c        |   49 -
 server/spice.h             |    2 
 16 files changed, 1278 insertions(+), 316 deletions(-)

New commits:
commit 8f9cbd19dbf3612abeafae60bdc4df2a97552b91
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Fri Feb 11 04:04:28 2011 +0100

    server: add SASL support
    
    We introduce 2 public functions to integrate with the library user.
    
    spice_server_set_sasl() - turn on SASL
    spice_server_set_sasl_appname() - specify the name of the app (It is
    used for where to find the default configuration file)
    
    The patch for QEMU is on its way.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index 4c36f92..750b785 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -16,6 +16,8 @@
    License along with this library; if not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "config.h"
+
 #include <stdint.h>
 #include <stdio.h>
 #include <unistd.h>
@@ -38,6 +40,9 @@
 #include <openssl/rsa.h>
 #include <openssl/ssl.h>
 #include <openssl/err.h>
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
 
 #include "spice.h"
 #include "spice-experimental.h"
@@ -53,7 +58,6 @@
 #include <spice/stats.h>
 #include "stat.h"
 #include "ring.h"
-#include "config.h"
 #include "demarshallers.h"
 #include "marshaller.h"
 #include "generated_marshallers.h"
@@ -83,6 +87,10 @@ static int spice_secure_port = -1;
 static char spice_addr[256];
 static int spice_family = PF_UNSPEC;
 static char *default_renderer = "sw";
+static int sasl_enabled = 0; // sasl disabled by default
+#if HAVE_SASL
+static char *sasl_appname = NULL; // default to "spice" if NULL
+#endif
 
 static int ticketing_enabled = 1; //Ticketing is enabled by default
 static pthread_mutex_t *lock_cs;
@@ -1349,15 +1357,20 @@ static void reds_channel_set_common_caps(Channel *channel, int cap, int active)
     channel->common_caps = spice_renew(uint32_t, channel->common_caps, channel->num_common_caps);
     memset(channel->common_caps + nbefore, 0,
            (channel->num_common_caps - nbefore) * sizeof(uint32_t));
-    if (active)
+    if (active) {
         channel->common_caps[n] |= (1 << cap);
-    else
+    } else {
         channel->common_caps[n] &= ~(1 << cap);
+    }
 }
 
 void reds_channel_init_auth_caps(Channel *channel)
 {
-    reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, TRUE);
+    if (sasl_enabled) {
+        reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SASL, TRUE);
+    } else {
+        reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, TRUE);
+    }
     reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, TRUE);
 }
 
@@ -1486,7 +1499,7 @@ static void reds_handle_main_link(RedLinkInfo *link)
     link_mess = link->link_mess;
     reds_disconnect();
 
-    if (!link_mess->connection_id) {
+    if (link_mess->connection_id == 0) {
         reds_send_link_result(link, SPICE_LINK_ERR_OK);
         while((connection_id = rand()) == 0);
         reds->agent_state.num_tokens = 0;
@@ -1670,6 +1683,104 @@ static inline void async_read_clear_handlers(AsyncRead *obj)
     reds_stream_remove_watch(obj->stream);
 }
 
+#if HAVE_SASL
+static int sync_write_u8(RedsStream *s, uint8_t n)
+{
+    return sync_write(s, &n, sizeof(uint8_t));
+}
+
+static int sync_write_u32(RedsStream *s, uint32_t n)
+{
+    return sync_write(s, &n, sizeof(uint32_t));
+}
+
+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) {
+            red_printf("sasl_encode error: %d", err);
+            return -1;
+        }
+
+        if (s->sasl.encodedLength == 0) {
+            return 0;
+        }
+
+        if (!s->sasl.encoded) {
+            red_printf("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, void *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) {
+        red_printf("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)
 {
     AsyncRead *obj = (AsyncRead *)data;
@@ -1722,16 +1833,537 @@ static void reds_get_spice_ticket(RedLinkInfo *link)
     async_read_handler(0, 0, &link->asyc_read);
 }
 
+#if HAVE_SASL
+static char *addr_to_string(const char *format,
+                            struct sockaddr *sa,
+                            socklen_t salen) {
+    char *addr;
+    char host[NI_MAXHOST];
+    char serv[NI_MAXSERV];
+    int err;
+    size_t addrlen;
+
+    if ((err = getnameinfo(sa, salen,
+                           host, sizeof(host),
+                           serv, sizeof(serv),
+                           NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
+        red_printf("Cannot resolve address %d: %s",
+                   err, gai_strerror(err));
+        return NULL;
+    }
+
+    /* Enough for the existing format + the 2 vars we're
+     * substituting in. */
+    addrlen = strlen(format) + strlen(host) + strlen(serv);
+    addr = spice_malloc(addrlen + 1);
+    snprintf(addr, addrlen, format, host, serv);
+    addr[addrlen] = '\0';
+
+    return addr;
+}
+
+static int auth_sasl_check_ssf(RedsSASL *sasl, int *runSSF)
+{
+    const void *val;
+    int err, ssf;
+
+    *runSSF = 0;
+    if (!sasl->wantSSF) {
+        return 1;
+    }
+
+    err = sasl_getprop(sasl->conn, SASL_SSF, &val);
+    if (err != SASL_OK) {
+        return 0;
+    }
+
+    ssf = *(const int *)val;
+    red_printf("negotiated an SSF of %d", ssf);
+    if (ssf < 56) {
+        return 0; /* 56 is good for Kerberos */
+    }
+
+    *runSSF = 1;
+
+    /* We have a SSF that's good enough */
+    return 1;
+}
+
+/*
+ * Step Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+#define SASL_DATA_MAX_LEN (1024 * 1024)
+
+static void reds_handle_auth_sasl_steplen(void *opaque);
+
+static void reds_handle_auth_sasl_step(void *opaque)
+{
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    RedsSASL *sasl = &link->stream->sasl;
+    uint32_t datalen = sasl->len;
+    AsyncRead *obj = &link->asyc_read;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = sasl->data;
+        clientdata[datalen - 1] = '\0'; /* Wire includes '\0', but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    red_printf("Step using SASL Data %p (%d bytes)",
+               clientdata, datalen);
+    err = sasl_server_step(sasl->conn,
+                           clientdata,
+                           datalen,
+                           &serverout,
+                           &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        red_printf("sasl step failed %d (%s)",
+                   err, sasl_errdetail(sasl->conn));
+        goto authabort;
+    }
+
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        red_printf("sasl step reply data too long %d",
+                   serveroutlen);
+        goto authabort;
+    }
+
+    red_printf("SASL return data %d bytes, %p", serveroutlen, serverout);
+
+    if (serveroutlen) {
+        serveroutlen += 1;
+        sync_write(link->stream, &serveroutlen, sizeof(uint32_t));
+        sync_write(link->stream, serverout, serveroutlen);
+    } else {
+        sync_write(link->stream, &serveroutlen, sizeof(uint32_t));
+    }
+
+    /* Whether auth is complete */
+    sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        red_printf("%s", "Authentication must continue (step)");
+        /* Wait for step length */
+        obj->now = (uint8_t *)&sasl->len;
+        obj->end = obj->now + sizeof(uint32_t);
+        obj->done = reds_handle_auth_sasl_steplen;
+        async_read_handler(0, 0, &link->asyc_read);
+    } else {
+        int ssf;
+
+        if (auth_sasl_check_ssf(sasl, &ssf) == 0) {
+            red_printf("Authentication rejected for weak SSF");
+            goto authreject;
+        }
+
+        red_printf("Authentication successful");
+        sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */
+
+        /*
+         * Delay writing in SSF encoded until now
+         */
+        sasl->runSSF = ssf;
+        link->stream->writev = NULL; /* make sure writev isn't called directly anymore */
+
+        reds_handle_link(link);
+    }
+
+    return;
+
+authreject:
+    sync_write_u32(link->stream, 1); /* Reject auth */
+    sync_write_u32(link->stream, sizeof("Authentication failed"));
+    sync_write(link->stream, "Authentication failed", sizeof("Authentication failed"));
+
+authabort:
+    reds_link_free(link);
+    return;
+}
+
+static void reds_handle_auth_sasl_steplen(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+    RedsSASL *sasl = &link->stream->sasl;
+
+    red_printf("Got steplen %d", sasl->len);
+    if (sasl->len > SASL_DATA_MAX_LEN) {
+        red_printf("Too much SASL data %d", sasl->len);
+        reds_link_free(link);
+        return;
+    }
+
+    if (sasl->len == 0) {
+        return reds_handle_auth_sasl_step(opaque);
+    } else {
+        sasl->data = spice_realloc(sasl->data, sasl->len);
+        obj->now = (uint8_t *)sasl->data;
+        obj->end = obj->now + sasl->len;
+        obj->done = reds_handle_auth_sasl_step;
+        async_read_handler(0, 0, &link->asyc_read);
+    }
+}
+
+/*
+ * Start Msg
+ *
+ * Input from client:
+ *
+ * u32 clientin-length
+ * u8-array clientin-string
+ *
+ * Output to client:
+ *
+ * u32 serverout-length
+ * u8-array serverout-strin
+ * u8 continue
+ */
+
+
+static void reds_handle_auth_sasl_start(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+    const char *serverout;
+    unsigned int serveroutlen;
+    int err;
+    char *clientdata = NULL;
+    RedsSASL *sasl = &link->stream->sasl;
+    uint32_t datalen = sasl->len;
+
+    /* NB, distinction of NULL vs "" is *critical* in SASL */
+    if (datalen) {
+        clientdata = sasl->data;
+        clientdata[datalen - 1] = '\0'; /* Should be on wire, but make sure */
+        datalen--; /* Don't count NULL byte when passing to _start() */
+    }
+
+    red_printf("Start SASL auth with mechanism %s. Data %p (%d bytes)",
+              sasl->mechlist, clientdata, datalen);
+    err = sasl_server_start(sasl->conn,
+                            sasl->mechlist,
+                            clientdata,
+                            datalen,
+                            &serverout,
+                            &serveroutlen);
+    if (err != SASL_OK &&
+        err != SASL_CONTINUE) {
+        red_printf("sasl start failed %d (%s)",
+                   err, sasl_errdetail(sasl->conn));
+        goto authabort;
+    }
+
+    if (serveroutlen > SASL_DATA_MAX_LEN) {
+        red_printf("sasl start reply data too long %d",
+                   serveroutlen);
+        goto authabort;
+    }
+
+    red_printf("SASL return data %d bytes, %p", serveroutlen, serverout);
+
+    if (serveroutlen) {
+        serveroutlen += 1;
+        sync_write(link->stream, &serveroutlen, sizeof(uint32_t));
+        sync_write(link->stream, serverout, serveroutlen);
+    } else {
+        sync_write(link->stream, &serveroutlen, sizeof(uint32_t));
+    }
+
+    /* Whether auth is complete */
+    sync_write_u8(link->stream, err == SASL_CONTINUE ? 0 : 1);
+
+    if (err == SASL_CONTINUE) {
+        red_printf("%s", "Authentication must continue (start)");
+        /* Wait for step length */
+        obj->now = (uint8_t *)&sasl->len;
+        obj->end = obj->now + sizeof(uint32_t);
+        obj->done = reds_handle_auth_sasl_steplen;
+        async_read_handler(0, 0, &link->asyc_read);
+    } else {
+        int ssf;
+
+        if (auth_sasl_check_ssf(sasl, &ssf) == 0) {
+            red_printf("Authentication rejected for weak SSF");
+            goto authreject;
+        }
+
+        red_printf("Authentication successful");
+        sync_write_u32(link->stream, SPICE_LINK_ERR_OK); /* Accept auth */
+
+        /*
+         * Delay writing in SSF encoded until now
+         */
+        sasl->runSSF = ssf;
+        link->stream->writev = NULL; /* make sure writev isn't called directly anymore */
+
+        reds_handle_link(link);
+    }
+
+    return;
+
+authreject:
+    sync_write_u32(link->stream, 1); /* Reject auth */
+    sync_write_u32(link->stream, sizeof("Authentication failed"));
+    sync_write(link->stream, "Authentication failed", sizeof("Authentication failed"));
+
+authabort:
+    reds_link_free(link);
+    return;
+}
+
+static void reds_handle_auth_startlen(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+    RedsSASL *sasl = &link->stream->sasl;
+
+    red_printf("Got client start len %d", sasl->len);
+    if (sasl->len > SASL_DATA_MAX_LEN) {
+        red_printf("Too much SASL data %d", sasl->len);
+        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
+        reds_link_free(link);
+        return;
+    }
+
+    if (sasl->len == 0) {
+        reds_handle_auth_sasl_start(opaque);
+        return;
+    }
+
+    sasl->data = spice_realloc(sasl->data, sasl->len);
+    obj->now = (uint8_t *)sasl->data;
+    obj->end = obj->now + sasl->len;
+    obj->done = reds_handle_auth_sasl_start;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
+static void reds_handle_auth_mechname(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+    RedsSASL *sasl = &link->stream->sasl;
+
+    sasl->mechname[sasl->len] = '\0';
+    red_printf("Got client mechname '%s' check against '%s'",
+               sasl->mechname, sasl->mechlist);
+
+    if (strncmp(sasl->mechlist, sasl->mechname, sasl->len) == 0) {
+        if (sasl->mechlist[sasl->len] != '\0' &&
+            sasl->mechlist[sasl->len] != ',') {
+            red_printf("One %d", sasl->mechlist[sasl->len]);
+            reds_link_free(link);
+            return;
+        }
+    } else {
+        char *offset = strstr(sasl->mechlist, sasl->mechname);
+        red_printf("Two %p", offset);
+        if (!offset) {
+            reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
+            return;
+        }
+        red_printf("Two '%s'", offset);
+        if (offset[-1] != ',' ||
+            (offset[sasl->len] != '\0'&&
+             offset[sasl->len] != ',')) {
+            reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
+            return;
+        }
+    }
+
+    free(sasl->mechlist);
+    sasl->mechlist = strdup(sasl->mechname);
+
+    red_printf("Validated mechname '%s'", sasl->mechname);
+
+    obj->now = (uint8_t *)&sasl->len;
+    obj->end = obj->now + sizeof(uint32_t);
+    obj->done = reds_handle_auth_startlen;
+    async_read_handler(0, 0, &link->asyc_read);
+
+    return;
+}
+
+static void reds_handle_auth_mechlen(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+    AsyncRead *obj = &link->asyc_read;
+    RedsSASL *sasl = &link->stream->sasl;
+
+    if (sasl->len < 1 || sasl->len > 100) {
+        red_printf("Got bad client mechname len %d", sasl->len);
+        reds_link_free(link);
+        return;
+    }
+
+    sasl->mechname = spice_malloc(sasl->len + 1);
+
+    red_printf("Wait for client mechname");
+    obj->now = (uint8_t *)sasl->mechname;
+    obj->end = obj->now + sasl->len;
+    obj->done = reds_handle_auth_mechname;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
+static void reds_start_auth_sasl(RedLinkInfo *link)
+{
+    const char *mechlist = NULL;
+    sasl_security_properties_t secprops;
+    int err;
+    char *localAddr, *remoteAddr;
+    int mechlistlen;
+    AsyncRead *obj = &link->asyc_read;
+    RedsSASL *sasl = &link->stream->sasl;
+
+    /* Get local & remote client addresses in form  IPADDR;PORT */
+    if (!(localAddr = addr_to_string("%s;%s", &link->stream->info.laddr, link->stream->info.llen))) {
+        goto error;
+    }
+
+    if (!(remoteAddr = addr_to_string("%s;%s", &link->stream->info.paddr, link->stream->info.plen))) {
+        free(localAddr);
+        goto error;
+    }
+
+    err = sasl_server_new("spice",
+                          NULL, /* FQDN - just delegates to gethostname */
+                          NULL, /* User realm */
+                          localAddr,
+                          remoteAddr,
+                          NULL, /* Callbacks, not needed */
+                          SASL_SUCCESS_DATA,
+                          &sasl->conn);
+    free(localAddr);
+    free(remoteAddr);
+    localAddr = remoteAddr = NULL;
+
+    if (err != SASL_OK) {
+        red_printf("sasl context setup failed %d (%s)",
+                   err, sasl_errstring(err, NULL, NULL));
+        sasl->conn = NULL;
+        goto error;
+    }
+
+    /* Inform SASL that we've got an external SSF layer from TLS */
+    if (link->stream->ssl) {
+        sasl_ssf_t ssf;
+
+        ssf = SSL_get_cipher_bits(link->stream->ssl, NULL);
+        err = sasl_setprop(sasl->conn, SASL_SSF_EXTERNAL, &ssf);
+        if (err != SASL_OK) {
+            red_printf("cannot set SASL external SSF %d (%s)",
+                       err, sasl_errstring(err, NULL, NULL));
+            sasl_dispose(&sasl->conn);
+            sasl->conn = NULL;
+            goto error;
+        }
+    } else {
+        sasl->wantSSF = 1;
+    }
+
+    memset(&secprops, 0, sizeof secprops);
+    /* Inform SASL that we've got an external SSF layer from TLS */
+    if (link->stream->ssl) {
+        /* If we've got TLS (or UNIX domain sock), we don't care about SSF */
+        secprops.min_ssf = 0;
+        secprops.max_ssf = 0;
+        secprops.maxbufsize = 8192;
+        secprops.security_flags = 0;
+    } else {
+        /* Plain TCP, better get an SSF layer */
+        secprops.min_ssf = 56; /* Good enough to require kerberos */
+        secprops.max_ssf = 100000; /* Arbitrary big number */
+        secprops.maxbufsize = 8192;
+        /* Forbid any anonymous or trivially crackable auth */
+        secprops.security_flags =
+            SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
+    }
+
+    err = sasl_setprop(sasl->conn, SASL_SEC_PROPS, &secprops);
+    if (err != SASL_OK) {
+        red_printf("cannot set SASL security props %d (%s)",
+                   err, sasl_errstring(err, NULL, NULL));
+        sasl_dispose(&sasl->conn);
+        sasl->conn = NULL;
+        goto error;
+    }
+
+    err = sasl_listmech(sasl->conn,
+                        NULL, /* Don't need to set user */
+                        "", /* Prefix */
+                        ",", /* Separator */
+                        "", /* Suffix */
+                        &mechlist,
+                        NULL,
+                        NULL);
+    if (err != SASL_OK) {
+        red_printf("cannot list SASL mechanisms %d (%s)",
+                   err, sasl_errdetail(sasl->conn));
+        sasl_dispose(&sasl->conn);
+        sasl->conn = NULL;
+        goto error;
+    }
+    red_printf("Available mechanisms for client: '%s'", mechlist);
+
+    sasl->mechlist = strdup(mechlist);
+
+    mechlistlen = strlen(mechlist);
+    if (!sync_write(link->stream, &mechlistlen, sizeof(uint32_t))
+        || !sync_write(link->stream, sasl->mechlist, mechlistlen)) {
+        red_printf("SASL mechanisms write error");
+        goto error;
+    }
+
+    red_printf("Wait for client mechname length");
+    obj->now = (uint8_t *)&sasl->len;
+    obj->end = obj->now + sizeof(uint32_t);
+    obj->done = reds_handle_auth_mechlen;
+    async_read_handler(0, 0, &link->asyc_read);
+
+    return;
+
+error:
+    reds_link_free(link);
+    return;
+}
+#endif
+
 static void reds_handle_auth_mechanism(void *opaque)
 {
     RedLinkInfo *link = (RedLinkInfo *)opaque;
 
     red_printf("Auth method: %d", link->auth_mechanism.auth_mechanism);
 
-    if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE) {
+    if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE
+        && !sasl_enabled
+        ) {
         reds_get_spice_ticket(link);
+#if HAVE_SASL
+    } else if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SASL) {
+        red_printf("Starting SASL");
+        reds_start_auth_sasl(link);
+#endif
     } else {
         red_printf("Unknown auth method, disconnecting");
+        if (sasl_enabled) {
+            red_printf("Your client doesn't handle SASL?");
+        }
         reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
         reds_link_free(link);
     }
@@ -1783,6 +2415,11 @@ static void reds_handle_read_link_done(void *opaque)
     }
 
     if (!auth_selection) {
+        if (sasl_enabled) {
+            red_printf("SASL enabled, but peer supports only spice authentication");
+            reds_send_link_error(link, SPICE_LINK_ERR_VERSION_MISMATCH);
+            return;
+        }
         red_printf("Peer doesn't support AUTH selection");
         reds_get_spice_ticket(link);
     } else {
@@ -2842,6 +3479,16 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     if (reds->secure_listen_socket != -1) {
         reds_init_ssl();
     }
+#if HAVE_SASL
+    int saslerr;
+    if ((saslerr = sasl_server_init(NULL, sasl_appname ?
+                                    sasl_appname : "spice")) != SASL_OK) {
+        red_error("Failed to initialize SASL auth %s",
+                  sasl_errstring(saslerr, NULL, NULL));
+        goto err;
+    }
+#endif
+
     reds->main_channel = NULL;
     inputs_init();
 
@@ -2935,6 +3582,29 @@ __visible__ int spice_server_set_noauth(SpiceServer *s)
     return 0;
 }
 
+__visible__ int spice_server_set_sasl(SpiceServer *s, int enabled)
+{
+    ASSERT(reds == s);
+#if HAVE_SASL
+    sasl_enabled = enabled;
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+__visible__ int spice_server_set_sasl_appname(SpiceServer *s, const char *appname)
+{
+    ASSERT(reds == s);
+#if HAVE_SASL
+    free(sasl_appname);
+    sasl_appname = strdup(appname);
+    return 0;
+#else
+    return -1;
+#endif
+}
+
 __visible__ int spice_server_set_ticket(SpiceServer *s,
                                         const char *passwd, int lifetime,
                                         int fail_if_connected,
@@ -3210,12 +3880,30 @@ __visible__ int spice_server_migrate_switch(SpiceServer *s)
 
 ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
 {
-    return s->read(s, buf, 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)
 {
-    return s->write(s, buf, 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)
@@ -3246,6 +3934,20 @@ void reds_stream_free(RedsStream *s)
 
     reds_stream_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);
     }
diff --git a/server/reds.h b/server/reds.h
index f0276b1..485d9eb 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -18,10 +18,16 @@
 #ifndef _H_REDS
 #define _H_REDS
 
+#include "config.h"
+
 #include <stdint.h>
 #include <openssl/ssl.h>
 #include <sys/uio.h>
 #include <spice/vd_agent.h>
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
 #include "common/marshaller.h"
 #include "common/messages.h"
 #include "spice.h"
@@ -30,6 +36,35 @@
 
 typedef struct RedsStream RedsStream;
 
+#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;
@@ -39,6 +74,10 @@ struct RedsStream {
     int shutdown;
     SSL *ssl;
 
+#if HAVE_SASL
+    RedsSASL sasl;
+#endif
+
     SpiceChannelEventInfo info;
 
     /* private */
diff --git a/server/spice.h b/server/spice.h
index 6fb22a4..7e85ad7 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -374,6 +374,8 @@ int spice_server_set_compat_version(SpiceServer *s,
 int spice_server_set_port(SpiceServer *s, int port);
 void spice_server_set_addr(SpiceServer *s, const char *addr, int flags);
 int spice_server_set_noauth(SpiceServer *s);
+int spice_server_set_sasl(SpiceServer *s, int enabled);
+int spice_server_set_sasl_appname(SpiceServer *s, const char *appname);
 int spice_server_set_ticket(SpiceServer *s, const char *passwd, int lifetime,
                             int fail_if_connected, int disconnect_if_connected);
 int spice_server_set_tls(SpiceServer *s, int port,
commit f4dddc50f06f90d7ff97d4ed60c6197c85814c5e
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Feb 22 13:54:09 2011 +0100

    server: add auth mechanism selection
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index c6c8a66..4c36f92 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -239,6 +239,7 @@ typedef struct RedLinkInfo {
     SpiceLinkMess *link_mess;
     int mess_pos;
     TicketInfo tiTicketing;
+    SpiceLinkAuthMechanism auth_mechanism;
 } RedLinkInfo;
 
 typedef struct VDIPortBuf VDIPortBuf;
@@ -1338,6 +1339,28 @@ static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
     return TRUE;
 }
 
+static void reds_channel_set_common_caps(Channel *channel, int cap, int active)
+{
+    int nbefore, n;
+
+    nbefore = channel->num_common_caps;
+    n = cap / 32;
+    channel->num_common_caps = MAX(channel->num_common_caps, n + 1);
+    channel->common_caps = spice_renew(uint32_t, channel->common_caps, channel->num_common_caps);
+    memset(channel->common_caps + nbefore, 0,
+           (channel->num_common_caps - nbefore) * sizeof(uint32_t));
+    if (active)
+        channel->common_caps[n] |= (1 << cap);
+    else
+        channel->common_caps[n] &= ~(1 << cap);
+}
+
+void reds_channel_init_auth_caps(Channel *channel)
+{
+    reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_AUTH_SPICE, TRUE);
+    reds_channel_set_common_caps(channel, SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION, TRUE);
+}
+
 void reds_channel_dispose(Channel *channel)
 {
     free(channel->caps);
@@ -1371,6 +1394,8 @@ static int reds_send_link_ack(RedLinkInfo *link)
         channel = &caps;
     }
 
+    reds_channel_init_auth_caps(channel); /* make sure common caps are set */
+
     ack.num_common_caps = channel->num_common_caps;
     ack.num_channel_caps = channel->num_caps;
     header.size += (ack.num_common_caps + ack.num_channel_caps) * sizeof(uint32_t);
@@ -1687,6 +1712,31 @@ static void async_read_handler(int fd, int event, void *data)
     }
 }
 
+static void reds_get_spice_ticket(RedLinkInfo *link)
+{
+    AsyncRead *obj = &link->asyc_read;
+
+    obj->now = (uint8_t *)&link->tiTicketing.encrypted_ticket.encrypted_data;
+    obj->end = obj->now + link->tiTicketing.rsa_size;
+    obj->done = reds_handle_ticket;
+    async_read_handler(0, 0, &link->asyc_read);
+}
+
+static void reds_handle_auth_mechanism(void *opaque)
+{
+    RedLinkInfo *link = (RedLinkInfo *)opaque;
+
+    red_printf("Auth method: %d", link->auth_mechanism.auth_mechanism);
+
+    if (link->auth_mechanism.auth_mechanism == SPICE_COMMON_CAP_AUTH_SPICE) {
+        reds_get_spice_ticket(link);
+    } else {
+        red_printf("Unknown auth method, disconnecting");
+        reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
+        reds_link_free(link);
+    }
+}
+
 static int reds_security_check(RedLinkInfo *link)
 {
     ChannelSecurityOptions *security_option = find_channel_security(link->link_mess->channel_type);
@@ -1701,6 +1751,8 @@ static void reds_handle_read_link_done(void *opaque)
     SpiceLinkMess *link_mess = link->link_mess;
     AsyncRead *obj = &link->asyc_read;
     uint32_t num_caps = link_mess->num_common_caps + link_mess->num_channel_caps;
+    uint32_t *caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
+    int auth_selection;
 
     if (num_caps && (num_caps * sizeof(uint32_t) + link_mess->caps_offset >
                      link->link_header.size ||
@@ -1710,6 +1762,9 @@ static void reds_handle_read_link_done(void *opaque)
         return;
     }
 
+    auth_selection = link_mess->num_common_caps > 0 &&
+        (caps[0] & (1 << SPICE_COMMON_CAP_PROTOCOL_AUTH_SELECTION));;
+
     if (!reds_security_check(link)) {
         if (link->stream->ssl) {
             red_printf("spice channels %d should not be encrypted", link_mess->channel_type);
@@ -1727,10 +1782,15 @@ static void reds_handle_read_link_done(void *opaque)
         return;
     }
 
-    obj->now = (uint8_t *)&link->tiTicketing.encrypted_ticket.encrypted_data;
-    obj->end = obj->now + link->tiTicketing.rsa_size;
-    obj->done = reds_handle_ticket;
-    async_read_handler(0, 0, &link->asyc_read);
+    if (!auth_selection) {
+        red_printf("Peer doesn't support AUTH selection");
+        reds_get_spice_ticket(link);
+    } else {
+        obj->now = (uint8_t *)&link->auth_mechanism;
+        obj->end = obj->now + sizeof(SpiceLinkAuthMechanism);
+        obj->done = reds_handle_auth_mechanism;
+        async_read_handler(0, 0, &link->asyc_read);
+    }
 }
 
 static void reds_handle_link_error(void *opaque, int err)
commit 4f983b2c9c642ac96abf214cefc1c51fad90791e
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Feb 22 03:52:38 2011 +0100

    server: add reds_channel_dispose()
    
    Try to have a common base dispose() method for channels. For now, it
    just free the caps.
    
    Make use of it in snd_worker, and in sync_write() - sync_write() is
    going to have default caps later on.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index 80f159e..c6c8a66 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1338,6 +1338,17 @@ static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
     return TRUE;
 }
 
+void reds_channel_dispose(Channel *channel)
+{
+    free(channel->caps);
+    channel->caps = NULL;
+    channel->num_caps = 0;
+
+    free(channel->common_caps);
+    channel->common_caps = NULL;
+    channel->num_common_caps = 0;
+}
+
 static int reds_send_link_ack(RedLinkInfo *link)
 {
     SpiceLinkHeader header;
diff --git a/server/reds.h b/server/reds.h
index 3c810e0..f0276b1 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -72,6 +72,8 @@ struct SpiceNetWireState {
     struct TunnelWorker *worker;
 };
 
+void reds_channel_dispose(Channel *channel);
+
 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);
diff --git a/server/snd_worker.c b/server/snd_worker.c
index f18f7c9..1a4840c 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -1236,8 +1236,7 @@ static void snd_detach_common(SndWorker *worker)
     snd_disconnect_channel(worker->connection);
     reds_unregister_channel(&worker->base);
 
-    free(worker->base.common_caps);
-    free(worker->base.caps);
+    reds_channel_dispose(&worker->base);
 }
 
 void snd_detach_playback(SpicePlaybackInstance *sin)
commit 09c01c9516045cfad1a95108f0386e50fcd9dfa0
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Fri Feb 11 04:00:27 2011 +0100

    server: simplify and constify sync_write()
    
    + symplify, improving style of code using it.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index d41e042..80f159e 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1321,9 +1321,9 @@ void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
     while (write_to_vdi_port() || read_from_vdi_port());
 }
 
-static int sync_write(RedsStream *stream, void *in_buf, size_t n)
+static int sync_write(RedsStream *stream, const void *in_buf, size_t n)
 {
-    uint8_t *buf = (uint8_t *)in_buf;
+    const uint8_t *buf = (uint8_t *)in_buf;
     while (n) {
         int now = reds_stream_write(stream, buf, n);
         if (now <= 0) {
@@ -1342,10 +1342,11 @@ static int reds_send_link_ack(RedLinkInfo *link)
 {
     SpiceLinkHeader header;
     SpiceLinkReply ack;
+    Channel caps = { 0, };
     Channel *channel;
     BUF_MEM *bmBuf;
     BIO *bio;
-    int ret;
+    int ret = FALSE;
 
     header.magic = SPICE_MAGIC;
     header.size = sizeof(ack);
@@ -1354,14 +1355,14 @@ static int reds_send_link_ack(RedLinkInfo *link)
 
     ack.error = SPICE_LINK_ERR_OK;
 
-    if ((channel = reds_find_channel(link->link_mess->channel_type, 0))) {
-        ack.num_common_caps = channel->num_common_caps;
-        ack.num_channel_caps = channel->num_caps;
-        header.size += (ack.num_common_caps + ack.num_channel_caps) * sizeof(uint32_t);
-    } else {
-        ack.num_common_caps = 0;
-        ack.num_channel_caps = 0;
+    channel = reds_find_channel(link->link_mess->channel_type, 0);
+    if (!channel) {
+        channel = &caps;
     }
+
+    ack.num_common_caps = channel->num_common_caps;
+    ack.num_channel_caps = channel->num_caps;
+    header.size += (ack.num_common_caps + ack.num_channel_caps) * sizeof(uint32_t);
     ack.caps_offset = sizeof(SpiceLinkReply);
 
     if (!(link->tiTicketing.rsa = RSA_new())) {
@@ -1382,13 +1383,20 @@ static int reds_send_link_ack(RedLinkInfo *link)
     BIO_get_mem_ptr(bio, &bmBuf);
     memcpy(ack.pub_key, bmBuf->data, sizeof(ack.pub_key));
 
-    ret = sync_write(link->stream, &header, sizeof(header)) && sync_write(link->stream, &ack,
-                                                                        sizeof(ack));
-    if (channel) {
-        ret = ret && sync_write(link->stream, channel->common_caps,
-                                channel->num_common_caps * sizeof(uint32_t)) &&
-              sync_write(link->stream, channel->caps, channel->num_caps * sizeof(uint32_t));
-    }
+
+    if (!sync_write(link->stream, &header, sizeof(header)))
+        goto end;
+    if (!sync_write(link->stream, &ack, sizeof(ack)))
+        goto end;
+    if (!sync_write(link->stream, channel->common_caps, channel->num_common_caps * sizeof(uint32_t)))
+        goto end;
+    if (!sync_write(link->stream, channel->caps, channel->num_caps * sizeof(uint32_t)))
+        goto end;
+
+    ret = TRUE;
+
+end:
+    reds_channel_dispose(&caps);
     BIO_free(bio);
     return ret;
 }
commit 37dbb8aec917f02075094d991b471b56f5f0a4a6
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Fri Feb 11 03:57:59 2011 +0100

    server: pull out reds_handle_link(), for future reuse
    
    + a couple of indent, style change
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index e72bba3..d41e042 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1574,6 +1574,15 @@ static void reds_handle_other_links(RedLinkInfo *link)
     free(link_mess);
 }
 
+static void reds_handle_link(RedLinkInfo *link)
+{
+    if (link->link_mess->channel_type == SPICE_CHANNEL_MAIN) {
+        reds_handle_main_link(link);
+    } else {
+        reds_handle_other_links(link);
+    }
+}
+
 static void reds_handle_ticket(void *opaque)
 {
     RedLinkInfo *link = (RedLinkInfo *)opaque;
@@ -1604,11 +1613,8 @@ static void reds_handle_ticket(void *opaque)
             return;
         }
     }
-    if (link->link_mess->channel_type == SPICE_CHANNEL_MAIN) {
-        reds_handle_main_link(link);
-    } else {
-        reds_handle_other_links(link);
-    }
+
+    reds_handle_link(link);
 }
 
 static inline void async_read_clear_handlers(AsyncRead *obj)
@@ -1678,8 +1684,8 @@ static void reds_handle_read_link_done(void *opaque)
     uint32_t num_caps = link_mess->num_common_caps + link_mess->num_channel_caps;
 
     if (num_caps && (num_caps * sizeof(uint32_t) + link_mess->caps_offset >
-                                                   link->link_header.size ||
-                                                     link_mess->caps_offset < sizeof(*link_mess))) {
+                     link->link_header.size ||
+                     link_mess->caps_offset < sizeof(*link_mess))) {
         reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
         reds_link_free(link);
         return;
@@ -1853,6 +1859,7 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
     if (!(link = __reds_accept_connection(listen_socket))) {
         return NULL;
     }
+
     stream = link->stream;
     stream->read = stream_read_cb;
     stream->write = stream_write_cb;
@@ -1948,7 +1955,7 @@ static int reds_init_socket(const char *addr, int portnr, int family)
     snprintf(port, sizeof(port), "%d", portnr);
     rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
     if (rc != 0) {
-        red_error("getaddrinfo(%s,%s): %s\n", addr, port,
+        red_error("getaddrinfo(%s,%s): %s", addr, port,
                   gai_strerror(rc));
     }
 
@@ -1974,7 +1981,7 @@ static int reds_init_socket(const char *addr, int portnr, int family)
         }
         close(slisten);
     }
-    red_printf("%s: binding socket to %s:%d failed\n", __FUNCTION__,
+    red_printf("%s: binding socket to %s:%d failed", __FUNCTION__,
                addr, portnr);
     freeaddrinfo(res);
     return -1;
commit 414e1de7207c1c807832836d56f5e301e5cb156f
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Fri Feb 11 03:50:51 2011 +0100

    build: add --with-sasl
    
    Using cyrus SASL library (same as gtk-vnc/qemu).
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/configure.ac b/configure.ac
index 5642be3..31e832b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -300,6 +300,57 @@ AC_SUBST(JPEG_LIBS)
 AC_CHECK_LIB(z, deflate, Z_LIBS='-lz', AC_MSG_ERROR([zlib not found]))
 AC_SUBST(Z_LIBS)
 
+dnl Cyrus SASL, check from gtk-vnc
+AC_ARG_WITH([sasl],
+  [AS_HELP_STRING([--with-sasl],
+    [use cyrus SASL for authentication @<:@default=check@:>@])],
+  [],
+  [with_sasl=check])
+
+SASL_CFLAGS=
+SASL_LIBS=
+enable_sasl=no
+if test "x$with_sasl" != "xno"; then
+  if test "x$with_sasl" != "xyes" -a "x$with_sasl" != "xcheck"; then
+    SASL_CFLAGS="-I$with_sasl"
+    SASL_LIBS="-L$with_sasl"
+  fi
+  fail=0
+  old_cflags="$CFLAGS"
+  old_libs="$LIBS"
+  CFLAGS="$CFLAGS $SASL_CFLAGS"
+  LIBS="$LIBS $SASL_LIBS"
+  AC_CHECK_HEADER([sasl/sasl.h],[],[
+    if test "x$with_sasl" != "xcheck" ; then
+        with_sasl=no
+    else
+        fail=1
+    fi])
+  if test "x$with_sasl" != "xno" ; then
+    AC_CHECK_LIB([sasl2], [sasl_client_init],[with_sasl2=yes],[with_sasl2=no])
+  fi
+  if test "x$with_sasl2" = "xno" -a "x$with_sasl" != "xno" ; then
+    AC_CHECK_LIB([sasl], [sasl_client_init],[with_sasl=yes],[with_sasl=no])
+  fi
+  if test "x$with_sasl2" = "xyes"; then
+    SASL_LIBS="$SASL_LIBS -lsasl2"
+  elif test "x$with_sasl" = "xyes"; then
+    SASL_LIBS="$SASL_LIBS -lsasl"
+  else
+    AC_MSG_ERROR([You must install the Cyrus SASL development package in order to compile GTK-VNC])
+  fi
+  CFLAGS="$old_cflags"
+  LIBS="$old_libs"
+  if test "x$with_sasl2" = "xyes" -o "x$with_sasl" = "xyes" ; then
+    AC_DEFINE_UNQUOTED([HAVE_SASL], 1,
+      [whether Cyrus SASL is available for authentication])
+    enable_sasl=yes
+  fi
+fi
+AM_CONDITIONAL([HAVE_SASL], [test "x$with_sasl2" = "xyes" -o "x$with_sasl" = "xyes"])
+AC_SUBST([SASL_CFLAGS])
+AC_SUBST([SASL_LIBS])
+
 dnl ===========================================================================
 dnl check compiler flags
 
@@ -491,6 +542,8 @@ echo "
         GUI:                      ${use_gui}
 
         Smartcard:                ${have_smartcard}
+
+        SASL support:             ${enable_sasl}
 "
 
 if test $os_win32 == "yes" ; then
diff --git a/server/Makefile.am b/server/Makefile.am
index 1cc5010..5a5106e 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -11,6 +11,7 @@ INCLUDES = \
 	$(PIXMAN_CFLAGS)			\
 	$(GL_CFLAGS)				\
 	$(SSL_CFLAGS)				\
+	$(SASL_CFLAGS)				\
 	$(CELT051_CFLAGS)			\
 	$(SLIRP_CFLAGS)				\
 	-DSW_CANVAS_IMAGE_CACHE			\
@@ -67,6 +68,7 @@ libspice_server_la_LIBADD =			\
 	$(JPEG_LIBS)				\
 	$(PIXMAN_LIBS)				\
 	$(SSL_LIBS)				\
+	$(SASL_LIBS)				\
 	$(CELT051_LIBS)				\
 	$(SLIRP_LIBS)				\
 	$(LIBRT)				\
commit 2bbb4fca0c97043b183fb65126b7198bc0750a78
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Feb 9 15:11:22 2011 +0100

    common: add SpiceBuffer - based on qemu-vnc Buffer
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/common/mem.c b/common/mem.c
index b0a7eb1..a9bd6cc 100644
--- a/common/mem.c
+++ b/common/mem.c
@@ -237,3 +237,56 @@ void spice_chunks_linearize(SpiceChunks *chunks)
         chunks->chunk[0].len = chunks->data_size;
     }
 }
+
+void spice_buffer_reserve(SpiceBuffer *buffer, size_t len)
+{
+    if ((buffer->capacity - buffer->offset) < len) {
+        buffer->capacity += (len + 1024);
+        buffer->buffer = (uint8_t*)spice_realloc(buffer->buffer, buffer->capacity);
+    }
+}
+
+int spice_buffer_empty(SpiceBuffer *buffer)
+{
+    return buffer->offset == 0;
+}
+
+uint8_t *spice_buffer_end(SpiceBuffer *buffer)
+{
+    return buffer->buffer + buffer->offset;
+}
+
+void spice_buffer_reset(SpiceBuffer *buffer)
+{
+    buffer->offset = 0;
+}
+
+void spice_buffer_free(SpiceBuffer *buffer)
+{
+    free(buffer->buffer);
+    buffer->offset = 0;
+    buffer->capacity = 0;
+    buffer->buffer = NULL;
+}
+
+void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len)
+{
+    spice_buffer_reserve(buffer, len);
+    memcpy(buffer->buffer + buffer->offset, data, len);
+    buffer->offset += len;
+}
+
+size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len)
+{
+    len = MIN(buffer->offset, len);
+    memcpy(dest, buffer->buffer, len);
+    return len;
+}
+
+size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len)
+{
+    len = MIN(buffer->offset, len);
+    memmove(buffer->buffer, buffer->buffer + len, buffer->offset - len);
+    buffer->offset -= len;
+    return len;
+}
diff --git a/common/mem.h b/common/mem.h
index 5f0eb25..797bba0 100644
--- a/common/mem.h
+++ b/common/mem.h
@@ -39,6 +39,13 @@ typedef struct SpiceChunks {
     SpiceChunk   chunk[0];
 } SpiceChunks;
 
+typedef struct SpiceBuffer
+{
+    size_t capacity;
+    size_t offset;
+    uint8_t *buffer;
+} SpiceBuffer;
+
 char *spice_strdup(const char *str) SPICE_GNUC_MALLOC;
 char *spice_strndup(const char *str, size_t n_bytes) SPICE_GNUC_MALLOC;
 void *spice_memdup(const void *mem, size_t n_bytes) SPICE_GNUC_MALLOC;
@@ -103,4 +110,14 @@ size_t spice_strnlen(const char *str, size_t max_len);
 #define spice_new0(struct_type, n_structs) _SPICE_NEW(struct_type, n_structs, malloc0)
 #define spice_renew(struct_type, mem, n_structs) _SPICE_RENEW(struct_type, mem, n_structs, realloc)
 
+/* Buffer management */
+void spice_buffer_reserve(SpiceBuffer *buffer, size_t len);
+int spice_buffer_empty(SpiceBuffer *buffer);
+uint8_t *spice_buffer_end(SpiceBuffer *buffer);
+void spice_buffer_reset(SpiceBuffer *buffer);
+void spice_buffer_free(SpiceBuffer *buffer);
+void spice_buffer_append(SpiceBuffer *buffer, const void *data, size_t len);
+size_t spice_buffer_copy(SpiceBuffer *buffer, void *dest, size_t len);
+size_t spice_buffer_remove(SpiceBuffer *buffer, size_t len);
+
 #endif
commit 2ced8996c86605bad91c7d2f73ea5460252b4517
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Thu Feb 10 04:26:00 2011 +0100

    server/reds: make writev fallback more generic
    
    We are going to reuse it for SASL/SSF encode write().
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index 26f3533..e72bba3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -347,30 +347,6 @@ static ssize_t stream_ssl_read_cb(RedsStream *s, void *buf, size_t size)
     return return_code;
 }
 
-static ssize_t stream_ssl_writev_cb(RedsStream *s, const struct iovec *vector, int count)
-{
-    int i;
-    int n;
-    ssize_t return_code = 0;
-    int ssl_error;
-
-    for (i = 0; i < count; ++i) {
-        n = SSL_write(s->ssl, vector[i].iov_base, vector[i].iov_len);
-        if (n <= 0) {
-            ssl_error = SSL_get_error(s->ssl, n);
-            if (return_code <= 0) {
-                return n;
-            } else {
-                break;
-            }
-        } else {
-            return_code += n;
-        }
-    }
-
-    return return_code;
-}
-
 static void reds_stream_remove_watch(RedsStream* s)
 {
     if (s->watch) {
@@ -1914,7 +1890,7 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
 
     link->stream->write = stream_ssl_write_cb;
     link->stream->read = stream_ssl_read_cb;
-    link->stream->writev = stream_ssl_writev_cb;
+    link->stream->writev = NULL;
 
     return_code = SSL_accept(link->stream->ssl);
     if (return_code == 1) {
@@ -3158,7 +3134,22 @@ 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)
 {
-    return s->writev(s, iov, 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)
commit 76dc27f08a15bd2cb0e0f536972e361e6d7acc25
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Feb 9 21:44:45 2011 +0100

    server: rename s/peer/stream
    
    This is stylish change again. We are talking about a RedStream object,
    so let's just name the variable "stream" everywhere, to avoid
    confusion with a non existent RedPeer object.
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index ebf915c..551da27 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -494,14 +494,14 @@ static int inputs_channel_config_socket(RedChannel *channel)
     int flags;
     int delay_val = 1;
 
-    if (setsockopt(channel->peer->socket, IPPROTO_TCP, TCP_NODELAY,
+    if (setsockopt(channel->stream->socket, IPPROTO_TCP, TCP_NODELAY,
             &delay_val, sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
         return FALSE;
     }
 
-    if ((flags = fcntl(channel->peer->socket, F_GETFL)) == -1 ||
-                 fcntl(channel->peer->socket, F_SETFL, flags | O_ASYNC) == -1) {
+    if ((flags = fcntl(channel->stream->socket, F_GETFL)) == -1 ||
+                 fcntl(channel->stream->socket, F_SETFL, flags | O_ASYNC) == -1) {
         red_printf("fcntl failed, %s", strerror(errno));
         return FALSE;
     }
@@ -512,7 +512,7 @@ static void inputs_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void inputs_link(Channel *channel, RedsStream *peer, int migration,
+static void inputs_link(Channel *channel, RedsStream *stream, int migration,
                         int num_common_caps, uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
 {
@@ -521,7 +521,7 @@ static void inputs_link(Channel *channel, RedsStream *peer, int migration,
     ASSERT(channel->data == NULL);
 
     g_inputs_channel = inputs_channel = (InputsChannel*)red_channel_create_parser(
-        sizeof(*inputs_channel), peer, core, migration, FALSE /* handle_acks */
+        sizeof(*inputs_channel), stream, core, migration, FALSE /* handle_acks */
         ,inputs_channel_config_socket
         ,spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL)
         ,inputs_channel_handle_parsed
diff --git a/server/main_channel.c b/server/main_channel.c
index f43f89a..d24c7aa 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -780,7 +780,7 @@ static void main_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void main_channel_link(Channel *channel, RedsStream *peer, int migration,
+static void main_channel_link(Channel *channel, RedsStream *stream, int migration,
                         int num_common_caps, uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
 {
@@ -789,7 +789,7 @@ static void main_channel_link(Channel *channel, RedsStream *peer, int migration,
     ASSERT(channel->data == NULL);
 
     main_chan = (MainChannel*)red_channel_create_parser(
-        sizeof(*main_chan), peer, core, migration, FALSE /* handle_acks */
+        sizeof(*main_chan), stream, core, migration, FALSE /* handle_acks */
         ,main_channel_config_socket
         ,spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL)
         ,main_channel_handle_parsed
@@ -808,22 +808,22 @@ int main_channel_getsockname(Channel *channel, struct sockaddr *sa, socklen_t *s
 {
     MainChannel *main_chan = channel->data;
 
-    return main_chan ? getsockname(main_chan->base.peer->socket, sa, salen) : -1;
+    return main_chan ? getsockname(main_chan->base.stream->socket, sa, salen) : -1;
 }
 
 int main_channel_getpeername(Channel *channel, struct sockaddr *sa, socklen_t *salen)
 {
     MainChannel *main_chan = channel->data;
 
-    return main_chan ? getpeername(main_chan->base.peer->socket, sa, salen) : -1;
+    return main_chan ? getpeername(main_chan->base.stream->socket, sa, salen) : -1;
 }
 
 void main_channel_close(Channel *channel)
 {
     MainChannel *main_chan = channel->data;
 
-    if (main_chan && main_chan->base.peer) {
-        close(main_chan->base.peer->socket);
+    if (main_chan && main_chan->base.stream) {
+        close(main_chan->base.stream->socket);
     }
 }
 
diff --git a/server/red_channel.c b/server/red_channel.c
index 3676b5a..b077bcd 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -33,15 +33,15 @@ static PipeItem *red_channel_pipe_get(RedChannel *channel);
 static void red_channel_event(int fd, int event, void *data);
 
 /* return the number of bytes read. -1 in case of error */
-static int red_peer_receive(RedsStream *peer, uint8_t *buf, uint32_t size)
+static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
 {
     uint8_t *pos = buf;
     while (size) {
         int now;
-        if (peer->shutdown) {
+        if (stream->shutdown) {
             return -1;
         }
-        now = reds_stream_read(peer, pos, size);
+        now = reds_stream_read(stream, pos, size);
         if (now <= 0) {
             if (now == 0) {
                 return -1;
@@ -69,7 +69,7 @@ static int red_peer_receive(RedsStream *peer, uint8_t *buf, uint32_t size)
 // does many calls to red_peer_receive and through it cb_read, and thus avoids pointer
 // arithmetic for the case where a single cb_read could return multiple messages. But
 // this is suboptimal potentially. Profile and consider fixing.
-static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
+static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handler)
 {
     int bytes_read;
     uint8_t *parsed;
@@ -79,7 +79,7 @@ static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
     for (;;) {
         int ret_handle;
         if (handler->header_pos < sizeof(SpiceDataHeader)) {
-            bytes_read = red_peer_receive(peer,
+            bytes_read = red_peer_receive(stream,
                                           ((uint8_t *)&handler->header) + handler->header_pos,
                                           sizeof(SpiceDataHeader) - handler->header_pos);
             if (bytes_read == -1) {
@@ -103,7 +103,7 @@ static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
                 }
             }
 
-            bytes_read = red_peer_receive(peer,
+            bytes_read = red_peer_receive(stream,
                                           handler->msg + handler->msg_pos,
                                           handler->header.size - handler->msg_pos);
             if (bytes_read == -1) {
@@ -150,10 +150,10 @@ static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
 
 void red_channel_receive(RedChannel *channel)
 {
-    red_peer_handle_incoming(channel->peer, &channel->incoming);
+    red_peer_handle_incoming(channel->stream, &channel->incoming);
 }
 
-static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
+static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
 {
     ssize_t n;
 
@@ -167,7 +167,7 @@ static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
 
     for (;;) {
         handler->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
-        n = reds_stream_writev(peer, handler->vec, handler->vec_size);
+        n = reds_stream_writev(stream, handler->vec, handler->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
@@ -236,7 +236,7 @@ static void red_channel_peer_on_out_block(void *opaque)
     RedChannel *channel = (RedChannel *)opaque;
 
     channel->send_data.blocked = TRUE;
-    channel->core->watch_update_mask(channel->peer->watch,
+    channel->core->watch_update_mask(channel->stream->watch,
                                      SPICE_WATCH_EVENT_READ |
                                      SPICE_WATCH_EVENT_WRITE);
 }
@@ -251,12 +251,12 @@ static void red_channel_peer_on_out_msg_done(void *opaque)
     }
     if (channel->send_data.blocked) {
         channel->send_data.blocked = FALSE;
-        channel->core->watch_update_mask(channel->peer->watch,
+        channel->core->watch_update_mask(channel->stream->watch,
                                          SPICE_WATCH_EVENT_READ);
     }
 }
 
-RedChannel *red_channel_create(int size, RedsStream *peer,
+RedChannel *red_channel_create(int size, RedsStream *stream,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -281,7 +281,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
     channel->release_item = release_item;
     channel->hold_item = hold_item;
 
-    channel->peer = peer;
+    channel->stream = stream;
     channel->core = core;
     channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
                                              // block flags)
@@ -315,7 +315,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
         goto error;
     }
 
-    channel->peer->watch = channel->core->watch_add(channel->peer->socket,
+    channel->stream->watch = channel->core->watch_add(channel->stream->socket,
                                                     SPICE_WATCH_EVENT_READ,
                                                     red_channel_event, channel);
 
@@ -324,7 +324,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
 error:
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
-    reds_stream_free(peer);
+    reds_stream_free(stream);
 
     return NULL;
 }
@@ -338,7 +338,7 @@ int do_nothing_handle_message(RedChannel *red_channel, SpiceDataHeader *header,
     return TRUE;
 }
 
-RedChannel *red_channel_create_parser(int size, RedsStream *peer,
+RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -352,7 +352,7 @@ RedChannel *red_channel_create_parser(int size, RedsStream *peer,
                                channel_on_incoming_error_proc incoming_error,
                                channel_on_outgoing_error_proc outgoing_error)
 {
-    RedChannel *channel = red_channel_create(size, peer,
+    RedChannel *channel = red_channel_create(size, stream,
         core, migrate, handle_acks, config_socket, do_nothing_disconnect,
         do_nothing_handle_message, alloc_recv_buf, release_recv_buf, hold_item,
         send_item, release_item);
@@ -375,7 +375,7 @@ void red_channel_destroy(RedChannel *channel)
         return;
     }
     red_channel_pipe_clear(channel);
-    reds_stream_free(channel->peer);
+    reds_stream_free(channel->stream);
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
 }
@@ -383,12 +383,12 @@ void red_channel_destroy(RedChannel *channel)
 void red_channel_shutdown(RedChannel *channel)
 {
     red_printf("");
-    if (channel->peer && !channel->peer->shutdown) {
-        channel->core->watch_update_mask(channel->peer->watch,
+    if (channel->stream && !channel->stream->shutdown) {
+        channel->core->watch_update_mask(channel->stream->watch,
                                          SPICE_WATCH_EVENT_READ);
         red_channel_pipe_clear(channel);
-        shutdown(channel->peer->socket, SHUT_RDWR);
-        channel->peer->shutdown = TRUE;
+        shutdown(channel->stream->socket, SHUT_RDWR);
+        channel->stream->shutdown = TRUE;
     }
 }
 
@@ -471,7 +471,7 @@ void red_channel_init_send_data(RedChannel *channel, uint16_t msg_type, PipeItem
 
 void red_channel_send(RedChannel *channel)
 {
-    red_peer_handle_outgoing(channel->peer, &channel->outgoing);
+    red_peer_handle_outgoing(channel->stream, &channel->outgoing);
 }
 
 void red_channel_begin_send_message(RedChannel *channel)
@@ -600,7 +600,7 @@ static inline PipeItem *red_channel_pipe_get(RedChannel *channel)
 
 int red_channel_is_connected(RedChannel *channel)
 {
-    return !!channel->peer;
+    return !!channel->stream;
 }
 
 void red_channel_pipe_clear(RedChannel *channel)
diff --git a/server/red_channel.h b/server/red_channel.h
index fd9ce37..a23a618 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -114,7 +114,7 @@ typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
 typedef void (*channel_on_outgoing_error_proc)(RedChannel *channel);
 
 struct RedChannel {
-    RedsStream *peer;
+    RedsStream *stream;
     SpiceCoreInterface *core;
     int migrate;
     int handle_acks;
@@ -160,7 +160,7 @@ struct RedChannel {
 
 /* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
    explicitly destroy the channel */
-RedChannel *red_channel_create(int size, RedsStream *peer,
+RedChannel *red_channel_create(int size, RedsStream *stream,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -174,7 +174,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
 
 /* alternative constructor, meant for marshaller based (inputs,main) channels,
  * will become default eventually */
-RedChannel *red_channel_create_parser(int size, RedsStream *peer,
+RedChannel *red_channel_create_parser(int size, RedsStream *stream,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 3816e14..75e0670 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -71,7 +71,7 @@ extern spice_wan_compression_t zlib_glz_state;
 
 static RedDispatcher *dispatchers = NULL;
 
-static void red_dispatcher_set_peer(Channel *channel, RedsStream *peer, int migration,
+static void red_dispatcher_set_peer(Channel *channel, RedsStream *stream, int migration,
                                     int num_common_caps, uint32_t *common_caps, int num_caps,
                                     uint32_t *caps)
 {
@@ -81,7 +81,7 @@ static void red_dispatcher_set_peer(Channel *channel, RedsStream *peer, int migr
     dispatcher = (RedDispatcher *)channel->data;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_CONNECT;
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &peer, sizeof(RedsStream *));
+    send_data(dispatcher->channel, &stream, sizeof(RedsStream *));
     send_data(dispatcher->channel, &migration, sizeof(int));
 }
 
@@ -101,7 +101,7 @@ static void red_dispatcher_migrate(Channel *channel)
     write_message(dispatcher->channel, &message);
 }
 
-static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStream *peer,
+static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStream *stream,
                                            int migration, int num_common_caps,
                                            uint32_t *common_caps, int num_caps,
                                            uint32_t *caps)
@@ -110,7 +110,7 @@ static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStream *peer,
     red_printf("");
     RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_CONNECT;
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &peer, sizeof(RedsStream *));
+    send_data(dispatcher->channel, &stream, sizeof(RedsStream *));
     send_data(dispatcher->channel, &migration, sizeof(int));
 }
 
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 6ea58f0..fddcf2c 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -598,7 +598,7 @@ static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer,
 
 
 /* reds interface */
-static void handle_tunnel_channel_link(Channel *channel, RedsStream *peer, int migration,
+static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int migration,
                                        int num_common_caps, uint32_t *common_caps, int num_caps,
                                        uint32_t *caps);
 static void handle_tunnel_channel_shutdown(struct Channel *channel);
@@ -3347,19 +3347,19 @@ static int tunnel_channel_config_socket(RedChannel *channel)
     int flags;
     int delay_val;
 
-    if ((flags = fcntl(channel->peer->socket, F_GETFL)) == -1) {
+    if ((flags = fcntl(channel->stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno)); // can't we just use red_error?
         return FALSE;
     }
 
-    if (fcntl(channel->peer->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+    if (fcntl(channel->stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         return FALSE;
     }
 
     delay_val = 1;
 
-    if (setsockopt(channel->peer->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
+    if (setsockopt(channel->stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val,
                    sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
@@ -3424,7 +3424,7 @@ static void tunnel_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void handle_tunnel_channel_link(Channel *channel, RedsStream *peer, int migration,
+static void handle_tunnel_channel_link(Channel *channel, RedsStream *stream, int migration,
                                        int num_common_caps, uint32_t *common_caps, int num_caps,
                                        uint32_t *caps)
 {
@@ -3435,7 +3435,7 @@ static void handle_tunnel_channel_link(Channel *channel, RedsStream *peer, int m
     }
 
     tunnel_channel =
-        (TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), peer, worker->core_interface,
+        (TunnelChannel *)red_channel_create(sizeof(*tunnel_channel), stream, worker->core_interface,
                                             migration, TRUE,
                                             tunnel_channel_config_socket,
                                             tunnel_channel_disconnect,
diff --git a/server/red_worker.c b/server/red_worker.c
index 3332f10..21d2f6c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -355,7 +355,7 @@ typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, ui
 
 struct RedChannel {
     spice_parse_channel_func_t parser;
-    RedsStream *peer;
+    RedsStream *stream;
     int migrate;
 
     Ring pipe;
@@ -7353,8 +7353,8 @@ static void red_send_data(RedChannel *channel)
         }
         vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
                                                vec, MAX_SEND_VEC, channel->send_data.pos);
-        ASSERT(channel->peer);
-        n = reds_stream_writev(channel->peer, vec, vec_size);
+        ASSERT(channel->stream);
+        n = reds_stream_writev(channel->stream, vec, vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
@@ -8542,15 +8542,15 @@ void red_show_tree(RedWorker *worker)
 
 static inline int channel_is_connected(RedChannel *channel)
 {
-    return !!channel->peer;
+    return !!channel->stream;
 }
 
 static void red_disconnect_channel(RedChannel *channel)
 {
     channel_release_res(channel);
     red_pipe_clear(channel);
-    reds_stream_free(channel->peer);
-    channel->peer = NULL;
+    reds_stream_free(channel->stream);
+    channel->stream = NULL;
     channel->send_data.blocked = FALSE;
     channel->send_data.size = channel->send_data.pos = 0;
     spice_marshaller_reset(channel->send_data.marshaller);
@@ -8563,7 +8563,7 @@ static void red_disconnect_display(RedChannel *channel)
     CommonChannel *common = SPICE_CONTAINEROF(channel, CommonChannel, base);
     RedWorker *worker;
 
-    if (!channel || !channel->peer) {
+    if (!channel || !channel->stream) {
         return;
     }
     worker = common->worker;
@@ -8895,7 +8895,7 @@ static int display_channel_wait_for_init(DisplayChannel *display_channel)
     uint64_t end_time = red_now() + DISPLAY_CLIENT_TIMEOUT;
     for (;;) {
         red_receive((RedChannel *)display_channel);
-        if (!display_channel->common.base.peer) {
+        if (!display_channel->common.base.stream) {
             break;
         }
         if (display_channel->pixmap_cache && display_channel->glz_dict) {
@@ -9277,8 +9277,8 @@ static void red_receive(RedChannel *channel)
         ssize_t n;
         n = channel->recive_data.end - channel->recive_data.now;
         ASSERT(n);
-        ASSERT(channel->peer);
-        n = reds_stream_read(channel->peer, channel->recive_data.now, n);
+        ASSERT(channel->stream);
+        n = reds_stream_read(channel->stream, channel->recive_data.now, n);
         if (n <= 0) {
             if (n == 0) {
                 channel->disconnect(channel);
@@ -9352,7 +9352,7 @@ static void free_common_channel_from_listener(EventListener *ctx)
 }
 
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
-                                 RedsStream *peer, int migrate,
+                                 RedsStream *stream, int migrate,
                                  event_listener_action_proc handler,
                                  channel_disconnect_proc disconnect,
                                  channel_hold_pipe_item_proc hold_item,
@@ -9365,18 +9365,18 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     int flags;
     int delay_val;
 
-    if ((flags = fcntl(peer->socket, F_GETFL)) == -1) {
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         goto error1;
     }
 
-    if (fcntl(peer->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+    if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         goto error1;
     }
 
     delay_val = IS_LOW_BANDWIDTH() ? 0 : 1;
-    if (setsockopt(peer->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
+    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
 
@@ -9393,7 +9393,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
     channel->hold_item = hold_item;
     channel->release_item = release_item;
     channel->handle_parsed = handle_parsed;
-    channel->peer = peer;
+    channel->stream = stream;
     common->worker = worker;
     channel->ack_data.messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
                                     // block flags)
@@ -9408,7 +9408,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
 
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = &common->listener;
-    if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, peer->socket, &event) == -1) {
+    if (epoll_ctl(worker->epoll, EPOLL_CTL_ADD, stream->socket, &event) == -1) {
         red_printf("epoll_ctl failed, %s", strerror(errno));
         goto error2;
     }
@@ -9420,7 +9420,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
 error2:
     free(channel);
 error1:
-    reds_stream_free(peer);
+    reds_stream_free(stream);
 
     return NULL;
 }
@@ -9485,7 +9485,7 @@ static void display_channel_release_item(RedChannel *channel, PipeItem *item, in
     }
 }
 
-static void handle_new_display_channel(RedWorker *worker, RedsStream *peer, int migrate)
+static void handle_new_display_channel(RedWorker *worker, RedsStream *stream, int migrate)
 {
     DisplayChannel *display_channel;
     size_t stream_buf_size;
@@ -9493,7 +9493,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *peer, int
     red_disconnect_display((RedChannel *)worker->display_channel);
 
     if (!(display_channel = (DisplayChannel *)__new_channel(worker, sizeof(*display_channel),
-                                                            SPICE_CHANNEL_DISPLAY, peer,
+                                                            SPICE_CHANNEL_DISPLAY, stream,
                                                             migrate, handle_channel_events,
                                                             red_disconnect_display,
                                                             display_channel_hold_pipe_item,
@@ -9567,7 +9567,7 @@ static void red_disconnect_cursor(RedChannel *channel)
 {
     CommonChannel *common;
 
-    if (!channel || !channel->peer) {
+    if (!channel || !channel->stream) {
         return;
     }
     common = SPICE_CONTAINEROF(channel, CommonChannel, base);
@@ -9612,14 +9612,14 @@ static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int
     red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
 }
 
-static void red_connect_cursor(RedWorker *worker, RedsStream *peer, int migrate)
+static void red_connect_cursor(RedWorker *worker, RedsStream *stream, int migrate)
 {
     CursorChannel *channel;
 
     red_disconnect_cursor((RedChannel *)worker->cursor_channel);
 
     if (!(channel = (CursorChannel *)__new_channel(worker, sizeof(*channel),
-                                                   SPICE_CHANNEL_CURSOR, peer, migrate,
+                                                   SPICE_CHANNEL_CURSOR, stream, migrate,
                                                    handle_channel_events,
                                                    red_disconnect_cursor,
                                                    cursor_channel_hold_pipe_item,
@@ -10053,13 +10053,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         handle_dev_destroy_primary_surface(worker);
         break;
     case RED_WORKER_MESSAGE_DISPLAY_CONNECT: {
-        RedsStream *peer;
+        RedsStream *stream;
         int migrate;
         red_printf("connect");
 
-        receive_data(worker->channel, &peer, sizeof(RedsStream *));
+        receive_data(worker->channel, &stream, sizeof(RedsStream *));
         receive_data(worker->channel, &migrate, sizeof(int));
-        handle_new_display_channel(worker, peer, migrate);
+        handle_new_display_channel(worker, stream, migrate);
         break;
     }
     case RED_WORKER_MESSAGE_DISPLAY_DISCONNECT:
@@ -10101,13 +10101,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_migrate_display(worker);
         break;
     case RED_WORKER_MESSAGE_CURSOR_CONNECT: {
-        RedsStream *peer;
+        RedsStream *stream;
         int migrate;
 
         red_printf("cursor connect");
-        receive_data(worker->channel, &peer, sizeof(RedsStream *));
+        receive_data(worker->channel, &stream, sizeof(RedsStream *));
         receive_data(worker->channel, &migrate, sizeof(int));
-        red_connect_cursor(worker, peer, migrate);
+        red_connect_cursor(worker, stream, migrate);
         break;
     }
     case RED_WORKER_MESSAGE_CURSOR_DISCONNECT:
diff --git a/server/reds.c b/server/reds.c
index f8d8a0e..26f3533 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -224,7 +224,7 @@ typedef struct RedsState {
 static RedsState *reds = NULL;
 
 typedef struct AsyncRead {
-    RedsStream *peer;
+    RedsStream *stream;
     void *opaque;
     uint8_t *now;
     uint8_t *end;
@@ -233,7 +233,7 @@ typedef struct AsyncRead {
 } AsyncRead;
 
 typedef struct RedLinkInfo {
-    RedsStream *peer;
+    RedsStream *stream;
     AsyncRead asyc_read;
     SpiceLinkHeader link_header;
     SpiceLinkMess *link_mess;
@@ -297,11 +297,11 @@ static ChannelSecurityOptions *find_channel_security(int id)
     return now;
 }
 
-static void reds_channel_event(RedsStream *peer, int event)
+static void reds_stream_channel_event(RedsStream *s, int event)
 {
     if (core->base.minor_version < 3 || core->channel_event == NULL)
         return;
-    core->channel_event(event, &peer->info);
+    core->channel_event(event, &s->info);
 }
 
 static ssize_t stream_write_cb(RedsStream *s, const void *buf, size_t size)
@@ -381,8 +381,8 @@ static void reds_stream_remove_watch(RedsStream* s)
 
 static void reds_link_free(RedLinkInfo *link)
 {
-    reds_stream_free(link->peer);
-    link->peer = NULL;
+    reds_stream_free(link->stream);
+    link->stream = NULL;
 
     free(link->link_mess);
     link->link_mess = NULL;
@@ -1345,11 +1345,11 @@ void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
     while (write_to_vdi_port() || read_from_vdi_port());
 }
 
-static int sync_write(RedsStream *peer, void *in_buf, size_t n)
+static int sync_write(RedsStream *stream, void *in_buf, size_t n)
 {
     uint8_t *buf = (uint8_t *)in_buf;
     while (n) {
-        int now = reds_stream_write(peer, buf, n);
+        int now = reds_stream_write(stream, buf, n);
         if (now <= 0) {
             if (now == -1 && (errno == EINTR || errno == EAGAIN)) {
                 continue;
@@ -1406,12 +1406,12 @@ static int reds_send_link_ack(RedLinkInfo *link)
     BIO_get_mem_ptr(bio, &bmBuf);
     memcpy(ack.pub_key, bmBuf->data, sizeof(ack.pub_key));
 
-    ret = sync_write(link->peer, &header, sizeof(header)) && sync_write(link->peer, &ack,
+    ret = sync_write(link->stream, &header, sizeof(header)) && sync_write(link->stream, &ack,
                                                                         sizeof(ack));
     if (channel) {
-        ret = ret && sync_write(link->peer, channel->common_caps,
+        ret = ret && sync_write(link->stream, channel->common_caps,
                                 channel->num_common_caps * sizeof(uint32_t)) &&
-              sync_write(link->peer, channel->caps, channel->num_caps * sizeof(uint32_t));
+              sync_write(link->stream, channel->caps, channel->num_caps * sizeof(uint32_t));
     }
     BIO_free(bio);
     return ret;
@@ -1428,7 +1428,7 @@ static int reds_send_link_error(RedLinkInfo *link, uint32_t error)
     header.minor_version = SPICE_VERSION_MINOR;
     memset(&reply, 0, sizeof(reply));
     reply.error = error;
-    return sync_write(link->peer, &header, sizeof(header)) && sync_write(link->peer, &reply,
+    return sync_write(link->stream, &header, sizeof(header)) && sync_write(link->stream, &reply,
                                                                          sizeof(reply));
 }
 
@@ -1437,27 +1437,27 @@ static void reds_show_new_channel(RedLinkInfo *link, int connection_id)
     red_printf("channel %d:%d, connected successfully, over %s link",
                link->link_mess->channel_type,
                link->link_mess->channel_id,
-               link->peer->ssl == NULL ? "Non Secure" : "Secure");
+               link->stream->ssl == NULL ? "Non Secure" : "Secure");
     /* add info + send event */
-    if (link->peer->ssl) {
-        link->peer->info.flags |= SPICE_CHANNEL_EVENT_FLAG_TLS;
+    if (link->stream->ssl) {
+        link->stream->info.flags |= SPICE_CHANNEL_EVENT_FLAG_TLS;
     }
-    link->peer->info.connection_id = connection_id;
-    link->peer->info.type = link->link_mess->channel_type;
-    link->peer->info.id   = link->link_mess->channel_id;
-    reds_channel_event(link->peer, SPICE_CHANNEL_EVENT_INITIALIZED);
+    link->stream->info.connection_id = connection_id;
+    link->stream->info.type = link->link_mess->channel_type;
+    link->stream->info.id   = link->link_mess->channel_id;
+    reds_stream_channel_event(link->stream, SPICE_CHANNEL_EVENT_INITIALIZED);
 }
 
 static void reds_send_link_result(RedLinkInfo *link, uint32_t error)
 {
-    sync_write(link->peer, &error, sizeof(error));
+    sync_write(link->stream, &error, sizeof(error));
 }
 
 // TODO: now that main is a separate channel this should
 // actually be joined with reds_handle_other_links, ebcome reds_handle_link
 static void reds_handle_main_link(RedLinkInfo *link)
 {
-    RedsStream *peer;
+    RedsStream *stream;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
     uint32_t connection_id;
@@ -1489,14 +1489,14 @@ static void reds_handle_main_link(RedLinkInfo *link)
     reds->mig_wait_disconnect = FALSE;
 
     reds_show_new_channel(link, connection_id);
-    peer = link->peer;
-    reds_stream_remove_watch(peer);
-    link->peer = NULL;
+    stream = link->stream;
+    reds_stream_remove_watch(stream);
+    link->stream = NULL;
     link->link_mess = NULL;
     reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
     reds->main_channel = main_channel_init();
-    reds->main_channel->link(reds->main_channel, peer, reds->mig_target, link_mess->num_common_caps,
+    reds->main_channel->link(reds->main_channel, stream, reds->mig_target, link_mess->num_common_caps,
                   link_mess->num_common_caps ? caps : NULL, link_mess->num_channel_caps,
                   link_mess->num_channel_caps ? caps + link_mess->num_common_caps : NULL);
     free(link_mess);
@@ -1560,7 +1560,7 @@ static void openssl_init(RedLinkInfo *link)
 static void reds_handle_other_links(RedLinkInfo *link)
 {
     Channel *channel;
-    RedsStream *peer;
+    RedsStream *stream;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
 
@@ -1581,18 +1581,18 @@ static void reds_handle_other_links(RedLinkInfo *link)
 
     reds_send_link_result(link, SPICE_LINK_ERR_OK);
     reds_show_new_channel(link, reds->link_id);
-    if (link_mess->channel_type == SPICE_CHANNEL_INPUTS && !link->peer->ssl) {
+    if (link_mess->channel_type == SPICE_CHANNEL_INPUTS && !link->stream->ssl) {
         char *mess = "keyboard channel is insecure";
         const int mess_len = strlen(mess);
         main_channel_push_notify(reds->main_channel, (uint8_t*)mess, mess_len);
     }
-    peer = link->peer;
-    reds_stream_remove_watch(peer);
-    link->peer = NULL;
+    stream = link->stream;
+    reds_stream_remove_watch(stream);
+    link->stream = NULL;
     link->link_mess = NULL;
     reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
-    channel->link(channel, peer, reds->mig_target, link_mess->num_common_caps,
+    channel->link(channel, stream, reds->mig_target, link_mess->num_common_caps,
                   link_mess->num_common_caps ? caps : NULL, link_mess->num_channel_caps,
                   link_mess->num_channel_caps ? caps + link_mess->num_common_caps : NULL);
     free(link_mess);
@@ -1637,10 +1637,11 @@ static void reds_handle_ticket(void *opaque)
 
 static inline void async_read_clear_handlers(AsyncRead *obj)
 {
-    if (!obj->peer->watch) {
+    if (!obj->stream->watch) {
         return;
     }
-    reds_stream_remove_watch(obj->peer);
+
+    reds_stream_remove_watch(obj->stream);
 }
 
 static void async_read_handler(int fd, int event, void *data)
@@ -1651,13 +1652,13 @@ static void async_read_handler(int fd, int event, void *data)
         int n = obj->end - obj->now;
 
         ASSERT(n > 0);
-        n = reds_stream_read(obj->peer, obj->now, n);
+        n = reds_stream_read(obj->stream, obj->now, n);
         if (n <= 0) {
             if (n < 0) {
                 switch (errno) {
                 case EAGAIN:
-                    if (!obj->peer->watch) {
-                        obj->peer->watch = core->watch_add(obj->peer->socket,
+                    if (!obj->stream->watch) {
+                        obj->stream->watch = core->watch_add(obj->stream->socket,
                                                            SPICE_WATCH_EVENT_READ,
                                                            async_read_handler, obj);
                     }
@@ -1689,8 +1690,8 @@ static int reds_security_check(RedLinkInfo *link)
 {
     ChannelSecurityOptions *security_option = find_channel_security(link->link_mess->channel_type);
     uint32_t security = security_option ? security_option->options : default_channel_security;
-    return (link->peer->ssl && (security & SPICE_CHANNEL_SECURITY_SSL)) ||
-        (!link->peer->ssl && (security & SPICE_CHANNEL_SECURITY_NONE));
+    return (link->stream->ssl && (security & SPICE_CHANNEL_SECURITY_SSL)) ||
+        (!link->stream->ssl && (security & SPICE_CHANNEL_SECURITY_NONE));
 }
 
 static void reds_handle_read_link_done(void *opaque)
@@ -1709,7 +1710,7 @@ static void reds_handle_read_link_done(void *opaque)
     }
 
     if (!reds_security_check(link)) {
-        if (link->peer->ssl) {
+        if (link->stream->ssl) {
             red_printf("spice channels %d should not be encrypted", link_mess->channel_type);
             reds_send_link_error(link, SPICE_LINK_ERR_NEED_UNSECURED);
         } else {
@@ -1788,7 +1789,7 @@ static void reds_handle_new_link(RedLinkInfo *link)
 {
     AsyncRead *obj = &link->asyc_read;
     obj->opaque = link;
-    obj->peer = link->peer;
+    obj->stream = link->stream;
     obj->now = (uint8_t *)&link->link_header;
     obj->end = (uint8_t *)((SpiceLinkHeader *)&link->link_header + 1);
     obj->done = reds_handle_read_header_done;
@@ -1801,28 +1802,28 @@ static void reds_handle_ssl_accept(int fd, int event, void *data)
     RedLinkInfo *link = (RedLinkInfo *)data;
     int return_code;
 
-    if ((return_code = SSL_accept(link->peer->ssl)) != 1) {
-        int ssl_error = SSL_get_error(link->peer->ssl, return_code);
+    if ((return_code = SSL_accept(link->stream->ssl)) != 1) {
+        int ssl_error = SSL_get_error(link->stream->ssl, return_code);
         if (ssl_error != SSL_ERROR_WANT_READ && ssl_error != SSL_ERROR_WANT_WRITE) {
             red_printf("SSL_accept failed, error=%d", ssl_error);
             reds_link_free(link);
         } else {
             if (ssl_error == SSL_ERROR_WANT_READ) {
-                core->watch_update_mask(link->peer->watch, SPICE_WATCH_EVENT_READ);
+                core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_READ);
             } else {
-                core->watch_update_mask(link->peer->watch, SPICE_WATCH_EVENT_WRITE);
+                core->watch_update_mask(link->stream->watch, SPICE_WATCH_EVENT_WRITE);
             }
         }
         return;
     }
-    reds_stream_remove_watch(link->peer);
+    reds_stream_remove_watch(link->stream);
     reds_handle_new_link(link);
 }
 
 static RedLinkInfo *__reds_accept_connection(int listen_socket)
 {
     RedLinkInfo *link;
-    RedsStream *peer;
+    RedsStream *stream;
     int delay_val = 1;
     int flags;
     int socket;
@@ -1847,16 +1848,16 @@ static RedLinkInfo *__reds_accept_connection(int listen_socket)
     }
 
     link = spice_new0(RedLinkInfo, 1);
-    peer = spice_new0(RedsStream, 1);
-    link->peer = peer;
-    peer->socket = socket;
+    stream = spice_new0(RedsStream, 1);
+    link->stream = stream;
 
+    stream->socket = socket;
     /* gather info + send event */
-    peer->info.llen = sizeof(peer->info.laddr);
-    peer->info.plen = sizeof(peer->info.paddr);
-    getsockname(peer->socket, (struct sockaddr*)(&peer->info.laddr), &peer->info.llen);
-    getpeername(peer->socket, (struct sockaddr*)(&peer->info.paddr), &peer->info.plen);
-    reds_channel_event(peer, SPICE_CHANNEL_EVENT_CONNECTED);
+    stream->info.llen = sizeof(stream->info.laddr);
+    stream->info.plen = sizeof(stream->info.paddr);
+    getsockname(stream->socket, (struct sockaddr*)(&stream->info.laddr), &stream->info.llen);
+    getpeername(stream->socket, (struct sockaddr*)(&stream->info.paddr), &stream->info.plen);
+    reds_stream_channel_event(stream, SPICE_CHANNEL_EVENT_CONNECTED);
 
     openssl_init(link);
 
@@ -1871,15 +1872,15 @@ error:
 static RedLinkInfo *reds_accept_connection(int listen_socket)
 {
     RedLinkInfo *link;
-    RedsStream *peer;
+    RedsStream *stream;
 
     if (!(link = __reds_accept_connection(listen_socket))) {
         return NULL;
     }
-    peer = link->peer;
-    peer->read = stream_read_cb;
-    peer->write = stream_write_cb;
-    peer->writev = stream_writev_cb;
+    stream = link->stream;
+    stream->read = stream_read_cb;
+    stream->write = stream_write_cb;
+    stream->writev = stream_writev_cb;
 
     return link;
 }
@@ -1897,47 +1898,47 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
     }
 
     // Handle SSL handshaking
-    if (!(sbio = BIO_new_socket(link->peer->socket, BIO_NOCLOSE))) {
+    if (!(sbio = BIO_new_socket(link->stream->socket, BIO_NOCLOSE))) {
         red_printf("could not allocate ssl bio socket");
         goto error;
     }
 
-    link->peer->ssl = SSL_new(reds->ctx);
-    if (!link->peer->ssl) {
+    link->stream->ssl = SSL_new(reds->ctx);
+    if (!link->stream->ssl) {
         red_printf("could not allocate ssl context");
         BIO_free(sbio);
         goto error;
     }
 
-    SSL_set_bio(link->peer->ssl, sbio, sbio);
+    SSL_set_bio(link->stream->ssl, sbio, sbio);
 
-    link->peer->write = stream_ssl_write_cb;
-    link->peer->read = stream_ssl_read_cb;
-    link->peer->writev = stream_ssl_writev_cb;
+    link->stream->write = stream_ssl_write_cb;
+    link->stream->read = stream_ssl_read_cb;
+    link->stream->writev = stream_ssl_writev_cb;
 
-    return_code = SSL_accept(link->peer->ssl);
+    return_code = SSL_accept(link->stream->ssl);
     if (return_code == 1) {
         reds_handle_new_link(link);
         return;
     }
 
-    ssl_error = SSL_get_error(link->peer->ssl, return_code);
+    ssl_error = SSL_get_error(link->stream->ssl, return_code);
     if (return_code == -1 && (ssl_error == SSL_ERROR_WANT_READ ||
                               ssl_error == SSL_ERROR_WANT_WRITE)) {
         int eventmask = ssl_error == SSL_ERROR_WANT_READ ?
             SPICE_WATCH_EVENT_READ : SPICE_WATCH_EVENT_WRITE;
-        link->peer->watch = core->watch_add(link->peer->socket, eventmask,
+        link->stream->watch = core->watch_add(link->stream->socket, eventmask,
                                             reds_handle_ssl_accept, link);
         return;
     }
 
     ERR_print_errors_fp(stderr);
     red_printf("SSL_accept failed, error=%d", ssl_error);
-    SSL_free(link->peer->ssl);
+    SSL_free(link->stream->ssl);
 
 error:
-    close(link->peer->socket);
-    free(link->peer);
+    close(link->stream->socket);
+    free(link->stream);
     BN_free(link->tiTicketing.bn);
     free(link);
 }
@@ -3166,7 +3167,7 @@ void reds_stream_free(RedsStream *s)
         return;
     }
 
-    reds_channel_event(s, SPICE_CHANNEL_EVENT_DISCONNECTED);
+    reds_stream_channel_event(s, SPICE_CHANNEL_EVENT_DISCONNECTED);
 
     if (s->ssl) {
         SSL_free(s->ssl);
diff --git a/server/reds.h b/server/reds.h
index 34e4082..3c810e0 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -55,7 +55,7 @@ typedef struct Channel {
     uint32_t *common_caps;
     int num_caps;
     uint32_t *caps;
-    void (*link)(struct Channel *, RedsStream *peer, int migration, int num_common_caps,
+    void (*link)(struct Channel *, RedsStream *stream, int migration, int num_common_caps,
                  uint32_t *common_caps, int num_caps, uint32_t *caps);
     void (*shutdown)(struct Channel *);
     void (*migrate)(struct Channel *);
diff --git a/server/smartcard.c b/server/smartcard.c
index 23b3779..d890372 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -469,7 +469,7 @@ static void smartcard_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void smartcard_link(Channel *channel, RedsStream *peer,
+static void smartcard_link(Channel *channel, RedsStream *stream,
                         int migration, int num_common_caps,
                         uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
@@ -479,7 +479,7 @@ static void smartcard_link(Channel *channel, RedsStream *peer,
     }
     g_smartcard_channel =
         (SmartCardChannel *)red_channel_create(sizeof(*g_smartcard_channel),
-                                        peer, core,
+                                        stream, core,
                                         migration, FALSE /* handle_acks */,
                                         smartcard_channel_config_socket,
                                         smartcard_channel_disconnect,
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 80a0f78..f18f7c9 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -73,7 +73,7 @@ typedef void (*cleanup_channel_proc)(SndChannel *channel);
 typedef struct SndWorker SndWorker;
 
 struct SndChannel {
-    RedsStream *peer;
+    RedsStream *stream;
     SndWorker *worker;
     spice_parse_channel_func_t parser;
 
@@ -186,9 +186,9 @@ static void snd_disconnect_channel(SndChannel *channel)
     channel->cleanup(channel);
     worker = channel->worker;
     worker->connection = NULL;
-    core->watch_remove(channel->peer->watch);
-    channel->peer->watch = NULL;
-    reds_stream_free(channel->peer);
+    core->watch_remove(channel->stream->watch);
+    channel->stream->watch = NULL;
+    reds_stream_free(channel->stream);
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
 }
@@ -236,19 +236,19 @@ static int snd_send_data(SndChannel *channel)
 
             if (channel->blocked) {
                 channel->blocked = FALSE;
-                core->watch_update_mask(channel->peer->watch, SPICE_WATCH_EVENT_READ);
+                core->watch_update_mask(channel->stream->watch, SPICE_WATCH_EVENT_READ);
             }
             break;
         }
 
         vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
                                                vec, MAX_SEND_VEC, channel->send_data.pos);
-        n = reds_stream_writev(channel->peer, vec, vec_size);
+        n = reds_stream_writev(channel->stream, vec, vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
                 channel->blocked = TRUE;
-                core->watch_update_mask(channel->peer->watch, SPICE_WATCH_EVENT_READ |
+                core->watch_update_mask(channel->stream->watch, SPICE_WATCH_EVENT_READ |
                                         SPICE_WATCH_EVENT_WRITE);
                 return FALSE;
             case EINTR:
@@ -390,7 +390,7 @@ static void snd_receive(void* data)
         ssize_t n;
         n = channel->recive_data.end - channel->recive_data.now;
         ASSERT(n);
-        n = reds_stream_read(channel->peer, channel->recive_data.now, n);
+        n = reds_stream_read(channel->stream, channel->recive_data.now, n);
         if (n <= 0) {
             if (n == 0) {
                 snd_disconnect_channel(channel);
@@ -736,7 +736,7 @@ static void snd_record_send(void* data)
 }
 
 static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_id,
-                                 RedsStream *peer,
+                                 RedsStream *stream,
                                  int migrate, send_messages_proc send_messages,
                                  handle_message_proc handle_message,
                                  on_message_done_proc on_message_done,
@@ -748,28 +748,28 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
     int priority;
     int tos;
 
-    if ((flags = fcntl(peer->socket, F_GETFL)) == -1) {
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         goto error1;
     }
 
     priority = 6;
-    if (setsockopt(peer->socket, SOL_SOCKET, SO_PRIORITY, (void*)&priority,
+    if (setsockopt(stream->socket, SOL_SOCKET, SO_PRIORITY, (void*)&priority,
                    sizeof(priority)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
 
     tos = IPTOS_LOWDELAY;
-    if (setsockopt(peer->socket, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) == -1) {
+    if (setsockopt(stream->socket, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
 
     delay_val = IS_LOW_BANDWIDTH() ? 0 : 1;
-    if (setsockopt(peer->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
+    if (setsockopt(stream->socket, IPPROTO_TCP, TCP_NODELAY, &delay_val, sizeof(delay_val)) == -1) {
         red_printf("setsockopt failed, %s", strerror(errno));
     }
 
-    if (fcntl(peer->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
+    if (fcntl(stream->socket, F_SETFL, flags | O_NONBLOCK) == -1) {
         red_printf("accept failed, %s", strerror(errno));
         goto error1;
     }
@@ -777,16 +777,16 @@ static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_i
     ASSERT(size >= sizeof(*channel));
     channel = spice_malloc0(size);
     channel->parser = spice_get_client_channel_parser(channel_id, NULL);
-    channel->peer = peer;
+    channel->stream = stream;
     channel->worker = worker;
     channel->recive_data.message = (SpiceDataHeader *)channel->recive_data.buf;
     channel->recive_data.now = channel->recive_data.buf;
     channel->recive_data.end = channel->recive_data.buf + sizeof(channel->recive_data.buf);
     channel->send_data.marshaller = spice_marshaller_new();
 
-    peer->watch = core->watch_add(peer->socket, SPICE_WATCH_EVENT_READ,
+    stream->watch = core->watch_add(stream->socket, SPICE_WATCH_EVENT_READ,
                                   snd_event, channel);
-    if (peer->watch == NULL) {
+    if (stream->watch == NULL) {
         red_printf("watch_add failed, %s", strerror(errno));
         goto error2;
     }
@@ -802,7 +802,7 @@ error2:
     free(channel);
 
 error1:
-    reds_stream_free(peer);
+    reds_stream_free(stream);
     return NULL;
 }
 
@@ -933,7 +933,7 @@ static void snd_playback_cleanup(SndChannel *channel)
     celt051_mode_destroy(playback_channel->celt_mode);
 }
 
-static void snd_set_playback_peer(Channel *channel, RedsStream *peer, int migration,
+static void snd_set_playback_peer(Channel *channel, RedsStream *stream, int migration,
                                   int num_common_caps, uint32_t *common_caps, int num_caps,
                                   uint32_t *caps)
 {
@@ -961,7 +961,7 @@ static void snd_set_playback_peer(Channel *channel, RedsStream *peer, int migrat
     if (!(playback_channel = (PlaybackChannel *)__new_channel(worker,
                                                               sizeof(*playback_channel),
                                                               SPICE_CHANNEL_PLAYBACK,
-                                                              peer,
+                                                              stream,
                                                               migration,
                                                               snd_playback_send,
                                                               snd_playback_handle_message,
@@ -1099,7 +1099,7 @@ static void snd_record_cleanup(SndChannel *channel)
     celt051_mode_destroy(record_channel->celt_mode);
 }
 
-static void snd_set_record_peer(Channel *channel, RedsStream *peer, int migration,
+static void snd_set_record_peer(Channel *channel, RedsStream *stream, int migration,
                                 int num_common_caps, uint32_t *common_caps, int num_caps,
                                 uint32_t *caps)
 {
@@ -1127,7 +1127,7 @@ static void snd_set_record_peer(Channel *channel, RedsStream *peer, int migratio
     if (!(record_channel = (RecordChannel *)__new_channel(worker,
                                                           sizeof(*record_channel),
                                                           SPICE_CHANNEL_RECORD,
-                                                          peer,
+                                                          stream,
                                                           migration,
                                                           snd_record_send,
                                                           snd_record_handle_message,
commit 1a4923c2107c89314714718ca1431d232cc23edf
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Thu Feb 10 03:00:57 2011 +0100

    server/reds: remove the void* ctx field
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index a6a978b..f8d8a0e 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1877,7 +1877,6 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
         return NULL;
     }
     peer = link->peer;
-    peer->ctx = (void *)((unsigned long)link->peer->socket);
     peer->read = stream_read_cb;
     peer->write = stream_write_cb;
     peer->writev = stream_writev_cb;
@@ -1912,7 +1911,6 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
 
     SSL_set_bio(link->peer->ssl, sbio, sbio);
 
-    link->peer->ctx = (void *)(link->peer->ssl);
     link->peer->write = stream_ssl_write_cb;
     link->peer->read = stream_ssl_read_cb;
     link->peer->writev = stream_ssl_writev_cb;
diff --git a/server/reds.h b/server/reds.h
index 63b73c4..34e4082 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -31,8 +31,6 @@
 typedef struct RedsStream RedsStream;
 
 struct RedsStream {
-    void *ctx;
-
     int socket;
     SpiceWatch *watch;
 
commit fc5d7f76257bf51c693dfb888c1a3dd61d8d2318
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 13:14:00 2011 +0100

    server: use the new reds_stream_{read,write}
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/red_channel.c b/server/red_channel.c
index 10bc054..3676b5a 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -41,7 +41,8 @@ static int red_peer_receive(RedsStream *peer, uint8_t *buf, uint32_t size)
         if (peer->shutdown) {
             return -1;
         }
-        if ((now = peer->cb_read(peer->ctx, pos, size)) <= 0) {
+        now = reds_stream_read(peer, pos, size);
+        if (now <= 0) {
             if (now == 0) {
                 return -1;
             }
@@ -154,7 +155,8 @@ void red_channel_receive(RedChannel *channel)
 
 static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
 {
-    int n;
+    ssize_t n;
+
     if (handler->size == 0) {
         handler->vec = handler->vec_buf;
         handler->size = handler->get_msg_size(handler->opaque);
@@ -162,9 +164,11 @@ static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
             return;
         }
     }
+
     for (;;) {
         handler->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
-        if ((n = peer->cb_writev(peer->ctx, handler->vec, handler->vec_size)) == -1) {
+        n = reds_stream_writev(peer, handler->vec, handler->vec_size);
+        if (n == -1) {
             switch (errno) {
             case EAGAIN:
                 handler->on_block(handler->opaque);
diff --git a/server/red_worker.c b/server/red_worker.c
index fc21bce..3332f10 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7339,9 +7339,9 @@ static void inline channel_release_res(RedChannel *channel)
 static void red_send_data(RedChannel *channel)
 {
     for (;;) {
-        uint32_t n = channel->send_data.size - channel->send_data.pos;
+        ssize_t n = channel->send_data.size - channel->send_data.pos;
         struct iovec vec[MAX_SEND_VEC];
-        int vec_size;
+        size_t vec_size;
 
         if (!n) {
             channel->send_data.blocked = FALSE;
@@ -7354,7 +7354,8 @@ static void red_send_data(RedChannel *channel)
         vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
                                                vec, MAX_SEND_VEC, channel->send_data.pos);
         ASSERT(channel->peer);
-        if ((n = channel->peer->cb_writev(channel->peer->ctx, vec, vec_size)) == -1) {
+        n = reds_stream_writev(channel->peer, vec, vec_size);
+        if (n == -1) {
             switch (errno) {
             case EAGAIN:
                 channel->send_data.blocked = TRUE;
@@ -9277,7 +9278,8 @@ static void red_receive(RedChannel *channel)
         n = channel->recive_data.end - channel->recive_data.now;
         ASSERT(n);
         ASSERT(channel->peer);
-        if ((n = channel->peer->cb_read(channel->peer->ctx, channel->recive_data.now, n)) <= 0) {
+        n = reds_stream_read(channel->peer, channel->recive_data.now, n);
+        if (n <= 0) {
             if (n == 0) {
                 channel->disconnect(channel);
                 return;
diff --git a/server/reds.c b/server/reds.c
index 733e79d..a6a978b 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -304,73 +304,60 @@ static void reds_channel_event(RedsStream *peer, int event)
     core->channel_event(event, &peer->info);
 }
 
-static int reds_write(void *ctx, void *buf, size_t size)
+static ssize_t stream_write_cb(RedsStream *s, const void *buf, size_t size)
 {
-    int return_code;
-    int sock = (long)ctx;
-    size_t count = size;
-
-    return_code = write(sock, buf, count);
-
-    return (return_code);
+    return write(s->socket, buf, size);
 }
 
-static int reds_read(void *ctx, void *buf, size_t size)
+static ssize_t stream_writev_cb(RedsStream *s, const struct iovec *iov, int iovcnt)
 {
-    int return_code;
-    int sock = (long)ctx;
-    size_t count = size;
-
-    return_code = read(sock, buf, count);
+    return writev(s->socket, iov, iovcnt);
+}
 
-    return (return_code);
+static ssize_t stream_read_cb(RedsStream *s, void *buf, size_t size)
+{
+    return read(s->socket, buf, size);
 }
 
-static int reds_ssl_write(void *ctx, void *buf, size_t size)
+static ssize_t stream_ssl_write_cb(RedsStream *s, const void *buf, size_t size)
 {
     int return_code;
-    int ssl_error;
-    SSL *ssl = ctx;
+    SPICE_GNUC_UNUSED int ssl_error;
 
-    return_code = SSL_write(ssl, buf, size);
+    return_code = SSL_write(s->ssl, buf, size);
 
     if (return_code < 0) {
-        ssl_error = SSL_get_error(ssl, return_code);
-        (void)ssl_error;
+        ssl_error = SSL_get_error(s->ssl, return_code);
     }
 
-    return (return_code);
+    return return_code;
 }
 
-static int reds_ssl_read(void *ctx, void *buf, size_t size)
+static ssize_t stream_ssl_read_cb(RedsStream *s, void *buf, size_t size)
 {
     int return_code;
-    int ssl_error;
-    SSL *ssl = ctx;
+    SPICE_GNUC_UNUSED int ssl_error;
 
-    return_code = SSL_read(ssl, buf, size);
+    return_code = SSL_read(s->ssl, buf, size);
 
     if (return_code < 0) {
-        ssl_error = SSL_get_error(ssl, return_code);
-        (void)ssl_error;
+        ssl_error = SSL_get_error(s->ssl, return_code);
     }
 
-    return (return_code);
+    return return_code;
 }
 
-static int reds_ssl_writev(void *ctx, const struct iovec *vector, int count)
+static ssize_t stream_ssl_writev_cb(RedsStream *s, const struct iovec *vector, int count)
 {
     int i;
     int n;
-    int return_code = 0;
+    ssize_t return_code = 0;
     int ssl_error;
-    SSL *ssl = ctx;
 
     for (i = 0; i < count; ++i) {
-        n = SSL_write(ssl, vector[i].iov_base, vector[i].iov_len);
+        n = SSL_write(s->ssl, vector[i].iov_base, vector[i].iov_len);
         if (n <= 0) {
-            ssl_error = SSL_get_error(ssl, n);
-            (void)ssl_error;
+            ssl_error = SSL_get_error(s->ssl, n);
             if (return_code <= 0) {
                 return n;
             } else {
@@ -1362,7 +1349,7 @@ static int sync_write(RedsStream *peer, void *in_buf, size_t n)
 {
     uint8_t *buf = (uint8_t *)in_buf;
     while (n) {
-        int now = peer->cb_write(peer->ctx, buf, n);
+        int now = reds_stream_write(peer, buf, n);
         if (now <= 0) {
             if (now == -1 && (errno == EINTR || errno == EAGAIN)) {
                 continue;
@@ -1664,7 +1651,8 @@ static void async_read_handler(int fd, int event, void *data)
         int n = obj->end - obj->now;
 
         ASSERT(n > 0);
-        if ((n = obj->peer->cb_read(obj->peer->ctx, obj->now, n)) <= 0) {
+        n = reds_stream_read(obj->peer, obj->now, n);
+        if (n <= 0) {
             if (n < 0) {
                 switch (errno) {
                 case EAGAIN:
@@ -1890,9 +1878,9 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
     }
     peer = link->peer;
     peer->ctx = (void *)((unsigned long)link->peer->socket);
-    peer->cb_read = (int (*)(void *, void *, int))reds_read;
-    peer->cb_write = (int (*)(void *, void *, int))reds_write;
-    peer->cb_writev = (int (*)(void *, const struct iovec *vector, int count))writev;
+    peer->read = stream_read_cb;
+    peer->write = stream_write_cb;
+    peer->writev = stream_writev_cb;
 
     return link;
 }
@@ -1925,9 +1913,9 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
     SSL_set_bio(link->peer->ssl, sbio, sbio);
 
     link->peer->ctx = (void *)(link->peer->ssl);
-    link->peer->cb_write = (int (*)(void *, void *, int))reds_ssl_write;
-    link->peer->cb_read = (int (*)(void *, void *, int))reds_ssl_read;
-    link->peer->cb_writev = reds_ssl_writev;
+    link->peer->write = stream_ssl_write_cb;
+    link->peer->read = stream_ssl_read_cb;
+    link->peer->writev = stream_ssl_writev_cb;
 
     return_code = SSL_accept(link->peer->ssl);
     if (return_code == 1) {
diff --git a/server/reds.h b/server/reds.h
index 0817253..63b73c4 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -43,11 +43,6 @@ struct RedsStream {
 
     SpiceChannelEventInfo info;
 
-    int (*cb_write)(void *, void *, int);
-    int (*cb_read)(void *, void *, int);
-
-    int (*cb_writev)(void *, const struct iovec *vector, int count);
-
     /* private */
     ssize_t (*read)(RedsStream *s, void *buf, size_t nbyte);
     ssize_t (*write)(RedsStream *s, const void *buf, size_t nbyte);
diff --git a/server/snd_worker.c b/server/snd_worker.c
index fcfaf97..80a0f78 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -243,7 +243,8 @@ static int snd_send_data(SndChannel *channel)
 
         vec_size = spice_marshaller_fill_iovec(channel->send_data.marshaller,
                                                vec, MAX_SEND_VEC, channel->send_data.pos);
-        if ((n = channel->peer->cb_writev(channel->peer->ctx, vec, vec_size)) == -1) {
+        n = reds_stream_writev(channel->peer, vec, vec_size);
+        if (n == -1) {
             switch (errno) {
             case EAGAIN:
                 channel->blocked = TRUE;
@@ -389,7 +390,8 @@ static void snd_receive(void* data)
         ssize_t n;
         n = channel->recive_data.end - channel->recive_data.now;
         ASSERT(n);
-        if ((n = channel->peer->cb_read(channel->peer->ctx, channel->recive_data.now, n)) <= 0) {
+        n = reds_stream_read(channel->peer, channel->recive_data.now, n);
+        if (n <= 0) {
             if (n == 0) {
                 snd_disconnect_channel(channel);
                 return;
commit f32503258fa1f0a88de410005609770bd23cac97
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 13:40:52 2011 +0100

    server: remove cb_free, not needed anymore
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index c5290c4..733e79d 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -326,14 +326,6 @@ static int reds_read(void *ctx, void *buf, size_t size)
     return (return_code);
 }
 
-static int reds_free(RedsStream *peer)
-{
-    reds_channel_event(peer, SPICE_CHANNEL_EVENT_DISCONNECTED);
-    close(peer->socket);
-    free(peer);
-    return 0;
-}
-
 static int reds_ssl_write(void *ctx, void *buf, size_t size)
 {
     int return_code;
@@ -392,15 +384,6 @@ static int reds_ssl_writev(void *ctx, const struct iovec *vector, int count)
     return return_code;
 }
 
-static int reds_ssl_free(RedsStream* peer)
-{
-    reds_channel_event(peer, SPICE_CHANNEL_EVENT_DISCONNECTED);
-    SSL_free(peer->ssl);
-    close(peer->socket);
-    free(peer);
-    return 0;
-}
-
 static void reds_stream_remove_watch(RedsStream* s)
 {
     if (s->watch) {
@@ -1910,7 +1893,6 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
     peer->cb_read = (int (*)(void *, void *, int))reds_read;
     peer->cb_write = (int (*)(void *, void *, int))reds_write;
     peer->cb_writev = (int (*)(void *, const struct iovec *vector, int count))writev;
-    peer->cb_free = (int (*)(RedsStream *))reds_free;
 
     return link;
 }
@@ -1946,7 +1928,6 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
     link->peer->cb_write = (int (*)(void *, void *, int))reds_ssl_write;
     link->peer->cb_read = (int (*)(void *, void *, int))reds_ssl_read;
     link->peer->cb_writev = reds_ssl_writev;
-    link->peer->cb_free = (int (*)(RedsStream *))reds_ssl_free;
 
     return_code = SSL_accept(link->peer->ssl);
     if (return_code == 1) {
diff --git a/server/reds.h b/server/reds.h
index 235e532..0817253 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -47,7 +47,6 @@ struct RedsStream {
     int (*cb_read)(void *, void *, int);
 
     int (*cb_writev)(void *, const struct iovec *vector, int count);
-    int (*cb_free)(struct RedsStream *);
 
     /* private */
     ssize_t (*read)(RedsStream *s, void *buf, size_t nbyte);
commit 07d6dd61080efdfe97fbce7a9a12abb7f315bdc3
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 13:33:28 2011 +0100

    server: use reds_{link,stream}_free()
    
    Be carefull removing the watch before, like __release_link
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/red_channel.c b/server/red_channel.c
index 5fcbda4..10bc054 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -371,8 +371,7 @@ void red_channel_destroy(RedChannel *channel)
         return;
     }
     red_channel_pipe_clear(channel);
-    channel->core->watch_remove(channel->peer->watch);
-    channel->peer->cb_free(channel->peer);
+    reds_stream_free(channel->peer);
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
 }
diff --git a/server/reds.c b/server/reds.c
index 39f47ed..c5290c4 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -428,28 +428,6 @@ static void reds_link_free(RedLinkInfo *link)
     free(link);
 }
 
-static void __reds_release_link(RedLinkInfo *link)
-{
-    ASSERT(link->peer);
-    if (link->peer->watch) {
-        core->watch_remove(link->peer->watch);
-        link->peer->watch = NULL;
-    }
-    free(link->link_mess);
-    BN_free(link->tiTicketing.bn);
-    if (link->tiTicketing.rsa) {
-        RSA_free(link->tiTicketing.rsa);
-    }
-    free(link);
-}
-
-static inline void reds_release_link(RedLinkInfo *link)
-{
-    RedsStream *peer = link->peer;
-    __reds_release_link(link);
-    peer->cb_free(peer);
-}
-
 #ifdef RED_STATISTICS
 
 void insert_stat_node(StatNodeRef parent, StatNodeRef ref)
@@ -1527,7 +1505,7 @@ static void reds_handle_main_link(RedLinkInfo *link)
     } else {
         if (link_mess->connection_id != reds->link_id) {
             reds_send_link_result(link, SPICE_LINK_ERR_BAD_CONNECTION_ID);
-            reds_release_link(link);
+            reds_link_free(link);
             return;
         }
         reds_send_link_result(link, SPICE_LINK_ERR_OK);
@@ -1542,8 +1520,10 @@ static void reds_handle_main_link(RedLinkInfo *link)
 
     reds_show_new_channel(link, connection_id);
     peer = link->peer;
+    reds_stream_remove_watch(peer);
+    link->peer = NULL;
     link->link_mess = NULL;
-    __reds_release_link(link);
+    reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
     reds->main_channel = main_channel_init();
     reds->main_channel->link(reds->main_channel, peer, reds->mig_target, link_mess->num_common_caps,
@@ -1618,14 +1598,14 @@ static void reds_handle_other_links(RedLinkInfo *link)
 
     if (!reds->link_id || reds->link_id != link_mess->connection_id) {
         reds_send_link_result(link, SPICE_LINK_ERR_BAD_CONNECTION_ID);
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
     if (!(channel = reds_find_channel(link_mess->channel_type,
                                       link_mess->channel_id))) {
         reds_send_link_result(link, SPICE_LINK_ERR_CHANNEL_NOT_AVAILABLE);
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1637,8 +1617,10 @@ static void reds_handle_other_links(RedLinkInfo *link)
         main_channel_push_notify(reds->main_channel, (uint8_t*)mess, mess_len);
     }
     peer = link->peer;
+    reds_stream_remove_watch(peer);
+    link->peer = NULL;
     link->link_mess = NULL;
-    __reds_release_link(link);
+    reds_link_free(link);
     caps = (uint32_t *)((uint8_t *)link_mess + link_mess->caps_offset);
     channel->link(channel, peer, reds->mig_target, link_mess->num_common_caps,
                   link_mess->num_common_caps ? caps : NULL, link_mess->num_channel_caps,
@@ -1666,13 +1648,13 @@ static void reds_handle_ticket(void *opaque)
             reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED);
             red_printf("Ticketing is enabled, but no password is set. "
                        "please set a ticket first");
-            reds_release_link(link);
+            reds_link_free(link);
             return;
         }
 
         if (expired || strncmp(password, actual_sever_pass, SPICE_MAX_PASSWORD_LENGTH) != 0) {
             reds_send_link_result(link, SPICE_LINK_ERR_PERMISSION_DENIED);
-            reds_release_link(link);
+            reds_link_free(link);
             return;
         }
     }
@@ -1751,7 +1733,7 @@ static void reds_handle_read_link_done(void *opaque)
                                                    link->link_header.size ||
                                                      link_mess->caps_offset < sizeof(*link_mess))) {
         reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1763,12 +1745,12 @@ static void reds_handle_read_link_done(void *opaque)
             red_printf("spice channels %d should be encrypted", link_mess->channel_type);
             reds_send_link_error(link, SPICE_LINK_ERR_NEED_SECURED);
         }
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
     if (!reds_send_link_ack(link)) {
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1789,7 +1771,7 @@ static void reds_handle_link_error(void *opaque, int err)
         red_printf("%s", strerror(errno));
         break;
     }
-    reds_release_link(link);
+    reds_link_free(link);
 }
 
 static void reds_handle_read_header_done(void *opaque)
@@ -1800,7 +1782,7 @@ static void reds_handle_read_header_done(void *opaque)
 
     if (header->magic != SPICE_MAGIC) {
         reds_send_link_error(link, SPICE_LINK_ERR_INVALID_MAGIC);
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1810,7 +1792,7 @@ static void reds_handle_read_header_done(void *opaque)
         }
 
         red_printf("version mismatch");
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1819,7 +1801,7 @@ static void reds_handle_read_header_done(void *opaque)
     if (header->size < sizeof(SpiceLinkMess)) {
         reds_send_link_error(link, SPICE_LINK_ERR_INVALID_DATA);
         red_printf("bad size %u", header->size);
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -1852,7 +1834,7 @@ static void reds_handle_ssl_accept(int fd, int event, void *data)
         int ssl_error = SSL_get_error(link->peer->ssl, return_code);
         if (ssl_error != SSL_ERROR_WANT_READ && ssl_error != SSL_ERROR_WANT_WRITE) {
             red_printf("SSL_accept failed, error=%d", ssl_error);
-            reds_release_link(link);
+            reds_link_free(link);
         } else {
             if (ssl_error == SSL_ERROR_WANT_READ) {
                 core->watch_update_mask(link->peer->watch, SPICE_WATCH_EVENT_READ);
commit fca602124ded4b3333344a8737a08751635bacdb
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 13:31:31 2011 +0100

    server: use reds_stream_remove_watch() helper
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index 999fa07..39f47ed 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1688,8 +1688,7 @@ static inline void async_read_clear_handlers(AsyncRead *obj)
     if (!obj->peer->watch) {
         return;
     }
-    core->watch_remove(obj->peer->watch);
-    obj->peer->watch = NULL;
+    reds_stream_remove_watch(obj->peer);
 }
 
 static void async_read_handler(int fd, int event, void *data)
@@ -1863,8 +1862,7 @@ static void reds_handle_ssl_accept(int fd, int event, void *data)
         }
         return;
     }
-    core->watch_remove(link->peer->watch);
-    link->peer->watch = NULL;
+    reds_stream_remove_watch(link->peer);
     reds_handle_new_link(link);
 }
 
commit b79e7320de6b2cd07000b9713ec77f3439eaf80d
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 09:46:14 2011 +0100

    server: add reds_stream_{read,write,free,remove_watch}()
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/red_channel.c b/server/red_channel.c
index 788960f..5fcbda4 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -320,7 +320,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
 error:
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
-    peer->cb_free(peer);
+    reds_stream_free(peer);
 
     return NULL;
 }
diff --git a/server/red_worker.c b/server/red_worker.c
index 96d5c94..fc21bce 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8548,9 +8548,7 @@ static void red_disconnect_channel(RedChannel *channel)
 {
     channel_release_res(channel);
     red_pipe_clear(channel);
-
-    channel->peer->cb_free(channel->peer);
-
+    reds_stream_free(channel->peer);
     channel->peer = NULL;
     channel->send_data.blocked = FALSE;
     channel->send_data.size = channel->send_data.pos = 0;
@@ -9420,7 +9418,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
 error2:
     free(channel);
 error1:
-    peer->cb_free(peer);
+    reds_stream_free(peer);
 
     return NULL;
 }
diff --git a/server/reds.c b/server/reds.c
index 2edf3e8..999fa07 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -392,7 +392,7 @@ static int reds_ssl_writev(void *ctx, const struct iovec *vector, int count)
     return return_code;
 }
 
-static int reds_ssl_free(RedsStream *peer)
+static int reds_ssl_free(RedsStream* peer)
 {
     reds_channel_event(peer, SPICE_CHANNEL_EVENT_DISCONNECTED);
     SSL_free(peer->ssl);
@@ -401,6 +401,33 @@ static int reds_ssl_free(RedsStream *peer)
     return 0;
 }
 
+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->peer);
+    link->peer = NULL;
+
+    free(link->link_mess);
+    link->link_mess = NULL;
+
+    BN_free(link->tiTicketing.bn);
+    link->tiTicketing.bn = NULL;
+
+    if (link->tiTicketing.rsa) {
+        RSA_free(link->tiTicketing.rsa);
+        link->tiTicketing.rsa = NULL;
+    }
+
+    free(link);
+}
+
 static void __reds_release_link(RedLinkInfo *link)
 {
     ASSERT(link->peer);
@@ -3170,3 +3197,36 @@ __visible__ int spice_server_migrate_switch(SpiceServer *s)
     reds_mig_switch();
     return 0;
 }
+
+ssize_t reds_stream_read(RedsStream *s, void *buf, size_t nbyte)
+{
+    return s->read(s, buf, nbyte);
+}
+
+ssize_t reds_stream_write(RedsStream *s, const void *buf, size_t nbyte)
+{
+    return s->write(s, buf, nbyte);
+}
+
+ssize_t reds_stream_writev(RedsStream *s, const struct iovec *iov, int iovcnt)
+{
+    return s->writev(s, iov, iovcnt);
+}
+
+void reds_stream_free(RedsStream *s)
+{
+    if (!s) {
+        return;
+    }
+
+    reds_channel_event(s, SPICE_CHANNEL_EVENT_DISCONNECTED);
+
+    if (s->ssl) {
+        SSL_free(s->ssl);
+    }
+
+    reds_stream_remove_watch(s);
+    close(s->socket);
+
+    free(s);
+}
diff --git a/server/reds.h b/server/reds.h
index b974eda..235e532 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -28,7 +28,9 @@
 
 #define __visible__ __attribute__ ((visibility ("default")))
 
-typedef struct RedsStream {
+typedef struct RedsStream RedsStream;
+
+struct RedsStream {
     void *ctx;
 
     int socket;
@@ -46,7 +48,12 @@ typedef struct RedsStream {
 
     int (*cb_writev)(void *, const struct iovec *vector, int count);
     int (*cb_free)(struct RedsStream *);
-} RedsStream;
+
+    /* 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 struct Channel {
     struct Channel *next;
@@ -73,6 +80,11 @@ struct SpiceNetWireState {
     struct TunnelWorker *worker;
 };
 
+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_desable_mm_timer();
 void reds_enable_mm_timer();
 void reds_update_mm_timer(uint32_t mm_time);
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 2cd4d92..fcfaf97 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -188,7 +188,7 @@ static void snd_disconnect_channel(SndChannel *channel)
     worker->connection = NULL;
     core->watch_remove(channel->peer->watch);
     channel->peer->watch = NULL;
-    channel->peer->cb_free(channel->peer);
+    reds_stream_free(channel->peer);
     spice_marshaller_destroy(channel->send_data.marshaller);
     free(channel);
 }
@@ -800,7 +800,7 @@ error2:
     free(channel);
 
 error1:
-    peer->cb_free(peer);
+    reds_stream_free(peer);
     return NULL;
 }
 
commit d47912241f4bc263cf3c19c07ed3907681826277
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Sun Feb 27 09:38:04 2011 +0100

    server: s/RedsStreamContext/RedsStream
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/inputs_channel.c b/server/inputs_channel.c
index c930d4d..ebf915c 100644
--- a/server/inputs_channel.c
+++ b/server/inputs_channel.c
@@ -512,7 +512,7 @@ static void inputs_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void inputs_link(Channel *channel, RedsStreamContext *peer, int migration,
+static void inputs_link(Channel *channel, RedsStream *peer, int migration,
                         int num_common_caps, uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
 {
diff --git a/server/main_channel.c b/server/main_channel.c
index 67ac72f..f43f89a 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -780,7 +780,7 @@ static void main_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void main_channel_link(Channel *channel, RedsStreamContext *peer, int migration,
+static void main_channel_link(Channel *channel, RedsStream *peer, int migration,
                         int num_common_caps, uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
 {
diff --git a/server/red_channel.c b/server/red_channel.c
index 6008876..788960f 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -33,7 +33,7 @@ static PipeItem *red_channel_pipe_get(RedChannel *channel);
 static void red_channel_event(int fd, int event, void *data);
 
 /* return the number of bytes read. -1 in case of error */
-static int red_peer_receive(RedsStreamContext *peer, uint8_t *buf, uint32_t size)
+static int red_peer_receive(RedsStream *peer, uint8_t *buf, uint32_t size)
 {
     uint8_t *pos = buf;
     while (size) {
@@ -68,7 +68,7 @@ static int red_peer_receive(RedsStreamContext *peer, uint8_t *buf, uint32_t size
 // does many calls to red_peer_receive and through it cb_read, and thus avoids pointer
 // arithmetic for the case where a single cb_read could return multiple messages. But
 // this is suboptimal potentially. Profile and consider fixing.
-static void red_peer_handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
+static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
 {
     int bytes_read;
     uint8_t *parsed;
@@ -152,7 +152,7 @@ void red_channel_receive(RedChannel *channel)
     red_peer_handle_incoming(channel->peer, &channel->incoming);
 }
 
-static void red_peer_handle_outgoing(RedsStreamContext *peer, OutgoingHandler *handler)
+static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
 {
     int n;
     if (handler->size == 0) {
@@ -252,7 +252,7 @@ static void red_channel_peer_on_out_msg_done(void *opaque)
     }
 }
 
-RedChannel *red_channel_create(int size, RedsStreamContext *peer,
+RedChannel *red_channel_create(int size, RedsStream *peer,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -334,7 +334,7 @@ int do_nothing_handle_message(RedChannel *red_channel, SpiceDataHeader *header,
     return TRUE;
 }
 
-RedChannel *red_channel_create_parser(int size, RedsStreamContext *peer,
+RedChannel *red_channel_create_parser(int size, RedsStream *peer,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
diff --git a/server/red_channel.h b/server/red_channel.h
index 2ee6566..fd9ce37 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -114,7 +114,7 @@ typedef void (*channel_on_incoming_error_proc)(RedChannel *channel);
 typedef void (*channel_on_outgoing_error_proc)(RedChannel *channel);
 
 struct RedChannel {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SpiceCoreInterface *core;
     int migrate;
     int handle_acks;
@@ -160,7 +160,7 @@ struct RedChannel {
 
 /* if one of the callbacks should cause disconnect, use red_channel_shutdown and don't
    explicitly destroy the channel */
-RedChannel *red_channel_create(int size, RedsStreamContext *peer,
+RedChannel *red_channel_create(int size, RedsStream *peer,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
@@ -174,7 +174,7 @@ RedChannel *red_channel_create(int size, RedsStreamContext *peer,
 
 /* alternative constructor, meant for marshaller based (inputs,main) channels,
  * will become default eventually */
-RedChannel *red_channel_create_parser(int size, RedsStreamContext *peer,
+RedChannel *red_channel_create_parser(int size, RedsStream *peer,
                                SpiceCoreInterface *core,
                                int migrate, int handle_acks,
                                channel_configure_socket_proc config_socket,
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 2a3c297..3816e14 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -71,7 +71,7 @@ extern spice_wan_compression_t zlib_glz_state;
 
 static RedDispatcher *dispatchers = NULL;
 
-static void red_dispatcher_set_peer(Channel *channel, RedsStreamContext *peer, int migration,
+static void red_dispatcher_set_peer(Channel *channel, RedsStream *peer, int migration,
                                     int num_common_caps, uint32_t *common_caps, int num_caps,
                                     uint32_t *caps)
 {
@@ -81,7 +81,7 @@ static void red_dispatcher_set_peer(Channel *channel, RedsStreamContext *peer, i
     dispatcher = (RedDispatcher *)channel->data;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DISPLAY_CONNECT;
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &peer, sizeof(RedsStreamContext *));
+    send_data(dispatcher->channel, &peer, sizeof(RedsStream *));
     send_data(dispatcher->channel, &migration, sizeof(int));
 }
 
@@ -101,7 +101,7 @@ static void red_dispatcher_migrate(Channel *channel)
     write_message(dispatcher->channel, &message);
 }
 
-static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStreamContext *peer,
+static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStream *peer,
                                            int migration, int num_common_caps,
                                            uint32_t *common_caps, int num_caps,
                                            uint32_t *caps)
@@ -110,7 +110,7 @@ static void red_dispatcher_set_cursor_peer(Channel *channel, RedsStreamContext *
     red_printf("");
     RedWorkerMessage message = RED_WORKER_MESSAGE_CURSOR_CONNECT;
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &peer, sizeof(RedsStreamContext *));
+    send_data(dispatcher->channel, &peer, sizeof(RedsStream *));
     send_data(dispatcher->channel, &migration, sizeof(int));
 }
 
diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index f60894b..6ea58f0 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -598,7 +598,7 @@ static void arm_timer(SlirpUsrNetworkInterface *usr_interface, UserTimer *timer,
 
 
 /* reds interface */
-static void handle_tunnel_channel_link(Channel *channel, RedsStreamContext *peer, int migration,
+static void handle_tunnel_channel_link(Channel *channel, RedsStream *peer, int migration,
                                        int num_common_caps, uint32_t *common_caps, int num_caps,
                                        uint32_t *caps);
 static void handle_tunnel_channel_shutdown(struct Channel *channel);
@@ -3424,7 +3424,7 @@ static void tunnel_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void handle_tunnel_channel_link(Channel *channel, RedsStreamContext *peer, int migration,
+static void handle_tunnel_channel_link(Channel *channel, RedsStream *peer, int migration,
                                        int num_common_caps, uint32_t *common_caps, int num_caps,
                                        uint32_t *caps)
 {
diff --git a/server/red_worker.c b/server/red_worker.c
index d75856e..96d5c94 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -355,7 +355,7 @@ typedef int (*channel_handle_parsed_proc)(RedChannel *channel, uint32_t size, ui
 
 struct RedChannel {
     spice_parse_channel_func_t parser;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     int migrate;
 
     Ring pipe;
@@ -9352,7 +9352,7 @@ static void free_common_channel_from_listener(EventListener *ctx)
 }
 
 static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_id,
-                                 RedsStreamContext *peer, int migrate,
+                                 RedsStream *peer, int migrate,
                                  event_listener_action_proc handler,
                                  channel_disconnect_proc disconnect,
                                  channel_hold_pipe_item_proc hold_item,
@@ -9485,7 +9485,7 @@ static void display_channel_release_item(RedChannel *channel, PipeItem *item, in
     }
 }
 
-static void handle_new_display_channel(RedWorker *worker, RedsStreamContext *peer, int migrate)
+static void handle_new_display_channel(RedWorker *worker, RedsStream *peer, int migrate)
 {
     DisplayChannel *display_channel;
     size_t stream_buf_size;
@@ -9612,7 +9612,7 @@ static void cursor_channel_release_item(RedChannel *channel, PipeItem *item, int
     red_release_cursor(common->worker, SPICE_CONTAINEROF(item, CursorItem, pipe_data));
 }
 
-static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int migrate)
+static void red_connect_cursor(RedWorker *worker, RedsStream *peer, int migrate)
 {
     CursorChannel *channel;
 
@@ -10053,11 +10053,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         handle_dev_destroy_primary_surface(worker);
         break;
     case RED_WORKER_MESSAGE_DISPLAY_CONNECT: {
-        RedsStreamContext *peer;
+        RedsStream *peer;
         int migrate;
         red_printf("connect");
 
-        receive_data(worker->channel, &peer, sizeof(RedsStreamContext *));
+        receive_data(worker->channel, &peer, sizeof(RedsStream *));
         receive_data(worker->channel, &migrate, sizeof(int));
         handle_new_display_channel(worker, peer, migrate);
         break;
@@ -10101,11 +10101,11 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_migrate_display(worker);
         break;
     case RED_WORKER_MESSAGE_CURSOR_CONNECT: {
-        RedsStreamContext *peer;
+        RedsStream *peer;
         int migrate;
 
         red_printf("cursor connect");
-        receive_data(worker->channel, &peer, sizeof(RedsStreamContext *));
+        receive_data(worker->channel, &peer, sizeof(RedsStream *));
         receive_data(worker->channel, &migrate, sizeof(int));
         red_connect_cursor(worker, peer, migrate);
         break;
diff --git a/server/reds.c b/server/reds.c
index 573a838..2edf3e8 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -224,7 +224,7 @@ typedef struct RedsState {
 static RedsState *reds = NULL;
 
 typedef struct AsyncRead {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     void *opaque;
     uint8_t *now;
     uint8_t *end;
@@ -233,7 +233,7 @@ typedef struct AsyncRead {
 } AsyncRead;
 
 typedef struct RedLinkInfo {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     AsyncRead asyc_read;
     SpiceLinkHeader link_header;
     SpiceLinkMess *link_mess;
@@ -297,7 +297,7 @@ static ChannelSecurityOptions *find_channel_security(int id)
     return now;
 }
 
-static void reds_channel_event(RedsStreamContext *peer, int event)
+static void reds_channel_event(RedsStream *peer, int event)
 {
     if (core->base.minor_version < 3 || core->channel_event == NULL)
         return;
@@ -326,7 +326,7 @@ static int reds_read(void *ctx, void *buf, size_t size)
     return (return_code);
 }
 
-static int reds_free(RedsStreamContext *peer)
+static int reds_free(RedsStream *peer)
 {
     reds_channel_event(peer, SPICE_CHANNEL_EVENT_DISCONNECTED);
     close(peer->socket);
@@ -392,7 +392,7 @@ static int reds_ssl_writev(void *ctx, const struct iovec *vector, int count)
     return return_code;
 }
 
-static int reds_ssl_free(RedsStreamContext *peer)
+static int reds_ssl_free(RedsStream *peer)
 {
     reds_channel_event(peer, SPICE_CHANNEL_EVENT_DISCONNECTED);
     SSL_free(peer->ssl);
@@ -418,7 +418,7 @@ static void __reds_release_link(RedLinkInfo *link)
 
 static inline void reds_release_link(RedLinkInfo *link)
 {
-    RedsStreamContext *peer = link->peer;
+    RedsStream *peer = link->peer;
     __reds_release_link(link);
     peer->cb_free(peer);
 }
@@ -1370,7 +1370,7 @@ void reds_on_main_receive_migrate_data(MainMigrateData *data, uint8_t *end)
     while (write_to_vdi_port() || read_from_vdi_port());
 }
 
-static int sync_write(RedsStreamContext *peer, void *in_buf, size_t n)
+static int sync_write(RedsStream *peer, void *in_buf, size_t n)
 {
     uint8_t *buf = (uint8_t *)in_buf;
     while (n) {
@@ -1482,7 +1482,7 @@ static void reds_send_link_result(RedLinkInfo *link, uint32_t error)
 // actually be joined with reds_handle_other_links, ebcome reds_handle_link
 static void reds_handle_main_link(RedLinkInfo *link)
 {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
     uint32_t connection_id;
@@ -1583,7 +1583,7 @@ static void openssl_init(RedLinkInfo *link)
 static void reds_handle_other_links(RedLinkInfo *link)
 {
     Channel *channel;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
 
@@ -1844,7 +1844,7 @@ static void reds_handle_ssl_accept(int fd, int event, void *data)
 static RedLinkInfo *__reds_accept_connection(int listen_socket)
 {
     RedLinkInfo *link;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     int delay_val = 1;
     int flags;
     int socket;
@@ -1869,7 +1869,7 @@ static RedLinkInfo *__reds_accept_connection(int listen_socket)
     }
 
     link = spice_new0(RedLinkInfo, 1);
-    peer = spice_new0(RedsStreamContext, 1);
+    peer = spice_new0(RedsStream, 1);
     link->peer = peer;
     peer->socket = socket;
 
@@ -1893,7 +1893,7 @@ error:
 static RedLinkInfo *reds_accept_connection(int listen_socket)
 {
     RedLinkInfo *link;
-    RedsStreamContext *peer;
+    RedsStream *peer;
 
     if (!(link = __reds_accept_connection(listen_socket))) {
         return NULL;
@@ -1903,7 +1903,7 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
     peer->cb_read = (int (*)(void *, void *, int))reds_read;
     peer->cb_write = (int (*)(void *, void *, int))reds_write;
     peer->cb_writev = (int (*)(void *, const struct iovec *vector, int count))writev;
-    peer->cb_free = (int (*)(RedsStreamContext *))reds_free;
+    peer->cb_free = (int (*)(RedsStream *))reds_free;
 
     return link;
 }
@@ -1939,7 +1939,7 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
     link->peer->cb_write = (int (*)(void *, void *, int))reds_ssl_write;
     link->peer->cb_read = (int (*)(void *, void *, int))reds_ssl_read;
     link->peer->cb_writev = reds_ssl_writev;
-    link->peer->cb_free = (int (*)(RedsStreamContext *))reds_ssl_free;
+    link->peer->cb_free = (int (*)(RedsStream *))reds_ssl_free;
 
     return_code = SSL_accept(link->peer->ssl);
     if (return_code == 1) {
diff --git a/server/reds.h b/server/reds.h
index 547c33c..b974eda 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -28,7 +28,7 @@
 
 #define __visible__ __attribute__ ((visibility ("default")))
 
-typedef struct RedsStreamContext {
+typedef struct RedsStream {
     void *ctx;
 
     int socket;
@@ -45,8 +45,8 @@ typedef struct RedsStreamContext {
     int (*cb_read)(void *, void *, int);
 
     int (*cb_writev)(void *, const struct iovec *vector, int count);
-    int (*cb_free)(struct RedsStreamContext *);
-} RedsStreamContext;
+    int (*cb_free)(struct RedsStream *);
+} RedsStream;
 
 typedef struct Channel {
     struct Channel *next;
@@ -56,7 +56,7 @@ typedef struct Channel {
     uint32_t *common_caps;
     int num_caps;
     uint32_t *caps;
-    void (*link)(struct Channel *, RedsStreamContext *peer, int migration, int num_common_caps,
+    void (*link)(struct Channel *, RedsStream *peer, int migration, int num_common_caps,
                  uint32_t *common_caps, int num_caps, uint32_t *caps);
     void (*shutdown)(struct Channel *);
     void (*migrate)(struct Channel *);
diff --git a/server/smartcard.c b/server/smartcard.c
index a93e59d..23b3779 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -469,7 +469,7 @@ static void smartcard_channel_hold_pipe_item(PipeItem *item)
 {
 }
 
-static void smartcard_link(Channel *channel, RedsStreamContext *peer,
+static void smartcard_link(Channel *channel, RedsStream *peer,
                         int migration, int num_common_caps,
                         uint32_t *common_caps, int num_caps,
                         uint32_t *caps)
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 6c0f9d6..2cd4d92 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -73,7 +73,7 @@ typedef void (*cleanup_channel_proc)(SndChannel *channel);
 typedef struct SndWorker SndWorker;
 
 struct SndChannel {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SndWorker *worker;
     spice_parse_channel_func_t parser;
 
@@ -734,7 +734,7 @@ static void snd_record_send(void* data)
 }
 
 static SndChannel *__new_channel(SndWorker *worker, int size, uint32_t channel_id,
-                                 RedsStreamContext *peer,
+                                 RedsStream *peer,
                                  int migrate, send_messages_proc send_messages,
                                  handle_message_proc handle_message,
                                  on_message_done_proc on_message_done,
@@ -931,7 +931,7 @@ static void snd_playback_cleanup(SndChannel *channel)
     celt051_mode_destroy(playback_channel->celt_mode);
 }
 
-static void snd_set_playback_peer(Channel *channel, RedsStreamContext *peer, int migration,
+static void snd_set_playback_peer(Channel *channel, RedsStream *peer, int migration,
                                   int num_common_caps, uint32_t *common_caps, int num_caps,
                                   uint32_t *caps)
 {
@@ -1097,7 +1097,7 @@ static void snd_record_cleanup(SndChannel *channel)
     celt051_mode_destroy(record_channel->celt_mode);
 }
 
-static void snd_set_record_peer(Channel *channel, RedsStreamContext *peer, int migration,
+static void snd_set_record_peer(Channel *channel, RedsStream *peer, int migration,
                                 int num_common_caps, uint32_t *common_caps, int num_caps,
                                 uint32_t *caps)
 {
commit 29be54f6d3549c44b2b771ca3c21952d2d1b7026
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Wed Feb 9 18:01:18 2011 +0100

    server/reds: remove unused readv
    
    Let's not bother with it since nobody uses it, and it's not implemented for SSL anyway
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/server/reds.c b/server/reds.c
index b8ac79b..573a838 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1902,7 +1902,6 @@ static RedLinkInfo *reds_accept_connection(int listen_socket)
     peer->ctx = (void *)((unsigned long)link->peer->socket);
     peer->cb_read = (int (*)(void *, void *, int))reds_read;
     peer->cb_write = (int (*)(void *, void *, int))reds_write;
-    peer->cb_readv = (int (*)(void *, const struct iovec *vector, int count))readv;
     peer->cb_writev = (int (*)(void *, const struct iovec *vector, int count))writev;
     peer->cb_free = (int (*)(RedsStreamContext *))reds_free;
 
@@ -1939,7 +1938,6 @@ static void reds_accept_ssl_connection(int fd, int event, void *data)
     link->peer->ctx = (void *)(link->peer->ssl);
     link->peer->cb_write = (int (*)(void *, void *, int))reds_ssl_write;
     link->peer->cb_read = (int (*)(void *, void *, int))reds_ssl_read;
-    link->peer->cb_readv = NULL;
     link->peer->cb_writev = reds_ssl_writev;
     link->peer->cb_free = (int (*)(RedsStreamContext *))reds_ssl_free;
 
diff --git a/server/reds.h b/server/reds.h
index b5dec7e..547c33c 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -44,7 +44,6 @@ typedef struct RedsStreamContext {
     int (*cb_write)(void *, void *, int);
     int (*cb_read)(void *, void *, int);
 
-    int (*cb_readv)(void *, const struct iovec *vector, int count);
     int (*cb_writev)(void *, const struct iovec *vector, int count);
     int (*cb_free)(struct RedsStreamContext *);
 } RedsStreamContext;
commit 0e64e2d02c7353ccad8951dfb9b5ec8b03cd59ee
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Nov 9 15:16:41 2010 +0100

    build: make it silent
    
    This patch make it easier to spot warnings in compilation.  It should
    work with older versions of automake that don't support silent rules.
    
    If you want verbose build, make V=1.
    
    Signed-off-by: Uri Lublin <uril at redhat.com>
    
    https://bugs.freedesktop.org/show_bug.cgi?id=34795

diff --git a/configure.ac b/configure.ac
index 00f19d2..5642be3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -452,6 +452,8 @@ AC_SUBST(SPICE_NONPKGCONFIG_LIBS)
 AC_SUBST([SPICEC_STATIC_LINKAGE_BSTATIC])
 AC_SUBST([SPICEC_STATIC_LINKAGE_BDYNAMIC])
 
+m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
+
 AC_OUTPUT([
 Makefile
 spice-server.pc
diff --git a/server/Makefile.am b/server/Makefile.am
index d265bfb..1cc5010 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -23,14 +23,14 @@ INCLUDES = \
 spice_built_sources = generated_marshallers.c generated_marshallers.h generated_demarshallers.c
 
 generated_demarshallers.c: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include red_common.h $(top_srcdir)/spice.proto generated_demarshallers.c
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --server --include red_common.h $(top_srcdir)/spice.proto generated_demarshallers.c
 
 STRUCTS=-M String -M Rect -M Point -M DisplayBase -M Fill -M Opaque -M Copy -M Blend -M Blackness -M Whiteness -M Invers -M Rop3 -M Stroke -M Text -M Transparent -M AlphaBlend
 generated_marshallers.c: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --include red_common.h --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --include red_common.h --generate-marshallers $(STRUCTS) --server $(top_srcdir)/spice.proto generated_marshallers.c
 
 generated_marshallers.h: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server -H $(top_srcdir)/spice.proto generated_marshallers.h
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers $(STRUCTS) --server -H $(top_srcdir)/spice.proto generated_marshallers.h
 
 if SUPPORT_GL
 GL_SRCS =				\


More information about the Spice-commits mailing list