[Spice-commits] 12 commits - server/Makefile.am server/cursor-channel.c server/dcc.c server/dcc.h server/display-channel.c server/inputs-channel.c server/main-channel-client.c server/main-channel.c server/red-channel-client-private.h server/red-channel-client.c server/red-channel-client.h server/red-channel.c server/red-channel.h server/smartcard-channel-client.c server/smartcard-channel-client.h server/sound.c server/spicevmc.c

Christophe Fergau teuf at kemper.freedesktop.org
Wed Feb 15 07:49:59 UTC 2017


 server/Makefile.am                  |    1 
 server/cursor-channel.c             |    2 
 server/dcc.c                        |    4 
 server/dcc.h                        |    4 
 server/display-channel.c            |    2 
 server/inputs-channel.c             |    8 
 server/main-channel-client.c        |    2 
 server/main-channel.c               |    8 
 server/red-channel-client-private.h |  112 ------------
 server/red-channel-client.c         |  325 +++++++++++++++++++++++++-----------
 server/red-channel-client.h         |   12 -
 server/red-channel.c                |   45 ----
 server/red-channel.h                |   82 +--------
 server/smartcard-channel-client.c   |    7 
 server/smartcard-channel-client.h   |    2 
 server/sound.c                      |    8 
 server/spicevmc.c                   |   12 -
 17 files changed, 277 insertions(+), 359 deletions(-)

New commits:
commit 3ef913a38876fbf9a744423cf58fccd47521d7c4
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Fri Feb 10 15:08:06 2017 +0100

    rcc: Rename {Outgoing,Incoming}Handler
    
    They no longer contain any vfuncs, so calling them "handler" does not
    make a lot of sense. This commit renames them to
    OutgoingMessageBuffer/IncomingMessageBuffer.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 051ac6f..9f48660 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -78,21 +78,21 @@ typedef struct RedChannelClientConnectivityMonitor {
     SpiceTimer *timer;
 } RedChannelClientConnectivityMonitor;
 
-typedef struct OutgoingHandler {
+typedef struct OutgoingMessageBuffer {
     struct iovec vec_buf[IOV_MAX];
     int vec_size;
     struct iovec *vec;
     int pos;
     int size;
-} OutgoingHandler;
+} OutgoingMessageBuffer;
 
-typedef struct IncomingHandler {
+typedef struct IncomingMessageBuffer {
     uint8_t header_buf[MAX_HEADER_SIZE];
     SpiceDataHeaderOpaque header;
     uint32_t header_pos;
     uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
     uint32_t msg_pos;
-} IncomingHandler;
+} IncomingMessageBuffer;
 
 struct RedChannelClientPrivate
 {
@@ -139,8 +139,8 @@ struct RedChannelClientPrivate
     RedChannelClientLatencyMonitor latency_monitor;
     RedChannelClientConnectivityMonitor connectivity_monitor;
 
-    IncomingHandler incoming;
-    OutgoingHandler outgoing;
+    IncomingMessageBuffer incoming;
+    OutgoingMessageBuffer outgoing;
 };
 
 static const SpiceDataHeaderOpaque full_header_wrapper;
@@ -1115,24 +1115,24 @@ static void red_channel_client_release_msg_buf(RedChannelClient *rcc,
 static void red_channel_client_handle_outgoing(RedChannelClient *rcc)
 {
     RedsStream *stream = rcc->priv->stream;
-    OutgoingHandler *handler = &rcc->priv->outgoing;
+    OutgoingMessageBuffer *buffer = &rcc->priv->outgoing;
     ssize_t n;
 
     if (!stream) {
         return;
     }
 
-    if (handler->size == 0) {
-        handler->vec = handler->vec_buf;
-        handler->size = red_channel_client_get_out_msg_size(rcc);
-        if (!handler->size) {  // nothing to be sent
+    if (buffer->size == 0) {
+        buffer->vec = buffer->vec_buf;
+        buffer->size = red_channel_client_get_out_msg_size(rcc);
+        if (!buffer->size) {  // nothing to be sent
             return;
         }
     }
 
     for (;;) {
-        red_channel_client_prepare_out_msg(rcc, handler->vec, &handler->vec_size, handler->pos);
-        n = reds_stream_writev(stream, handler->vec, handler->vec_size);
+        red_channel_client_prepare_out_msg(rcc, buffer->vec, &buffer->vec_size, buffer->pos);
+        n = reds_stream_writev(stream, buffer->vec, buffer->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
@@ -1149,15 +1149,15 @@ static void red_channel_client_handle_outgoing(RedChannelClient *rcc)
                 return;
             }
         } else {
-            handler->pos += n;
+            buffer->pos += n;
             red_channel_client_data_sent(rcc, n);
-            if (handler->pos == handler->size) { // finished writing data
-                /* reset handler before calling on_msg_done, since it
+            if (buffer->pos == buffer->size) { // finished writing data
+                /* reset buffer before calling on_msg_done, since it
                  * can trigger another call to red_channel_client_handle_outgoing (when
                  * switching from the urgent marshaller to the main one */
-                handler->vec = handler->vec_buf;
-                handler->pos = 0;
-                handler->size = 0;
+                buffer->vec = buffer->vec_buf;
+                buffer->pos = 0;
+                buffer->size = 0;
                 red_channel_client_msg_sent(rcc);
                 return;
             }
@@ -1225,7 +1225,7 @@ static uint8_t *red_channel_client_parse(RedChannelClient *rcc, uint8_t *message
 static void red_channel_client_handle_incoming(RedChannelClient *rcc)
 {
     RedsStream *stream = rcc->priv->stream;
-    IncomingHandler *handler = &rcc->priv->incoming;
+    IncomingMessageBuffer *buffer = &rcc->priv->incoming;
     int bytes_read;
     uint16_t msg_type;
     uint32_t msg_size;
@@ -1244,28 +1244,28 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc)
         RedChannel *channel = red_channel_client_get_channel(rcc);
         RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
 
-        if (handler->header_pos < handler->header.header_size) {
+        if (buffer->header_pos < buffer->header.header_size) {
             bytes_read = red_peer_receive(stream,
-                                          handler->header.data + handler->header_pos,
-                                          handler->header.header_size - handler->header_pos);
+                                          buffer->header.data + buffer->header_pos,
+                                          buffer->header.header_size - buffer->header_pos);
             if (bytes_read == -1) {
                 red_channel_client_disconnect(rcc);
                 return;
             }
             red_channel_client_data_read(rcc, bytes_read);
-            handler->header_pos += bytes_read;
+            buffer->header_pos += bytes_read;
 
-            if (handler->header_pos != handler->header.header_size) {
+            if (buffer->header_pos != buffer->header.header_size) {
                 return;
             }
         }
 
-        msg_size = handler->header.get_msg_size(&handler->header);
-        msg_type = handler->header.get_msg_type(&handler->header);
-        if (handler->msg_pos < msg_size) {
-            if (!handler->msg) {
-                handler->msg = red_channel_client_alloc_msg_buf(rcc, msg_type, msg_size);
-                if (handler->msg == NULL) {
+        msg_size = buffer->header.get_msg_size(&buffer->header);
+        msg_type = buffer->header.get_msg_type(&buffer->header);
+        if (buffer->msg_pos < msg_size) {
+            if (!buffer->msg) {
+                buffer->msg = red_channel_client_alloc_msg_buf(rcc, msg_type, msg_size);
+                if (buffer->msg == NULL) {
                     spice_printerr("ERROR: channel refused to allocate buffer.");
                     red_channel_client_disconnect(rcc);
                     return;
@@ -1273,30 +1273,30 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc)
             }
 
             bytes_read = red_peer_receive(stream,
-                                          handler->msg + handler->msg_pos,
-                                          msg_size - handler->msg_pos);
+                                          buffer->msg + buffer->msg_pos,
+                                          msg_size - buffer->msg_pos);
             if (bytes_read == -1) {
                 red_channel_client_release_msg_buf(rcc, msg_type, msg_size,
-                                                   handler->msg);
+                                                   buffer->msg);
                 red_channel_client_disconnect(rcc);
                 return;
             }
             red_channel_client_data_read(rcc, bytes_read);
-            handler->msg_pos += bytes_read;
-            if (handler->msg_pos != msg_size) {
+            buffer->msg_pos += bytes_read;
+            if (buffer->msg_pos != msg_size) {
                 return;
             }
         }
 
         parsed = red_channel_client_parse(rcc,
-                                          handler->msg, msg_size,
+                                          buffer->msg, msg_size,
                                           msg_type,
                                           &parsed_size, &parsed_free);
         if (parsed == NULL) {
             spice_printerr("failed to parse message type %d", msg_type);
             red_channel_client_release_msg_buf(rcc,
                                                msg_type, msg_size,
-                                               handler->msg);
+                                               buffer->msg);
             red_channel_client_disconnect(rcc);
             return;
         }
@@ -1305,12 +1305,12 @@ static void red_channel_client_handle_incoming(RedChannelClient *rcc)
         if (parsed_free != NULL) {
             parsed_free(parsed);
         }
-        handler->msg_pos = 0;
+        buffer->msg_pos = 0;
         red_channel_client_release_msg_buf(rcc,
                                            msg_type, msg_size,
-                                           handler->msg);
-        handler->msg = NULL;
-        handler->header_pos = 0;
+                                           buffer->msg);
+        buffer->msg = NULL;
+        buffer->header_pos = 0;
 
         if (!ret_handle) {
             red_channel_client_disconnect(rcc);
commit 65501eb13c88feb3755bc6756f311114663b5271
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Fri Feb 10 14:59:17 2017 +0100

    rcc: Remove red-channel-client-private.h
    
    Nothing outside of RedChannelClient needs access to data contained in
    RedChannelClientPrivate, so we can move all the type definitions to the
    .c file to make it fully opaque rather than relying on a private header.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/Makefile.am b/server/Makefile.am
index 6db4e7b..a043660 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -101,7 +101,6 @@ libserver_la_SOURCES =				\
 	red-channel.h				\
 	red-channel-client.c			\
 	red-channel-client.h			\
-	red-channel-client-private.h		\
 	red-client.c				\
 	red-client.h				\
 	red-common.h				\
diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
deleted file mode 100644
index 5c1308b..0000000
--- a/server/red-channel-client-private.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-    Copyright (C) 2009-2015 Red Hat, Inc.
-
-   This library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   This library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _H_RED_CHANNEL_CLIENT_PRIVATE
-#define _H_RED_CHANNEL_CLIENT_PRIVATE
-
-#include "red-channel.h"
-#include "red-channel-client.h"
-
-typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
-
-typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
-typedef uint32_t (*get_msg_size_proc)(SpiceDataHeaderOpaque *header);
-typedef void (*set_msg_type_proc)(SpiceDataHeaderOpaque *header, uint16_t type);
-typedef void (*set_msg_size_proc)(SpiceDataHeaderOpaque *header, uint32_t size);
-typedef void (*set_msg_serial_proc)(SpiceDataHeaderOpaque *header, uint64_t serial);
-typedef void (*set_msg_sub_list_proc)(SpiceDataHeaderOpaque *header, uint32_t sub_list);
-
-struct SpiceDataHeaderOpaque {
-    uint8_t *data;
-    uint16_t header_size;
-
-    set_msg_type_proc set_msg_type;
-    set_msg_size_proc set_msg_size;
-    set_msg_serial_proc set_msg_serial;
-    set_msg_sub_list_proc set_msg_sub_list;
-
-    get_msg_type_proc get_msg_type;
-    get_msg_size_proc get_msg_size;
-};
-
-typedef struct RedChannelClientLatencyMonitor {
-    int state;
-    uint64_t last_pong_time;
-    SpiceTimer *timer;
-    uint32_t id;
-    int tcp_nodelay;
-    int warmup_was_sent;
-
-    int64_t roundtrip;
-} RedChannelClientLatencyMonitor;
-
-typedef struct RedChannelClientConnectivityMonitor {
-    int state;
-    uint32_t out_bytes;
-    uint32_t in_bytes;
-    uint32_t timeout;
-    SpiceTimer *timer;
-} RedChannelClientConnectivityMonitor;
-
-typedef struct OutgoingHandler {
-    struct iovec vec_buf[IOV_MAX];
-    int vec_size;
-    struct iovec *vec;
-    int pos;
-    int size;
-} OutgoingHandler;
-
-typedef struct IncomingHandler {
-    uint8_t header_buf[MAX_HEADER_SIZE];
-    SpiceDataHeaderOpaque header;
-    uint32_t header_pos;
-    uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
-    uint32_t msg_pos;
-} IncomingHandler;
-
-struct RedChannelClientPrivate
-{
-    RedChannel *channel;
-    RedClient  *client;
-    RedsStream *stream;
-    gboolean monitor_latency;
-
-    struct {
-        uint32_t generation;
-        uint32_t client_generation;
-        uint32_t messages_window;
-        uint32_t client_window;
-    } ack_data;
-
-    struct {
-        /* this can be either main.marshaller or urgent.marshaller */
-        SpiceMarshaller *marshaller;
-        SpiceDataHeaderOpaque header;
-        uint32_t size;
-        int blocked;
-        uint64_t last_sent_serial;
-
-        struct {
-            SpiceMarshaller *marshaller;
-            uint8_t *header_data;
-        } main;
-
-        struct {
-            SpiceMarshaller *marshaller;
-        } urgent;
-    } send_data;
-
-    int during_send;
-    GQueue pipe;
-
-    RedChannelCapabilities remote_caps;
-    int is_mini_header;
-    gboolean destroying;
-
-    int wait_migrate_data;
-    int wait_migrate_flush_mark;
-
-    RedChannelClientLatencyMonitor latency_monitor;
-    RedChannelClientConnectivityMonitor connectivity_monitor;
-
-    IncomingHandler incoming;
-    OutgoingHandler outgoing;
-};
-
-#endif /* _H_RED_CHANNEL_CLIENT_PRIVATE */
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index b7a6268..051ac6f 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -34,10 +34,115 @@
 #include <common/generated_server_marshallers.h>
 
 #include "red-channel-client.h"
-#include "red-channel-client-private.h"
 #include "red-client.h"
 #include "glib-compat.h"
 
+typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
+
+typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
+typedef uint32_t (*get_msg_size_proc)(SpiceDataHeaderOpaque *header);
+typedef void (*set_msg_type_proc)(SpiceDataHeaderOpaque *header, uint16_t type);
+typedef void (*set_msg_size_proc)(SpiceDataHeaderOpaque *header, uint32_t size);
+typedef void (*set_msg_serial_proc)(SpiceDataHeaderOpaque *header, uint64_t serial);
+typedef void (*set_msg_sub_list_proc)(SpiceDataHeaderOpaque *header, uint32_t sub_list);
+
+struct SpiceDataHeaderOpaque {
+    uint8_t *data;
+    uint16_t header_size;
+
+    set_msg_type_proc set_msg_type;
+    set_msg_size_proc set_msg_size;
+    set_msg_serial_proc set_msg_serial;
+    set_msg_sub_list_proc set_msg_sub_list;
+
+    get_msg_type_proc get_msg_type;
+    get_msg_size_proc get_msg_size;
+};
+
+typedef struct RedChannelClientLatencyMonitor {
+    int state;
+    uint64_t last_pong_time;
+    SpiceTimer *timer;
+    uint32_t id;
+    int tcp_nodelay;
+    int warmup_was_sent;
+
+    int64_t roundtrip;
+} RedChannelClientLatencyMonitor;
+
+typedef struct RedChannelClientConnectivityMonitor {
+    int state;
+    uint32_t out_bytes;
+    uint32_t in_bytes;
+    uint32_t timeout;
+    SpiceTimer *timer;
+} RedChannelClientConnectivityMonitor;
+
+typedef struct OutgoingHandler {
+    struct iovec vec_buf[IOV_MAX];
+    int vec_size;
+    struct iovec *vec;
+    int pos;
+    int size;
+} OutgoingHandler;
+
+typedef struct IncomingHandler {
+    uint8_t header_buf[MAX_HEADER_SIZE];
+    SpiceDataHeaderOpaque header;
+    uint32_t header_pos;
+    uint8_t *msg; // data of the msg following the header. allocated by alloc_msg_buf.
+    uint32_t msg_pos;
+} IncomingHandler;
+
+struct RedChannelClientPrivate
+{
+    RedChannel *channel;
+    RedClient  *client;
+    RedsStream *stream;
+    gboolean monitor_latency;
+
+    struct {
+        uint32_t generation;
+        uint32_t client_generation;
+        uint32_t messages_window;
+        uint32_t client_window;
+    } ack_data;
+
+    struct {
+        /* this can be either main.marshaller or urgent.marshaller */
+        SpiceMarshaller *marshaller;
+        SpiceDataHeaderOpaque header;
+        uint32_t size;
+        int blocked;
+        uint64_t last_sent_serial;
+
+        struct {
+            SpiceMarshaller *marshaller;
+            uint8_t *header_data;
+        } main;
+
+        struct {
+            SpiceMarshaller *marshaller;
+        } urgent;
+    } send_data;
+
+    int during_send;
+    GQueue pipe;
+
+    RedChannelCapabilities remote_caps;
+    int is_mini_header;
+    gboolean destroying;
+
+    int wait_migrate_data;
+    int wait_migrate_flush_mark;
+
+    RedChannelClientLatencyMonitor latency_monitor;
+    RedChannelClientConnectivityMonitor connectivity_monitor;
+
+    IncomingHandler incoming;
+    OutgoingHandler outgoing;
+};
+
 static const SpiceDataHeaderOpaque full_header_wrapper;
 static const SpiceDataHeaderOpaque mini_header_wrapper;
 static void red_channel_client_clear_sent_item(RedChannelClient *rcc);
commit 31a5182bd22db217325340fad7294d6f509ba6f8
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Nov 30 09:36:58 2016 +0100

    rcc: Move SpiceDataHeaderOpaque to red-channel-client-private.h
    
    It's only used by red-channel-client.c
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index 08ac6ca..5c1308b 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -21,6 +21,28 @@
 #include "red-channel.h"
 #include "red-channel-client.h"
 
+typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
+
+typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
+typedef uint32_t (*get_msg_size_proc)(SpiceDataHeaderOpaque *header);
+typedef void (*set_msg_type_proc)(SpiceDataHeaderOpaque *header, uint16_t type);
+typedef void (*set_msg_size_proc)(SpiceDataHeaderOpaque *header, uint32_t size);
+typedef void (*set_msg_serial_proc)(SpiceDataHeaderOpaque *header, uint64_t serial);
+typedef void (*set_msg_sub_list_proc)(SpiceDataHeaderOpaque *header, uint32_t sub_list);
+
+struct SpiceDataHeaderOpaque {
+    uint8_t *data;
+    uint16_t header_size;
+
+    set_msg_type_proc set_msg_type;
+    set_msg_size_proc set_msg_size;
+    set_msg_serial_proc set_msg_serial;
+    set_msg_sub_list_proc set_msg_sub_list;
+
+    get_msg_type_proc get_msg_type;
+    get_msg_size_proc get_msg_size;
+};
+
 typedef struct RedChannelClientLatencyMonitor {
     int state;
     uint64_t last_pong_time;
diff --git a/server/red-channel.h b/server/red-channel.h
index 698759e..e22f96e 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -37,28 +37,6 @@
 
 G_BEGIN_DECLS
 
-typedef struct SpiceDataHeaderOpaque SpiceDataHeaderOpaque;
-
-typedef uint16_t (*get_msg_type_proc)(SpiceDataHeaderOpaque *header);
-typedef uint32_t (*get_msg_size_proc)(SpiceDataHeaderOpaque *header);
-typedef void (*set_msg_type_proc)(SpiceDataHeaderOpaque *header, uint16_t type);
-typedef void (*set_msg_size_proc)(SpiceDataHeaderOpaque *header, uint32_t size);
-typedef void (*set_msg_serial_proc)(SpiceDataHeaderOpaque *header, uint64_t serial);
-typedef void (*set_msg_sub_list_proc)(SpiceDataHeaderOpaque *header, uint32_t sub_list);
-
-struct SpiceDataHeaderOpaque {
-    uint8_t *data;
-    uint16_t header_size;
-
-    set_msg_type_proc set_msg_type;
-    set_msg_size_proc set_msg_size;
-    set_msg_serial_proc set_msg_serial;
-    set_msg_sub_list_proc set_msg_sub_list;
-
-    get_msg_type_proc get_msg_type;
-    get_msg_size_proc get_msg_size;
-};
-
 typedef struct RedChannel RedChannel;
 typedef struct RedChannelClient RedChannelClient;
 typedef struct RedClient RedClient;
commit d4938694e251337b763c1e575026af921ba7e745
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Nov 30 09:29:37 2016 +0100

    rcc: Replace 'opaque' arg with typed RedChannelClient
    
    The methods previously used by OutgoingHandlerInterface and
    IncomingHandlerInterface are no longer used as generic callbacks,
    but are directly called from RedChannelClient code. We can be explicit
    about the type of their first argument (RedChannelClient *) rather than
    using a generic void * pointer.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 4740e80..b7a6268 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -368,9 +368,8 @@ RedChannel* red_channel_client_get_channel(RedChannelClient *rcc)
     return rcc->priv->channel;
 }
 
-static void red_channel_client_data_sent(void *opaque, int n)
+static void red_channel_client_data_sent(RedChannelClient *rcc, int n)
 {
-    RedChannelClient *rcc = opaque;
     RedChannel *channel = red_channel_client_get_channel(rcc);
 
     if (rcc->priv->connectivity_monitor.timer) {
@@ -380,35 +379,29 @@ static void red_channel_client_data_sent(void *opaque, int n)
     red_channel_on_output(channel, n);
 }
 
-static void red_channel_client_data_read(void *opaque, int n)
+static void red_channel_client_data_read(RedChannelClient *rcc, int n)
 {
-    RedChannelClient *rcc = opaque;
-
     if (rcc->priv->connectivity_monitor.timer) {
         rcc->priv->connectivity_monitor.in_bytes += n;
     }
 }
 
-static int red_channel_client_get_out_msg_size(void *opaque)
+static int red_channel_client_get_out_msg_size(RedChannelClient *rcc)
 {
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
-
     return rcc->priv->send_data.size;
 }
 
-static void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
-                                               int *vec_size, int pos)
+static void red_channel_client_prepare_out_msg(RedChannelClient *rcc,
+                                               struct iovec *vec, int *vec_size,
+                                               int pos)
 {
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
-
     *vec_size = spice_marshaller_fill_iovec(rcc->priv->send_data.marshaller,
                                             vec, IOV_MAX, pos);
 }
 
-static void red_channel_client_set_blocked(void *opaque)
+static void red_channel_client_set_blocked(RedChannelClient *rcc)
 {
     SpiceCoreInterfaceInternal *core;
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
 
     rcc->priv->send_data.blocked = TRUE;
     core = red_channel_get_core_interface(rcc->priv->channel);
@@ -545,9 +538,8 @@ static void red_channel_client_restore_main_sender(RedChannelClient *rcc)
     rcc->priv->send_data.header.data = rcc->priv->send_data.main.header_data;
 }
 
-static void red_channel_client_msg_sent(void *opaque)
+static void red_channel_client_msg_sent(RedChannelClient *rcc)
 {
-    RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
     int fd;
 
     if (spice_marshaller_get_fd(rcc->priv->send_data.marshaller, &fd)) {
commit 7ffc7ed303f7de9a61d6a1b3953be4a46d13aefa
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Nov 29 19:18:31 2016 +0100

    rcc: Pass RedChannelClient to red_peer_handle_outgoing()
    
    There is only one implementation of OutgoingHandler which relies
    OutgoingHandler::opaque being a RedChannelClient. This commit makes this
    explicit in order to get rid of the OutgoingHandler::opaque data member.
    
    This renames red_peer_handle_outgoing() to
    red_channel_client_handle_outgoing() as the method is now very much tied
    to RedChannelClient.
    
    If we want to keep some genericity, we could return error codes from
    red_channel_client_handle_outgoing() and handle RedChannelClient
    disconnection/... from the caller rather than directly in the
    _handle_outgoing() method. This would probably allow to move the
    data reading logic to reds-stream.c
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index a7167e5..08ac6ca 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -41,7 +41,6 @@ typedef struct RedChannelClientConnectivityMonitor {
 } RedChannelClientConnectivityMonitor;
 
 typedef struct OutgoingHandler {
-    void *opaque;
     struct iovec vec_buf[IOV_MAX];
     int vec_size;
     struct iovec *vec;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 27b8f9d..4740e80 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -268,7 +268,6 @@ static void red_channel_client_constructed(GObject *object)
 {
     RedChannelClient *self =  RED_CHANNEL_CLIENT(object);
 
-    self->priv->outgoing.opaque = self;
     self->priv->outgoing.pos = 0;
     self->priv->outgoing.size = 0;
 
@@ -1016,8 +1015,10 @@ static void red_channel_client_release_msg_buf(RedChannelClient *rcc,
     klass->release_recv_buf(rcc, type, size, msg);
 }
 
-static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
+static void red_channel_client_handle_outgoing(RedChannelClient *rcc)
 {
+    RedsStream *stream = rcc->priv->stream;
+    OutgoingHandler *handler = &rcc->priv->outgoing;
     ssize_t n;
 
     if (!stream) {
@@ -1026,41 +1027,41 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
 
     if (handler->size == 0) {
         handler->vec = handler->vec_buf;
-        handler->size = red_channel_client_get_out_msg_size(handler->opaque);
+        handler->size = red_channel_client_get_out_msg_size(rcc);
         if (!handler->size) {  // nothing to be sent
             return;
         }
     }
 
     for (;;) {
-        red_channel_client_prepare_out_msg(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
+        red_channel_client_prepare_out_msg(rcc, handler->vec, &handler->vec_size, handler->pos);
         n = reds_stream_writev(stream, handler->vec, handler->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
-                red_channel_client_set_blocked(handler->opaque);
+                red_channel_client_set_blocked(rcc);
                 return;
             case EINTR:
                 continue;
             case EPIPE:
-                red_channel_client_disconnect(handler->opaque);
+                red_channel_client_disconnect(rcc);
                 return;
             default:
                 spice_printerr("%s", strerror(errno));
-                red_channel_client_disconnect(handler->opaque);
+                red_channel_client_disconnect(rcc);
                 return;
             }
         } else {
             handler->pos += n;
-            red_channel_client_data_sent(handler->opaque, n);
+            red_channel_client_data_sent(rcc, n);
             if (handler->pos == handler->size) { // finished writing data
                 /* reset handler before calling on_msg_done, since it
-                 * can trigger another call to red_peer_handle_outgoing (when
+                 * can trigger another call to red_channel_client_handle_outgoing (when
                  * switching from the urgent marshaller to the main one */
                 handler->vec = handler->vec_buf;
                 handler->pos = 0;
                 handler->size = 0;
-                red_channel_client_msg_sent(handler->opaque);
+                red_channel_client_msg_sent(rcc);
                 return;
             }
         }
@@ -1231,7 +1232,7 @@ void red_channel_client_receive(RedChannelClient *rcc)
 void red_channel_client_send(RedChannelClient *rcc)
 {
     g_object_ref(rcc);
-    red_peer_handle_outgoing(rcc->priv->stream, &rcc->priv->outgoing);
+    red_channel_client_handle_outgoing(rcc);
     g_object_unref(rcc);
 }
 
commit d6126bf49568891fe7222162aeb95bb7e21783f1
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Nov 29 19:18:31 2016 +0100

    rcc: Pass RedChannelClient to red_peer_handle_incoming()
    
    There is only one implementation of IncomingHandler which relies
    IncomingHandler::opaque to be a RedChannlClient. This commit makes this
    explicit. This allows to get rid of the IncomingHandler::opaque data
    member.
    
    This renames red_peer_handle_incoming() to
    red_channel_client_handle_incoming() as the method is now very much tied
    to RedChannelClient.
    
    If we want to keep some genericity, we could return error codes from
    red_channel_client_handle_incoming() and handle RedChannelClient
    disconnection/... from the caller rather than directly in the
    _handle_incoming() method. This would probably allow to move the
    data reading logic to reds-stream.c
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index 77766d0..a7167e5 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -50,7 +50,6 @@ typedef struct OutgoingHandler {
 } OutgoingHandler;
 
 typedef struct IncomingHandler {
-    void *opaque;
     uint8_t header_buf[MAX_HEADER_SIZE];
     SpiceDataHeaderOpaque header;
     uint32_t header_pos;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 5ab1b8f..27b8f9d 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -268,7 +268,6 @@ static void red_channel_client_constructed(GObject *object)
 {
     RedChannelClient *self =  RED_CHANNEL_CLIENT(object);
 
-    self->priv->incoming.opaque = self;
     self->priv->outgoing.opaque = self;
     self->priv->outgoing.pos = 0;
     self->priv->outgoing.size = 0;
@@ -1125,8 +1124,10 @@ static uint8_t *red_channel_client_parse(RedChannelClient *rcc, uint8_t *message
 // 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 *stream, IncomingHandler *handler)
+static void red_channel_client_handle_incoming(RedChannelClient *rcc)
 {
+    RedsStream *stream = rcc->priv->stream;
+    IncomingHandler *handler = &rcc->priv->incoming;
     int bytes_read;
     uint16_t msg_type;
     uint32_t msg_size;
@@ -1142,7 +1143,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         uint8_t *parsed;
         size_t parsed_size;
         message_destructor_t parsed_free = NULL;
-        RedChannel *channel = red_channel_client_get_channel(handler->opaque);
+        RedChannel *channel = red_channel_client_get_channel(rcc);
         RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
 
         if (handler->header_pos < handler->header.header_size) {
@@ -1150,10 +1151,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->header.data + handler->header_pos,
                                           handler->header.header_size - handler->header_pos);
             if (bytes_read == -1) {
-                red_channel_client_disconnect(handler->opaque);
+                red_channel_client_disconnect(rcc);
                 return;
             }
-            red_channel_client_data_read(handler->opaque, bytes_read);
+            red_channel_client_data_read(rcc, bytes_read);
             handler->header_pos += bytes_read;
 
             if (handler->header_pos != handler->header.header_size) {
@@ -1165,10 +1166,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         msg_type = handler->header.get_msg_type(&handler->header);
         if (handler->msg_pos < msg_size) {
             if (!handler->msg) {
-                handler->msg = red_channel_client_alloc_msg_buf(handler->opaque, msg_type, msg_size);
+                handler->msg = red_channel_client_alloc_msg_buf(rcc, msg_type, msg_size);
                 if (handler->msg == NULL) {
                     spice_printerr("ERROR: channel refused to allocate buffer.");
-                    red_channel_client_disconnect(handler->opaque);
+                    red_channel_client_disconnect(rcc);
                     return;
                 }
             }
@@ -1177,44 +1178,44 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->msg + handler->msg_pos,
                                           msg_size - handler->msg_pos);
             if (bytes_read == -1) {
-                red_channel_client_release_msg_buf(handler->opaque, msg_type, msg_size,
+                red_channel_client_release_msg_buf(rcc, msg_type, msg_size,
                                                    handler->msg);
-                red_channel_client_disconnect(handler->opaque);
+                red_channel_client_disconnect(rcc);
                 return;
             }
-            red_channel_client_data_read(handler->opaque, bytes_read);
+            red_channel_client_data_read(rcc, bytes_read);
             handler->msg_pos += bytes_read;
             if (handler->msg_pos != msg_size) {
                 return;
             }
         }
 
-        parsed = red_channel_client_parse(handler->opaque,
+        parsed = red_channel_client_parse(rcc,
                                           handler->msg, msg_size,
                                           msg_type,
                                           &parsed_size, &parsed_free);
         if (parsed == NULL) {
             spice_printerr("failed to parse message type %d", msg_type);
-            red_channel_client_release_msg_buf(handler->opaque,
+            red_channel_client_release_msg_buf(rcc,
                                                msg_type, msg_size,
                                                handler->msg);
-            red_channel_client_disconnect(handler->opaque);
+            red_channel_client_disconnect(rcc);
             return;
         }
-        ret_handle = klass->handle_message(handler->opaque, msg_type,
+        ret_handle = klass->handle_message(rcc, msg_type,
                                            parsed_size, parsed);
         if (parsed_free != NULL) {
             parsed_free(parsed);
         }
         handler->msg_pos = 0;
-        red_channel_client_release_msg_buf(handler->opaque,
+        red_channel_client_release_msg_buf(rcc,
                                            msg_type, msg_size,
                                            handler->msg);
         handler->msg = NULL;
         handler->header_pos = 0;
 
         if (!ret_handle) {
-            red_channel_client_disconnect(handler->opaque);
+            red_channel_client_disconnect(rcc);
             return;
         }
     }
@@ -1223,7 +1224,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
 void red_channel_client_receive(RedChannelClient *rcc)
 {
     g_object_ref(rcc);
-    red_peer_handle_incoming(rcc->priv->stream, &rcc->priv->incoming);
+    red_channel_client_handle_incoming(rcc);
     g_object_unref(rcc);
 }
 
commit f93fe59c215cfd3c5f8a5dab028cc4d8ab75b2dc
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Nov 29 19:01:53 2016 +0100

    channel: Remove IncomingHandlerInterface
    
    This commit removes what remains of IncomingHandlerInterface. The
    remaining function pointers were pointing to RedChannel vfuncs.
    Moreover the IncomingHandlerInterface abstraction is unused, ie the
    codebase only has a single implementation for it, so we can directly
    call the relevant methods and make them static instead.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index 5d29f32..77766d0 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -50,7 +50,6 @@ typedef struct OutgoingHandler {
 } OutgoingHandler;
 
 typedef struct IncomingHandler {
-    IncomingHandlerInterface *cb;
     void *opaque;
     uint8_t header_buf[MAX_HEADER_SIZE];
     SpiceDataHeaderOpaque header;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 5106a97..5ab1b8f 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -269,8 +269,6 @@ static void red_channel_client_constructed(GObject *object)
     RedChannelClient *self =  RED_CHANNEL_CLIENT(object);
 
     self->priv->incoming.opaque = self;
-    self->priv->incoming.cb = red_channel_get_incoming_handler(self->priv->channel);
-
     self->priv->outgoing.opaque = self;
     self->priv->outgoing.pos = 0;
     self->priv->outgoing.size = 0;
@@ -1103,15 +1101,17 @@ static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
     return pos - buf;
 }
 
-static uint8_t *red_channel_client_parse(IncomingHandler *handler, uint8_t *message, size_t message_size,
+static uint8_t *red_channel_client_parse(RedChannelClient *rcc, uint8_t *message, size_t message_size,
                                          uint16_t message_type,
                                          size_t *size_out, message_destructor_t *free_message)
 {
+    RedChannel *channel = red_channel_client_get_channel(rcc);
+    RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
     uint8_t *parsed_message;
 
-    if (handler->cb->parser) {
-        parsed_message = handler->cb->parser(message, message + message_size, message_type,
-                                             SPICE_VERSION_MINOR, size_out, free_message);
+    if (klass->parser) {
+        parsed_message = klass->parser(message, message + message_size, message_type,
+                                       SPICE_VERSION_MINOR, size_out, free_message);
     } else {
         parsed_message = message;
         *size_out = message_size;
@@ -1142,6 +1142,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         uint8_t *parsed;
         size_t parsed_size;
         message_destructor_t parsed_free = NULL;
+        RedChannel *channel = red_channel_client_get_channel(handler->opaque);
+        RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
+
         if (handler->header_pos < handler->header.header_size) {
             bytes_read = red_peer_receive(stream,
                                           handler->header.data + handler->header_pos,
@@ -1186,7 +1189,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             }
         }
 
-        parsed = red_channel_client_parse(handler,
+        parsed = red_channel_client_parse(handler->opaque,
                                           handler->msg, msg_size,
                                           msg_type,
                                           &parsed_size, &parsed_free);
@@ -1198,8 +1201,8 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             red_channel_client_disconnect(handler->opaque);
             return;
         }
-        ret_handle = handler->cb->handle_message(handler->opaque, msg_type,
-                                                 parsed_size, parsed);
+        ret_handle = klass->handle_message(handler->opaque, msg_type,
+                                           parsed_size, parsed);
         if (parsed_free != NULL) {
             parsed_free(parsed);
         }
diff --git a/server/red-channel.c b/server/red-channel.c
index d2c9b4d..e1ea6d1 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -93,8 +93,6 @@ struct RedChannelPrivate
 
     void *data;
 
-    IncomingHandlerInterface incoming_cb;
-
     ClientCbs client_cbs;
     // TODO: when different channel_clients are in different threads
     // from Channel -> need to protect!
@@ -220,9 +218,6 @@ red_channel_constructed(GObject *object)
                  klass->alloc_recv_buf && klass->release_recv_buf);
     spice_assert(klass->handle_migrate_data ||
                  !(self->priv->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
-
-    self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message;
-    self->priv->incoming_cb.parser = klass->parser;
 }
 
 static void red_channel_client_default_connect(RedChannel *channel, RedClient *client,
@@ -764,11 +759,6 @@ void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem
     klass->send_item(rcc, item);
 }
 
-IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self)
-{
-    return &self->priv->incoming_cb;
-}
-
 void red_channel_reset_thread_id(RedChannel *self)
 {
     self->priv->thread_id = pthread_self();
diff --git a/server/red-channel.h b/server/red-channel.h
index cbdf2d9..698759e 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -59,15 +59,6 @@ struct SpiceDataHeaderOpaque {
     get_msg_size_proc get_msg_size;
 };
 
-typedef int (*handle_message_proc)(void *opaque,
-                                   uint16_t type, uint32_t size, uint8_t *msg);
-
-typedef struct IncomingHandlerInterface {
-    // 'parser' is optional and will not be used if NULL
-    spice_parse_channel_func_t parser;
-    handle_message_proc handle_message;
-} IncomingHandlerInterface;
-
 typedef struct RedChannel RedChannel;
 typedef struct RedChannelClient RedChannelClient;
 typedef struct RedClient RedClient;
@@ -275,10 +266,6 @@ void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem
 void red_channel_reset_thread_id(RedChannel *self);
 StatNodeRef red_channel_get_stat_node(RedChannel *channel);
 
-/* FIXME: does this even need to be in RedChannel? It's really only used in
- * RedChannelClient. Needs refactoring */
-IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self);
-
 const RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self);
 
 /*
commit 99641c687406ed1fc7222ced99a88c9fdca07d23
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Nov 29 17:02:57 2016 +0100

    channel: More removal of IncomingHandlerInterface vfuncs
    
    This commit removes IncomingHandlerInterface::on_error and
    IncomingHandlerInterface::on_input. As with previous commits, these
    vfuncs are always calling the method, and RedChannel::init sets them to
    point to RedChannelClient methods, which RedChannelClient is then going
    to call indirectly through the IncomingHandlerInterface instance.
    
    This commit changes this to direct calls to the corresponding methods.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index d38b82f..5106a97 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -384,7 +384,7 @@ static void red_channel_client_data_sent(void *opaque, int n)
     red_channel_on_output(channel, n);
 }
 
-void red_channel_client_on_input(void *opaque, int n)
+static void red_channel_client_data_read(void *opaque, int n)
 {
     RedChannelClient *rcc = opaque;
 
@@ -1147,10 +1147,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->header.data + handler->header_pos,
                                           handler->header.header_size - handler->header_pos);
             if (bytes_read == -1) {
-                handler->cb->on_error(handler->opaque);
+                red_channel_client_disconnect(handler->opaque);
                 return;
             }
-            handler->cb->on_input(handler->opaque, bytes_read);
+            red_channel_client_data_read(handler->opaque, bytes_read);
             handler->header_pos += bytes_read;
 
             if (handler->header_pos != handler->header.header_size) {
@@ -1165,7 +1165,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                 handler->msg = red_channel_client_alloc_msg_buf(handler->opaque, msg_type, msg_size);
                 if (handler->msg == NULL) {
                     spice_printerr("ERROR: channel refused to allocate buffer.");
-                    handler->cb->on_error(handler->opaque);
+                    red_channel_client_disconnect(handler->opaque);
                     return;
                 }
             }
@@ -1176,10 +1176,10 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             if (bytes_read == -1) {
                 red_channel_client_release_msg_buf(handler->opaque, msg_type, msg_size,
                                                    handler->msg);
-                handler->cb->on_error(handler->opaque);
+                red_channel_client_disconnect(handler->opaque);
                 return;
             }
-            handler->cb->on_input(handler->opaque, bytes_read);
+            red_channel_client_data_read(handler->opaque, bytes_read);
             handler->msg_pos += bytes_read;
             if (handler->msg_pos != msg_size) {
                 return;
@@ -1195,7 +1195,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             red_channel_client_release_msg_buf(handler->opaque,
                                                msg_type, msg_size,
                                                handler->msg);
-            handler->cb->on_error(handler->opaque);
+            red_channel_client_disconnect(handler->opaque);
             return;
         }
         ret_handle = handler->cb->handle_message(handler->opaque, msg_type,
@@ -1211,7 +1211,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         handler->header_pos = 0;
 
         if (!ret_handle) {
-            handler->cb->on_error(handler->opaque);
+            red_channel_client_disconnect(handler->opaque);
             return;
         }
     }
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index 9e2bf73..4f1d481 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -175,8 +175,6 @@ void red_channel_client_disconnect_if_pending_send(RedChannelClient *rcc);
 
 RedChannel* red_channel_client_get_channel(RedChannelClient *rcc);
 
-void red_channel_client_on_input(void *opaque, int n);
-
 void red_channel_client_semi_seamless_migration_complete(RedChannelClient *rcc);
 void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc);
 
diff --git a/server/red-channel.c b/server/red-channel.c
index 8563b96..d2c9b4d 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -198,11 +198,6 @@ red_channel_finalize(GObject *object)
     G_OBJECT_CLASS(red_channel_parent_class)->finalize(object);
 }
 
-static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
-{
-    red_channel_client_disconnect(rcc);
-}
-
 void red_channel_on_output(RedChannel *self, int n)
 {
 #ifdef RED_STATISTICS
@@ -325,11 +320,6 @@ red_channel_init(RedChannel *self)
     red_channel_set_common_cap(self, SPICE_COMMON_CAP_MINI_HEADER);
     self->priv->thread_id = pthread_self();
 
-    // TODO: send incoming_cb as parameters instead of duplicating?
-    self->priv->incoming_cb.on_error =
-        (on_incoming_error_proc)red_channel_client_default_peer_on_error;
-    self->priv->incoming_cb.on_input = red_channel_client_on_input;
-
     self->priv->client_cbs.connect = red_channel_client_default_connect;
     self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
     self->priv->client_cbs.migrate = red_channel_client_default_migrate;
diff --git a/server/red-channel.h b/server/red-channel.h
index 9a7669b..cbdf2d9 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -61,15 +61,11 @@ struct SpiceDataHeaderOpaque {
 
 typedef int (*handle_message_proc)(void *opaque,
                                    uint16_t type, uint32_t size, uint8_t *msg);
-typedef void (*on_incoming_error_proc)(void *opaque);
-typedef void (*on_input_proc)(void *opaque, int n);
 
 typedef struct IncomingHandlerInterface {
-    on_incoming_error_proc on_error; // recv error or handle_message error
     // 'parser' is optional and will not be used if NULL
     spice_parse_channel_func_t parser;
     handle_message_proc handle_message;
-    on_input_proc on_input;
 } IncomingHandlerInterface;
 
 typedef struct RedChannel RedChannel;
commit 725c5fd3236047503321ecdce8912b2a0eaa6f17
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Nov 29 16:59:50 2016 +0100

    channel: Remove IncomingHandlerInterface::{alloc,release}_msg_buf
    
    Similarly to the previous commits, this removes an indirection level,
    IncomingHandlerInterface stores pointers to
    alloc_recv_buf/release_recv_buf vfuncs, but these are always set to
    RedChannel::alloc_recv_buf/RedChannel::release_recv_buf, which are also
    vfuncs which can be overridden if needed. This commit removes the
    indirection and directly calls the relevant methods.
    
    These vfuncs really should be in RedChannelClient rather than
    RedChannel.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 615ee15..d38b82f 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -1000,6 +1000,25 @@ void red_channel_client_shutdown(RedChannelClient *rcc)
     }
 }
 
+static uint8_t *red_channel_client_alloc_msg_buf(RedChannelClient *rcc,
+                                                 uint16_t type, uint32_t size)
+{
+    RedChannel *channel = red_channel_client_get_channel(rcc);
+    RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
+
+    return klass->alloc_recv_buf(rcc, type, size);
+}
+
+static void red_channel_client_release_msg_buf(RedChannelClient *rcc,
+                                               uint16_t type, uint32_t size,
+                                               uint8_t *msg)
+{
+    RedChannel *channel = red_channel_client_get_channel(rcc);
+    RedChannelClass *klass = RED_CHANNEL_GET_CLASS(channel);
+
+    klass->release_recv_buf(rcc, type, size, msg);
+}
+
 static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
 {
     ssize_t n;
@@ -1143,7 +1162,7 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
         msg_type = handler->header.get_msg_type(&handler->header);
         if (handler->msg_pos < msg_size) {
             if (!handler->msg) {
-                handler->msg = handler->cb->alloc_msg_buf(handler->opaque, msg_type, msg_size);
+                handler->msg = red_channel_client_alloc_msg_buf(handler->opaque, msg_type, msg_size);
                 if (handler->msg == NULL) {
                     spice_printerr("ERROR: channel refused to allocate buffer.");
                     handler->cb->on_error(handler->opaque);
@@ -1155,7 +1174,8 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           handler->msg + handler->msg_pos,
                                           msg_size - handler->msg_pos);
             if (bytes_read == -1) {
-                handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
+                red_channel_client_release_msg_buf(handler->opaque, msg_type, msg_size,
+                                                   handler->msg);
                 handler->cb->on_error(handler->opaque);
                 return;
             }
@@ -1172,7 +1192,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
                                           &parsed_size, &parsed_free);
         if (parsed == NULL) {
             spice_printerr("failed to parse message type %d", msg_type);
-            handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
+            red_channel_client_release_msg_buf(handler->opaque,
+                                               msg_type, msg_size,
+                                               handler->msg);
             handler->cb->on_error(handler->opaque);
             return;
         }
@@ -1182,7 +1204,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             parsed_free(parsed);
         }
         handler->msg_pos = 0;
-        handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
+        red_channel_client_release_msg_buf(handler->opaque,
+                                           msg_type, msg_size,
+                                           handler->msg);
         handler->msg = NULL;
         handler->header_pos = 0;
 
diff --git a/server/red-channel.c b/server/red-channel.c
index 7e58006..8563b96 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -226,10 +226,6 @@ red_channel_constructed(GObject *object)
     spice_assert(klass->handle_migrate_data ||
                  !(self->priv->migration_flags & SPICE_MIGRATE_NEED_DATA_TRANSFER));
 
-    self->priv->incoming_cb.alloc_msg_buf =
-        (alloc_msg_recv_buf_proc)klass->alloc_recv_buf;
-    self->priv->incoming_cb.release_msg_buf =
-        (release_msg_recv_buf_proc)klass->release_recv_buf;
     self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message;
     self->priv->incoming_cb.parser = klass->parser;
 }
diff --git a/server/red-channel.h b/server/red-channel.h
index 63a68cf..9a7669b 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -61,16 +61,11 @@ struct SpiceDataHeaderOpaque {
 
 typedef int (*handle_message_proc)(void *opaque,
                                    uint16_t type, uint32_t size, uint8_t *msg);
-typedef uint8_t *(*alloc_msg_recv_buf_proc)(void *opaque, uint16_t type, uint32_t size);
-typedef void (*release_msg_recv_buf_proc)(void *opaque,
-                                          uint16_t type, uint32_t size, uint8_t *msg);
 typedef void (*on_incoming_error_proc)(void *opaque);
 typedef void (*on_input_proc)(void *opaque, int n);
 
 typedef struct IncomingHandlerInterface {
-    alloc_msg_recv_buf_proc alloc_msg_buf;
     on_incoming_error_proc on_error; // recv error or handle_message error
-    release_msg_recv_buf_proc release_msg_buf; // for errors
     // 'parser' is optional and will not be used if NULL
     spice_parse_channel_func_t parser;
     handle_message_proc handle_message;
commit c166cf3f249d4e24f0ec3c324698f2e3fe710c8b
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Fri Dec 2 15:43:35 2016 +0100

    channel: Remove OutgoingHandlerInterface
    
    RedChannel uses OutgoingHandlerInterface to provide constant pointers to
    RedChannelClient methods. This OutgoingHandlerInterface structure is
    then used in RedChannelClient to indirectly call these methods.
    
    The OutgoingHandlerInterface abstraction is unused, ie the codebase
    only has a single implementation for it, so we can directly call the
    relevant methods and make them static instead.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <figlio at redhat.com>

diff --git a/server/red-channel-client-private.h b/server/red-channel-client-private.h
index d01cdbd..5d29f32 100644
--- a/server/red-channel-client-private.h
+++ b/server/red-channel-client-private.h
@@ -41,7 +41,6 @@ typedef struct RedChannelClientConnectivityMonitor {
 } RedChannelClientConnectivityMonitor;
 
 typedef struct OutgoingHandler {
-    OutgoingHandlerInterface *cb;
     void *opaque;
     struct iovec vec_buf[IOV_MAX];
     int vec_size;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 7201e81..615ee15 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -272,7 +272,6 @@ static void red_channel_client_constructed(GObject *object)
     self->priv->incoming.cb = red_channel_get_incoming_handler(self->priv->channel);
 
     self->priv->outgoing.opaque = self;
-    self->priv->outgoing.cb = red_channel_get_outgoing_handler(self->priv->channel);
     self->priv->outgoing.pos = 0;
     self->priv->outgoing.size = 0;
 
@@ -373,7 +372,7 @@ RedChannel* red_channel_client_get_channel(RedChannelClient *rcc)
     return rcc->priv->channel;
 }
 
-void red_channel_client_on_output(void *opaque, int n)
+static void red_channel_client_data_sent(void *opaque, int n)
 {
     RedChannelClient *rcc = opaque;
     RedChannel *channel = red_channel_client_get_channel(rcc);
@@ -394,15 +393,15 @@ void red_channel_client_on_input(void *opaque, int n)
     }
 }
 
-int red_channel_client_get_out_msg_size(void *opaque)
+static int red_channel_client_get_out_msg_size(void *opaque)
 {
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
 
     return rcc->priv->send_data.size;
 }
 
-void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
-                                        int *vec_size, int pos)
+static void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
+                                               int *vec_size, int pos)
 {
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
 
@@ -410,7 +409,7 @@ void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
                                             vec, IOV_MAX, pos);
 }
 
-void red_channel_client_on_out_block(void *opaque)
+static void red_channel_client_set_blocked(void *opaque)
 {
     SpiceCoreInterfaceInternal *core;
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
@@ -550,7 +549,7 @@ static void red_channel_client_restore_main_sender(RedChannelClient *rcc)
     rcc->priv->send_data.header.data = rcc->priv->send_data.main.header_data;
 }
 
-void red_channel_client_on_out_msg_done(void *opaque)
+static void red_channel_client_msg_sent(void *opaque)
 {
     RedChannelClient *rcc = RED_CHANNEL_CLIENT(opaque);
     int fd;
@@ -1011,33 +1010,33 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
 
     if (handler->size == 0) {
         handler->vec = handler->vec_buf;
-        handler->size = handler->cb->get_msg_size(handler->opaque);
+        handler->size = red_channel_client_get_out_msg_size(handler->opaque);
         if (!handler->size) {  // nothing to be sent
             return;
         }
     }
 
     for (;;) {
-        handler->cb->prepare(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
+        red_channel_client_prepare_out_msg(handler->opaque, handler->vec, &handler->vec_size, handler->pos);
         n = reds_stream_writev(stream, handler->vec, handler->vec_size);
         if (n == -1) {
             switch (errno) {
             case EAGAIN:
-                handler->cb->on_block(handler->opaque);
+                red_channel_client_set_blocked(handler->opaque);
                 return;
             case EINTR:
                 continue;
             case EPIPE:
-                handler->cb->on_error(handler->opaque);
+                red_channel_client_disconnect(handler->opaque);
                 return;
             default:
                 spice_printerr("%s", strerror(errno));
-                handler->cb->on_error(handler->opaque);
+                red_channel_client_disconnect(handler->opaque);
                 return;
             }
         } else {
             handler->pos += n;
-            handler->cb->on_output(handler->opaque, n);
+            red_channel_client_data_sent(handler->opaque, n);
             if (handler->pos == handler->size) { // finished writing data
                 /* reset handler before calling on_msg_done, since it
                  * can trigger another call to red_peer_handle_outgoing (when
@@ -1045,7 +1044,7 @@ static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handle
                 handler->vec = handler->vec_buf;
                 handler->pos = 0;
                 handler->size = 0;
-                handler->cb->on_msg_done(handler->opaque);
+                red_channel_client_msg_sent(handler->opaque);
                 return;
             }
         }
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index d54e7dd..9e2bf73 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -175,13 +175,7 @@ void red_channel_client_disconnect_if_pending_send(RedChannelClient *rcc);
 
 RedChannel* red_channel_client_get_channel(RedChannelClient *rcc);
 
-void red_channel_client_on_output(void *opaque, int n);
 void red_channel_client_on_input(void *opaque, int n);
-int red_channel_client_get_out_msg_size(void *opaque);
-void red_channel_client_prepare_out_msg(void *opaque, struct iovec *vec,
-                                             int *vec_size, int pos);
-void red_channel_client_on_out_block(void *opaque);
-void red_channel_client_on_out_msg_done(void *opaque);
 
 void red_channel_client_semi_seamless_migration_complete(RedChannelClient *rcc);
 void red_channel_client_init_outgoing_messages_window(RedChannelClient *rcc);
diff --git a/server/red-channel.c b/server/red-channel.c
index 14f4608..7e58006 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -93,7 +93,6 @@ struct RedChannelPrivate
 
     void *data;
 
-    OutgoingHandlerInterface outgoing_cb;
     IncomingHandlerInterface incoming_cb;
 
     ClientCbs client_cbs;
@@ -334,13 +333,6 @@ red_channel_init(RedChannel *self)
     self->priv->incoming_cb.on_error =
         (on_incoming_error_proc)red_channel_client_default_peer_on_error;
     self->priv->incoming_cb.on_input = red_channel_client_on_input;
-    self->priv->outgoing_cb.get_msg_size = red_channel_client_get_out_msg_size;
-    self->priv->outgoing_cb.prepare = red_channel_client_prepare_out_msg;
-    self->priv->outgoing_cb.on_block = red_channel_client_on_out_block;
-    self->priv->outgoing_cb.on_error =
-        (on_outgoing_error_proc)red_channel_client_default_peer_on_error;
-    self->priv->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
-    self->priv->outgoing_cb.on_output = red_channel_client_on_output;
 
     self->priv->client_cbs.connect = red_channel_client_default_connect;
     self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
@@ -791,11 +783,6 @@ IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self)
     return &self->priv->incoming_cb;
 }
 
-OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self)
-{
-    return &self->priv->outgoing_cb;
-}
-
 void red_channel_reset_thread_id(RedChannel *self)
 {
     self->priv->thread_id = pthread_self();
diff --git a/server/red-channel.h b/server/red-channel.h
index 83382b6..63a68cf 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -77,23 +77,6 @@ typedef struct IncomingHandlerInterface {
     on_input_proc on_input;
 } IncomingHandlerInterface;
 
-typedef int (*get_outgoing_msg_size_proc)(void *opaque);
-typedef void (*prepare_outgoing_proc)(void *opaque, struct iovec *vec, int *vec_size, int pos);
-typedef void (*on_outgoing_error_proc)(void *opaque);
-typedef void (*on_outgoing_block_proc)(void *opaque);
-typedef void (*on_outgoing_msg_done_proc)(void *opaque);
-typedef void (*on_output_proc)(void *opaque, int n);
-
-typedef struct OutgoingHandlerInterface {
-    get_outgoing_msg_size_proc get_msg_size;
-    prepare_outgoing_proc prepare;
-    on_outgoing_error_proc on_error;
-    on_outgoing_block_proc on_block;
-    on_outgoing_msg_done_proc on_msg_done;
-    on_output_proc on_output;
-} OutgoingHandlerInterface;
-/* Red Channel interface */
-
 typedef struct RedChannel RedChannel;
 typedef struct RedChannelClient RedChannelClient;
 typedef struct RedClient RedClient;
@@ -301,10 +284,9 @@ void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem
 void red_channel_reset_thread_id(RedChannel *self);
 StatNodeRef red_channel_get_stat_node(RedChannel *channel);
 
-/* FIXME: do these even need to be in RedChannel? It's really only used in
+/* FIXME: does this even need to be in RedChannel? It's really only used in
  * RedChannelClient. Needs refactoring */
 IncomingHandlerInterface* red_channel_get_incoming_handler(RedChannel *self);
-OutgoingHandlerInterface* red_channel_get_outgoing_handler(RedChannel *self);
 
 const RedChannelCapabilities* red_channel_get_local_capabilities(RedChannel *self);
 
commit a5471ea9b2e4fafac1792fe1e8c4ab4af23e39c0
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Nov 30 09:18:11 2016 +0100

    channel: Rework red_channel_on_output a bit
    
    Have the RedChannelClient callback call into a RedChannel callback
    rather than doing the opposite. This will be useful in some subsequent
    refactoring of this code.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 52dee70..7201e81 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -376,10 +376,13 @@ RedChannel* red_channel_client_get_channel(RedChannelClient *rcc)
 void red_channel_client_on_output(void *opaque, int n)
 {
     RedChannelClient *rcc = opaque;
+    RedChannel *channel = red_channel_client_get_channel(rcc);
 
     if (rcc->priv->connectivity_monitor.timer) {
         rcc->priv->connectivity_monitor.out_bytes += n;
     }
+    /* TODO: use a signal rather than a hardcoded call to a RedChannel callback? */
+    red_channel_on_output(channel, n);
 }
 
 void red_channel_client_on_input(void *opaque, int n)
diff --git a/server/red-channel.c b/server/red-channel.c
index e09ba97..14f4608 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -204,14 +204,9 @@ static void red_channel_client_default_peer_on_error(RedChannelClient *rcc)
     red_channel_client_disconnect(rcc);
 }
 
-static void red_channel_on_output(void *opaque, int n)
+void red_channel_on_output(RedChannel *self, int n)
 {
-    RedChannelClient *rcc G_GNUC_UNUSED;
-    RedChannel *self G_GNUC_UNUSED;
-
-    red_channel_client_on_output(opaque, n);
 #ifdef RED_STATISTICS
-    self = red_channel_client_get_channel((RedChannelClient *)opaque);
     stat_inc_counter(self->priv->reds, self->priv->out_bytes_counter, n);
 #endif
 }
@@ -345,7 +340,7 @@ red_channel_init(RedChannel *self)
     self->priv->outgoing_cb.on_error =
         (on_outgoing_error_proc)red_channel_client_default_peer_on_error;
     self->priv->outgoing_cb.on_msg_done = red_channel_client_on_out_msg_done;
-    self->priv->outgoing_cb.on_output = red_channel_on_output;
+    self->priv->outgoing_cb.on_output = red_channel_client_on_output;
 
     self->priv->client_cbs.connect = red_channel_client_default_connect;
     self->priv->client_cbs.disconnect = red_channel_client_default_disconnect;
diff --git a/server/red-channel.h b/server/red-channel.h
index 86f2458..83382b6 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -296,6 +296,7 @@ SpiceCoreInterfaceInternal* red_channel_get_core_interface(RedChannel *channel);
 /* channel callback function */
 int red_channel_config_socket(RedChannel *self, RedChannelClient *rcc);
 void red_channel_on_disconnect(RedChannel *self, RedChannelClient *rcc);
+void red_channel_on_output(RedChannel *self, int n);
 void red_channel_send_item(RedChannel *self, RedChannelClient *rcc, RedPipeItem *item);
 void red_channel_reset_thread_id(RedChannel *self);
 StatNodeRef red_channel_get_stat_node(RedChannel *channel);
commit 03ab89341236b58e05bcfc1fd28dfc982b25e783
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Mon Feb 13 12:28:53 2017 +0100

    channel: Remove RedChannel::handle_parsed
    
    red_channel_client_parse() currently does roughly:
    
    if (klass->parser) {
        parsed = klass->parser(msg, msg_size, &parsed_size);
        klass->handle_parsed(rcc, parsed_size, msg_type, parsed);
    } else {
        klass->handle_message(rcc, msg_type, msg, msg_size);
    }
    
    The handle_parsed implementation expects a void * 'parsed' argument,
    which will then be cast to the correct type. There is not really a need
    to provide distinct handle_parsed/handle_message vfuncs, instead we can
    say that if a RedChannel subclass provides a 'parser' vfunc, then it's
    'handle_message' vfunc will be called with the parsed message, otherwise
    it will be called with unparsed data (ie what handle_message currently
    expects).
    
    This makes the code slightly easier to follow as messages will always be
    handled by the same vfunc.
    
    Signed-off-by: Christophe Fergeau <cfergeau at redhat.com>
    Acked-by: Frediano Ziglio <fziglio at redhat.com>

diff --git a/server/cursor-channel.c b/server/cursor-channel.c
index b3cbb96..4fe3f8d 100644
--- a/server/cursor-channel.c
+++ b/server/cursor-channel.c
@@ -448,7 +448,7 @@ cursor_channel_class_init(CursorChannelClass *klass)
     object_class->finalize = cursor_channel_finalize;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_CURSOR, NULL);
-    channel_class->handle_parsed = red_channel_client_handle_message;
+    channel_class->handle_message = red_channel_client_handle_message;
 
     channel_class->on_disconnect =  cursor_channel_client_on_disconnect;
     channel_class->send_item = cursor_channel_send_item;
diff --git a/server/dcc.c b/server/dcc.c
index afe37b1..cf9431a 100644
--- a/server/dcc.c
+++ b/server/dcc.c
@@ -1121,7 +1121,7 @@ static int dcc_handle_gl_draw_done(DisplayChannelClient *dcc)
     return TRUE;
 }
 
-int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void *msg)
+int dcc_handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *msg)
 {
     DisplayChannelClient *dcc = DISPLAY_CHANNEL_CLIENT(rcc);
 
@@ -1136,7 +1136,7 @@ int dcc_handle_message(RedChannelClient *rcc, uint32_t size, uint16_t type, void
     case SPICE_MSGC_DISPLAY_GL_DRAW_DONE:
         return dcc_handle_gl_draw_done(dcc);
     default:
-        return red_channel_client_handle_message(rcc, size, type, msg);
+        return red_channel_client_handle_message(rcc, type, size, msg);
     }
 }
 
diff --git a/server/dcc.h b/server/dcc.h
index 6fb468d..ebdbb8d 100644
--- a/server/dcc.h
+++ b/server/dcc.h
@@ -144,8 +144,8 @@ DisplayChannelClient*      dcc_new                                   (DisplayCha
 void                       dcc_start                                 (DisplayChannelClient *dcc);
 void                       dcc_stop                                  (DisplayChannelClient *dcc);
 int                        dcc_handle_message                        (RedChannelClient *rcc,
-                                                                      uint32_t size,
-                                                                      uint16_t type, void *msg);
+                                                                      uint16_t type,
+                                                                      uint32_t size, void *msg);
 int                        dcc_handle_migrate_data                   (DisplayChannelClient *dcc,
                                                                       uint32_t size, void *message);
 void                       dcc_push_monitors_config                  (DisplayChannelClient *dcc);
diff --git a/server/display-channel.c b/server/display-channel.c
index 7d3c6e4..9a9385f 100644
--- a/server/display-channel.c
+++ b/server/display-channel.c
@@ -2229,7 +2229,7 @@ display_channel_class_init(DisplayChannelClass *klass)
     object_class->finalize = display_channel_finalize;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_DISPLAY, NULL);
-    channel_class->handle_parsed = dcc_handle_message;
+    channel_class->handle_message = dcc_handle_message;
 
     channel_class->on_disconnect = on_disconnect;
     channel_class->send_item = dcc_send_item;
diff --git a/server/inputs-channel.c b/server/inputs-channel.c
index f105b4d..3672d7e 100644
--- a/server/inputs-channel.c
+++ b/server/inputs-channel.c
@@ -279,8 +279,8 @@ static void inputs_channel_send_item(RedChannelClient *rcc, RedPipeItem *base)
     red_channel_client_begin_send_message(rcc);
 }
 
-static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
-                                        void *message)
+static int inputs_channel_handle_message(RedChannelClient *rcc, uint16_t type,
+                                         uint32_t size, void *message)
 {
     InputsChannel *inputs_channel = INPUTS_CHANNEL(red_channel_client_get_channel(rcc));
     InputsChannelClient *icc = INPUTS_CHANNEL_CLIENT(rcc);
@@ -436,7 +436,7 @@ static int inputs_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, ui
     case SPICE_MSGC_DISCONNECTING:
         break;
     default:
-        return red_channel_client_handle_message(rcc, size, type, message);
+        return red_channel_client_handle_message(rcc, type, size, message);
     }
     return TRUE;
 }
@@ -646,7 +646,7 @@ inputs_channel_class_init(InputsChannelClass *klass)
     object_class->finalize = inputs_channel_finalize;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
-    channel_class->handle_parsed = inputs_channel_handle_parsed;
+    channel_class->handle_message = inputs_channel_handle_message;
 
     /* channel callbacks */
     channel_class->config_socket = inputs_channel_config_socket;
diff --git a/server/main-channel-client.c b/server/main-channel-client.c
index 94150e6..6aace29 100644
--- a/server/main-channel-client.c
+++ b/server/main-channel-client.c
@@ -486,7 +486,7 @@ void main_channel_client_handle_pong(MainChannelClient *mcc, SpiceMsgPing *ping,
         /*
          * channel client monitors the connectivity using ping-pong messages
          */
-        red_channel_client_handle_message(rcc, size, SPICE_MSGC_PONG, ping);
+        red_channel_client_handle_message(rcc, SPICE_MSGC_PONG, size, ping);
         return;
     }
 
diff --git a/server/main-channel.c b/server/main-channel.c
index 1124506..2d32444 100644
--- a/server/main-channel.c
+++ b/server/main-channel.c
@@ -179,8 +179,8 @@ void main_channel_migrate_switch(MainChannel *main_chan, RedsMigSpice *mig_targe
     red_channel_pipes_add_type(RED_CHANNEL(main_chan), RED_PIPE_ITEM_TYPE_MAIN_MIGRATE_SWITCH_HOST);
 }
 
-static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type,
-                                      void *message)
+static int main_channel_handle_message(RedChannelClient *rcc, uint16_t type,
+                                       uint32_t size, void *message)
 {
     RedChannel *channel = red_channel_client_get_channel(rcc);
     MainChannel *main_chan = MAIN_CHANNEL(channel);
@@ -243,7 +243,7 @@ static int main_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint
         main_channel_client_handle_migrate_end(mcc);
         break;
     default:
-        return red_channel_client_handle_message(rcc, size, type, message);
+        return red_channel_client_handle_message(rcc, type, size, message);
     }
     return TRUE;
 }
@@ -352,7 +352,7 @@ main_channel_class_init(MainChannelClass *klass)
     object_class->constructed = main_channel_constructed;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
-    channel_class->handle_parsed = main_channel_handle_parsed;
+    channel_class->handle_message = main_channel_handle_message;
 
     /* channel callbacks */
     channel_class->config_socket = main_channel_config_socket;
diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index 06fb8a8..52dee70 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -1082,6 +1082,24 @@ static int red_peer_receive(RedsStream *stream, uint8_t *buf, uint32_t size)
     return pos - buf;
 }
 
+static uint8_t *red_channel_client_parse(IncomingHandler *handler, uint8_t *message, size_t message_size,
+                                         uint16_t message_type,
+                                         size_t *size_out, message_destructor_t *free_message)
+{
+    uint8_t *parsed_message;
+
+    if (handler->cb->parser) {
+        parsed_message = handler->cb->parser(message, message + message_size, message_type,
+                                             SPICE_VERSION_MINOR, size_out, free_message);
+    } else {
+        parsed_message = message;
+        *size_out = message_size;
+        *free_message = NULL;
+    }
+
+    return parsed_message;
+}
+
 // TODO: this implementation, as opposed to the old implementation in red_worker,
 // 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
@@ -1100,6 +1118,9 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
 
     for (;;) {
         int ret_handle;
+        uint8_t *parsed;
+        size_t parsed_size;
+        message_destructor_t parsed_free = NULL;
         if (handler->header_pos < handler->header.header_size) {
             bytes_read = red_peer_receive(stream,
                                           handler->header.data + handler->header_pos,
@@ -1143,26 +1164,20 @@ static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handle
             }
         }
 
-        if (handler->cb->parser) {
-            uint8_t *parsed;
-            size_t parsed_size;
-            message_destructor_t parsed_free;
-
-            parsed = handler->cb->parser(handler->msg,
-                handler->msg + msg_size, msg_type,
-                SPICE_VERSION_MINOR, &parsed_size, &parsed_free);
-            if (parsed == NULL) {
-                spice_printerr("failed to parse message type %d", msg_type);
-                handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
-                handler->cb->on_error(handler->opaque);
-                return;
-            }
-            ret_handle = handler->cb->handle_parsed(handler->opaque, parsed_size,
-                                                    msg_type, parsed);
+        parsed = red_channel_client_parse(handler,
+                                          handler->msg, msg_size,
+                                          msg_type,
+                                          &parsed_size, &parsed_free);
+        if (parsed == NULL) {
+            spice_printerr("failed to parse message type %d", msg_type);
+            handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
+            handler->cb->on_error(handler->opaque);
+            return;
+        }
+        ret_handle = handler->cb->handle_message(handler->opaque, msg_type,
+                                                 parsed_size, parsed);
+        if (parsed_free != NULL) {
             parsed_free(parsed);
-        } else {
-            ret_handle = handler->cb->handle_message(handler->opaque, msg_type, msg_size,
-                                                     handler->msg);
         }
         handler->msg_pos = 0;
         handler->cb->release_msg_buf(handler->opaque, msg_type, msg_size, handler->msg);
@@ -1343,8 +1358,8 @@ static void red_channel_client_handle_migrate_data(RedChannelClient *rcc,
 }
 
 
-int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
-                                      uint16_t type, void *message)
+int red_channel_client_handle_message(RedChannelClient *rcc, uint16_t type,
+                                      uint32_t size, void *message)
 {
     switch (type) {
     case SPICE_MSGC_ACK_SYNC:
diff --git a/server/red-channel-client.h b/server/red-channel-client.h
index fada609..d54e7dd 100644
--- a/server/red-channel-client.h
+++ b/server/red-channel-client.h
@@ -86,8 +86,8 @@ int red_channel_client_test_remote_cap(RedChannelClient *rcc, uint32_t cap);
  * It should be followed by some way to guarantee a disconnection. */
 void red_channel_client_shutdown(RedChannelClient *rcc);
 /* handles general channel msgs from the client */
-int red_channel_client_handle_message(RedChannelClient *rcc, uint32_t size,
-                                      uint16_t type, void *message);
+int red_channel_client_handle_message(RedChannelClient *rcc, uint16_t type,
+                                      uint32_t size, void *message);
 /* when preparing send_data: should call init and then use marshaller */
 void red_channel_client_init_send_data(RedChannelClient *rcc, uint16_t msg_type);
 
diff --git a/server/red-channel.c b/server/red-channel.c
index f2a35f3..e09ba97 100644
--- a/server/red-channel.c
+++ b/server/red-channel.c
@@ -237,7 +237,6 @@ red_channel_constructed(GObject *object)
     self->priv->incoming_cb.release_msg_buf =
         (release_msg_recv_buf_proc)klass->release_recv_buf;
     self->priv->incoming_cb.handle_message = (handle_message_proc)klass->handle_message;
-    self->priv->incoming_cb.handle_parsed = (handle_parsed_proc)klass->handle_parsed;
     self->priv->incoming_cb.parser = klass->parser;
 }
 
diff --git a/server/red-channel.h b/server/red-channel.h
index 4430d0b..86f2458 100644
--- a/server/red-channel.h
+++ b/server/red-channel.h
@@ -61,7 +61,6 @@ struct SpiceDataHeaderOpaque {
 
 typedef int (*handle_message_proc)(void *opaque,
                                    uint16_t type, uint32_t size, uint8_t *msg);
-typedef int (*handle_parsed_proc)(void *opaque, uint32_t size, uint16_t type, void *message);
 typedef uint8_t *(*alloc_msg_recv_buf_proc)(void *opaque, uint16_t type, uint32_t size);
 typedef void (*release_msg_recv_buf_proc)(void *opaque,
                                           uint16_t type, uint32_t size, uint8_t *msg);
@@ -69,13 +68,12 @@ typedef void (*on_incoming_error_proc)(void *opaque);
 typedef void (*on_input_proc)(void *opaque, int n);
 
 typedef struct IncomingHandlerInterface {
-    handle_message_proc handle_message;
     alloc_msg_recv_buf_proc alloc_msg_buf;
     on_incoming_error_proc on_error; // recv error or handle_message error
     release_msg_recv_buf_proc release_msg_buf; // for errors
-    // The following is an optional alternative to handle_message, used if not null
+    // 'parser' is optional and will not be used if NULL
     spice_parse_channel_func_t parser;
-    handle_parsed_proc handle_parsed;
+    handle_message_proc handle_message;
     on_input_proc on_input;
 } IncomingHandlerInterface;
 
@@ -103,10 +101,8 @@ typedef struct MainChannelClient MainChannelClient;
 
 typedef uint8_t *(*channel_alloc_msg_recv_buf_proc)(RedChannelClient *channel,
                                                     uint16_t type, uint32_t size);
-typedef int (*channel_handle_parsed_proc)(RedChannelClient *rcc, uint32_t size, uint16_t type,
-                                        void *message);
-typedef int (*channel_handle_message_proc)(RedChannelClient *rcc,
-                                           uint16_t type, uint32_t size, uint8_t *msg);
+typedef int (*channel_handle_message_proc)(RedChannelClient *rcc, uint16_t type,
+                                           uint32_t size, void *msg);
 typedef void (*channel_release_msg_recv_buf_proc)(RedChannelClient *channel,
                                                   uint16_t type, uint32_t size, uint8_t *msg);
 typedef void (*channel_disconnect_proc)(RedChannelClient *rcc);
@@ -166,11 +162,14 @@ struct RedChannelClass
 {
     GObjectClass parent_class;
 
-    /* subclasses must implement either handle_message(), or both parser() and
-     * handle_parsed() */
-    channel_handle_message_proc handle_message;
+    /* subclasses must implement handle_message() and optionally parser().
+     * If parser() is implemented, then handle_message() will get passed the
+     * parsed message as its 'msg' argument, otherwise it will be passed
+     * the raw data. In both cases, the 'size' argument is the length of 'msg'
+     * in bytes
+     */
     spice_parse_channel_func_t parser;
-    channel_handle_parsed_proc handle_parsed;
+    channel_handle_message_proc handle_message;
 
     // TODO: add ASSERTS for thread_id  in client and channel calls
     /*
diff --git a/server/smartcard-channel-client.c b/server/smartcard-channel-client.c
index 668a1fb..6234844 100644
--- a/server/smartcard-channel-client.c
+++ b/server/smartcard-channel-client.c
@@ -295,15 +295,16 @@ static void smartcard_channel_client_write_to_reader(SmartCardChannelClient *scc
 int smartcard_channel_client_handle_message(RedChannelClient *rcc,
                                             uint16_t type,
                                             uint32_t size,
-                                            uint8_t *msg)
+                                            void *message)
 {
-    VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
+    uint8_t *msg = message;
+    VSCMsgHeader* vheader = message;
     SmartCardChannelClient *scc = SMARTCARD_CHANNEL_CLIENT(rcc);
 
     if (type != SPICE_MSGC_SMARTCARD_DATA) {
         /* Handles seamless migration protocol. Also handles ack's,
          * spicy sends them while spicec does not */
-        return red_channel_client_handle_message(rcc, size, type, msg);
+        return red_channel_client_handle_message(rcc, type, size, msg);
     }
 
     spice_assert(size == vheader->length + sizeof(VSCMsgHeader));
diff --git a/server/smartcard-channel-client.h b/server/smartcard-channel-client.h
index db29e20..9350d7a 100644
--- a/server/smartcard-channel-client.h
+++ b/server/smartcard-channel-client.h
@@ -86,7 +86,7 @@ void smartcard_channel_client_send_error(RedChannelClient *rcc,
 int smartcard_channel_client_handle_message(RedChannelClient *rcc,
                                             uint16_t type,
                                             uint32_t size,
-                                            uint8_t *msg);
+                                            void *msg);
 
 int smartcard_channel_client_handle_migrate_data(RedChannelClient *rcc,
                                                  uint32_t size,
diff --git a/server/sound.c b/server/sound.c
index 7c36174..68aa191 100644
--- a/server/sound.c
+++ b/server/sound.c
@@ -320,7 +320,7 @@ static int snd_record_handle_write(RecordChannelClient *record_client, size_t si
 }
 
 static int
-record_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type, void *message)
+record_channel_handle_message(RedChannelClient *rcc, uint16_t type, uint32_t size, void *message)
 {
     RecordChannelClient *record_client = RECORD_CHANNEL_CLIENT(rcc);
 
@@ -357,7 +357,7 @@ record_channel_handle_parsed(RedChannelClient *rcc, uint32_t size, uint16_t type
         break;
     }
     default:
-        return red_channel_client_handle_message(rcc, size, type, message);
+        return red_channel_client_handle_message(rcc, type, size, message);
     }
     return TRUE;
 }
@@ -1413,7 +1413,7 @@ playback_channel_class_init(PlaybackChannelClass *klass)
     object_class->constructed = playback_channel_constructed;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_PLAYBACK, NULL);
-    channel_class->handle_parsed = red_channel_client_handle_message;
+    channel_class->handle_message = red_channel_client_handle_message;
     channel_class->send_item = playback_channel_send_item;
 }
 
@@ -1463,7 +1463,7 @@ record_channel_class_init(RecordChannelClass *klass)
     object_class->constructed = record_channel_constructed;
 
     channel_class->parser = spice_get_client_channel_parser(SPICE_CHANNEL_RECORD, NULL);
-    channel_class->handle_parsed = record_channel_handle_parsed;
+    channel_class->handle_message = record_channel_handle_message;
     channel_class->send_item = record_channel_send_item;
 }
 
diff --git a/server/spicevmc.c b/server/spicevmc.c
index 9bcbada..679ea9d 100644
--- a/server/spicevmc.c
+++ b/server/spicevmc.c
@@ -550,10 +550,10 @@ static int handle_compressed_msg(RedVmcChannel *channel, RedChannelClient *rcc,
     return TRUE;
 }
 
-static int spicevmc_red_channel_client_handle_message_parsed(RedChannelClient *rcc,
-                                                             uint32_t size,
-                                                             uint16_t type,
-                                                             void *msg)
+static int spicevmc_red_channel_client_handle_message(RedChannelClient *rcc,
+                                                      uint16_t type,
+                                                      uint32_t size,
+                                                      void *msg)
 {
     /* NOTE: *msg free by free() (when cb to spicevmc_red_channel_release_msg_rcv_buf
      * with the compressed msg type) */
@@ -582,7 +582,7 @@ static int spicevmc_red_channel_client_handle_message_parsed(RedChannelClient *r
             sif->event(channel->chardev_sin, *(uint8_t*)msg);
         break;
     default:
-        return red_channel_client_handle_message(rcc, size, type, msg);
+        return red_channel_client_handle_message(rcc, type, size, msg);
     }
 
     return TRUE;
@@ -732,7 +732,7 @@ red_vmc_channel_class_init(RedVmcChannelClass *klass)
     object_class->constructed = red_vmc_channel_constructed;
     object_class->finalize = red_vmc_channel_finalize;
 
-    channel_class->handle_parsed = spicevmc_red_channel_client_handle_message_parsed;
+    channel_class->handle_message = spicevmc_red_channel_client_handle_message;
 
     channel_class->config_socket = spicevmc_red_channel_client_config_socket;
     channel_class->on_disconnect = spicevmc_red_channel_client_on_disconnect;


More information about the Spice-commits mailing list