[Spice-commits] Branch '0.8' - 75 commits - client/application.cpp client/application.h client/cmd_line_parser.cpp client/cmd_line_parser.h client/display_channel.cpp client/gui client/Makefile.am client/red_client.cpp client/red_client.h client/red_peer.cpp client/red_peer.h client/screen.cpp client/screen.h client/smartcard_channel.cpp client/smartcard_channel.h client/windows client/x11 client/zlib_decoder.cpp common/canvas_base.h common/canvas_utils.h common/draw.h common/gdi_canvas.c common/gdi_canvas.h common/gl_canvas.c common/gl_canvas.h common/glc.c common/glc.h common/gl_utils.h common/lines.h common/lz_common.h common/lz.h common/marshaller.h common/mem.c common/mem.h common/messages.h common/mutex.h common/ogl_ctx.h common/pixman_utils.c common/pixman_utils.h common/quic.c common/quic_config.h common/quic.h common/rect.h common/region.h common/ring.h common/rop3.c common/rop3.h common/sw_canvas.c common/sw_canvas.h configure.ac Makefile.am NEWS python_modules/codegen.py python_modules/spice_parser.py server/char_device.h server/Makefile.am server/red_channel.c server/red_channel.h server/red_dispatcher.c server/red_dispatcher.h server/red_parse_qxl.c server/red_parse_qxl.h server/reds.c server/reds.h server/red_tunnel_worker.c server/red_tunnel_worker.h server/red_worker.c server/red_worker.h server/smartcard.c server/smartcard.h server/snd_worker.c server/snd_worker.h server/spice.h server/spice-server.syms server/tests server/zlib_encoder.c spice.proto

Alon Levy alon at kemper.freedesktop.org
Fri Jul 22 06:37:48 PDT 2011


 Makefile.am                      |    2 
 NEWS                             |   11 
 client/Makefile.am               |    8 
 client/application.cpp           |  101 +-
 client/application.h             |    4 
 client/cmd_line_parser.cpp       |    6 
 client/cmd_line_parser.h         |    4 
 client/display_channel.cpp       |    3 
 client/gui/gui.cpp               |   17 
 client/gui/gui.h                 |   17 
 client/gui/resource_provider.cpp |   17 
 client/gui/resource_provider.h   |   17 
 client/gui/softrenderer.cpp      |   17 
 client/gui/softrenderer.h        |   17 
 client/gui/softtexture.cpp       |   17 
 client/gui/softtexture.h         |   18 
 client/red_client.cpp            |   44 -
 client/red_client.h              |    8 
 client/red_peer.cpp              |   17 
 client/red_peer.h                |    1 
 client/screen.cpp                |    4 
 client/screen.h                  |    2 
 client/smartcard_channel.cpp     |   18 
 client/smartcard_channel.h       |   16 
 client/windows/redc.vcproj       |   12 
 client/windows/stdint.h          |    2 
 client/x11/platform.cpp          |   10 
 client/x11/red_drawable.cpp      |    2 
 client/x11/red_pixmap_gl.cpp     |    6 
 client/x11/red_window.cpp        |    6 
 client/zlib_decoder.cpp          |   16 
 common/canvas_base.h             |    8 
 common/canvas_utils.h            |    8 
 common/draw.h                    |    8 
 common/gdi_canvas.c              |    2 
 common/gdi_canvas.h              |   10 
 common/gl_canvas.c               |    2 
 common/gl_canvas.h               |   14 
 common/gl_utils.h                |    8 
 common/glc.c                     |    5 
 common/glc.h                     |    8 
 common/lines.h                   |    8 
 common/lz.h                      |    7 
 common/lz_common.h               |    7 
 common/marshaller.h              |    8 
 common/mem.c                     |   57 +
 common/mem.h                     |   25 
 common/messages.h                |   10 
 common/mutex.h                   |    9 
 common/ogl_ctx.h                 |    8 
 common/pixman_utils.c            |   10 
 common/pixman_utils.h            |    8 
 common/quic.c                    |    2 
 common/quic.h                    |   10 
 common/quic_config.h             |    8 
 common/rect.h                    |    8 
 common/region.h                  |    8 
 common/ring.h                    |    8 
 common/rop3.c                    |    2 
 common/rop3.h                    |   11 
 common/sw_canvas.c               |    2 
 common/sw_canvas.h               |   10 
 configure.ac                     |  180 +++--
 python_modules/codegen.py        |    2 
 python_modules/spice_parser.py   |   11 
 server/Makefile.am               |   11 
 server/char_device.h             |    2 
 server/red_channel.c             |   54 -
 server/red_channel.h             |    4 
 server/red_dispatcher.c          |  495 +++++++++++--
 server/red_dispatcher.h          |   13 
 server/red_parse_qxl.c           |    2 
 server/red_parse_qxl.h           |    2 
 server/red_tunnel_worker.c       |   16 
 server/red_worker.c              |  536 +++++++-------
 server/red_worker.h              |   12 
 server/reds.c                    | 1404 ++++++++++++++++++++++++++++++---------
 server/reds.h                    |   72 +-
 server/smartcard.c               |   43 +
 server/smartcard.h               |   21 
 server/snd_worker.c              |   69 -
 server/snd_worker.h              |    2 
 server/spice-server.syms         |   28 
 server/spice.h                   |   42 +
 server/tests/Makefile.am         |   16 
 server/tests/basic_event_loop.c  |    1 
 server/zlib_encoder.c            |   17 
 spice.proto                      |    2 
 88 files changed, 2852 insertions(+), 944 deletions(-)

New commits:
commit f0e5a3cb77625b32050f052a8ede7ab0ca008224
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 21 13:57:26 2011 +0300

    Release 0.8.2

diff --git a/NEWS b/NEWS
index e2cec29..ee6ceec 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,14 @@
+Major changes in 0.8.2:
+=======================
+* server: sasl support (fdo bz 34795)
+* server: support guest async io
+* server: support guest suspend and hibernate
+* server: add symbol versioning to libspice-server.so
+* server: prevent running an old spice-server with a newer qemu
+* server Bug fixes (RHBZ): 714801, 713474, 674532, 653545
+* client Bug fixes (RHBZ): 712938, 710461, 673973, 667689
+* require spice-protocol >= 0.8.1
+
 Major changes in 0.8.1:
 =======================
 * client: Fix handling of --smartcard-db option
diff --git a/configure.ac b/configure.ac
index 7081497..5828a70 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ([2.57])
 
 m4_define([SPICE_MAJOR], 0)
 m4_define([SPICE_MINOR], 8)
-m4_define([SPICE_MICRO], 1)
+m4_define([SPICE_MICRO], 2)
 
 AC_INIT(spice, [SPICE_MAJOR.SPICE_MINOR.SPICE_MICRO], [], spice)
 
diff --git a/server/spice.h b/server/spice.h
index ee19e5a..ac5a41e 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -22,7 +22,7 @@
 #include <sys/socket.h>
 #include <spice/qxl_dev.h>
 
-#define SPICE_SERVER_VERSION 0x000801 /* release 0.8.1 */
+#define SPICE_SERVER_VERSION 0x000802 /* release 0.8.2 */
 
 /* interface base type */
 
commit 0b6a49011043ecaba2f91351b67c28119ed8418a
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 21 19:52:21 2011 +0300

    distcheck: add --enable-smartcard --with-sasl

diff --git a/Makefile.am b/Makefile.am
index d90357f..0495693 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,4 +8,4 @@ DISTCLEANFILES =                                \
 
 EXTRA_DIST = spice.proto spice1.proto spice_codegen.py
 
-DISTCHECK_CONFIGURE_FLAGS=--enable-opengl --enable-gui --enable-tunnel
+DISTCHECK_CONFIGURE_FLAGS=--enable-opengl --enable-gui --enable-tunnel --enable-smartcard --with-sasl
commit aab6aa419c74cac0dda3acceb17558ebdcc85459
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 21 18:23:49 2011 +0200

    fix make distcheck

diff --git a/client/smartcard_channel.cpp b/client/smartcard_channel.cpp
index b086ad7..9770b1b 100644
--- a/client/smartcard_channel.cpp
+++ b/client/smartcard_channel.cpp
@@ -16,7 +16,7 @@
 */
 #include <spice/enums.h>
 
-#include "client/red_client.h"
+#include "red_client.h"
 #include "mutex.h"
 
 extern "C" {
diff --git a/configure.ac b/configure.ac
index 01872c5..7081497 100644
--- a/configure.ac
+++ b/configure.ac
@@ -207,7 +207,7 @@ SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
 
 if test ! -e client/generated_marshallers.cpp; then
 AC_MSG_CHECKING([for pyparsing python module])
-echo "import pyparsing" | python - >/dev/null 2&>1
+echo "import pyparsing" | python - >/dev/null 2>&1
 if test $? -ne 0 ; then
     AC_MSG_RESULT([not found])
     AC_MSG_ERROR([pyparsing python module is required to compile this package])
diff --git a/server/Makefile.am b/server/Makefile.am
index bd54aa2..93ed312 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -60,7 +60,7 @@ lib_LTLIBRARIES = libspice-server.la
 
 libspice_server_la_LDFLAGS =			\
 	-version-number $(SPICE_LT_VERSION)	\
-	-Wl,--version-script=spice-server.syms	\
+	-Wl,--version-script=$(top_srcdir)/server/spice-server.syms	\
 	-no-undefined				\
 	$(NULL)
 
@@ -150,6 +150,7 @@ libspice_serverinclude_HEADERS =		\
 EXTRA_DIST =					\
 	glz_encode_match_tmpl.c			\
 	glz_encode_tmpl.c			\
+	spice-server.syms			\
 	$(NULL)
 
 BUILT_SOURCES = $(spice_built_sources)
diff --git a/server/char_device.h b/server/char_device.h
index 486df6f..9b90b87 100644
--- a/server/char_device.h
+++ b/server/char_device.h
@@ -1,7 +1,7 @@
 #ifndef __CHAR_DEVICE_H__
 #define __CHAR_DEVICE_H__
 
-#include "server/spice-experimental.h"
+#include "spice-experimental.h"
 
 struct SpiceCharDeviceState {
     void (*wakeup)(SpiceCharDeviceInstance *sin);
diff --git a/server/reds.c b/server/reds.c
index 9f881c3..f082c53 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -60,7 +60,7 @@
 #include "demarshallers.h"
 #include "marshaller.h"
 #include "generated_marshallers.h"
-#include "server/char_device.h"
+#include "char_device.h"
 #ifdef USE_TUNNEL
 #include "red_tunnel_worker.h"
 #endif
diff --git a/server/smartcard.c b/server/smartcard.c
index 20a31f2..c75094d 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -17,9 +17,9 @@
 */
 #include <arpa/inet.h>
 
-#include "server/char_device.h"
-#include "server/red_channel.h"
-#include "server/smartcard.h"
+#include "char_device.h"
+#include "red_channel.h"
+#include "smartcard.h"
 #include "vscard_common.h"
 
 #define SMARTCARD_MAX_READERS 10
diff --git a/server/smartcard.h b/server/smartcard.h
index cc74d9b..b8731dd 100644
--- a/server/smartcard.h
+++ b/server/smartcard.h
@@ -18,7 +18,7 @@
 #ifndef __SMART_CARD_H__
 #define __SMART_CARD_H__
 
-#include "server/spice-experimental.h"
+#include "spice-experimental.h"
 
 // Maximal length of APDU
 #define APDUBufSize 270
diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index ddac420..0c3441e 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -1,8 +1,8 @@
 NULL =
 
-INCLUDES =                          \
-	-I..                            \
-	-I../../common                  \
+INCLUDES =                              \
+	-I$(top_srcdir)/server          \
+	-I$(top_srcdir)/common          \
 	$(PROTOCOL_CFLAGS)              \
 	$(SPICE_NONPKGCONFIG_CFLAGS)    \
 	$(NULL)
commit ebe1cf76d4a86fea239b425caabe64aeaa2e13e2
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 21 12:11:36 2011 +0200

    client: don't die if initial agent timeout triggers
    
    When the client connects to a spice VM, if an agent is detected,
    there will be a few messages exchanged to exchange capabilities,
    display resolutions, ... This exchange has a timeout in case
    something goes wrong. However, when it fires, the client dies.
    This commit changes this and lets the client connects to the
    guest when the timeout happens.
    rhbz #673973

diff --git a/client/red_client.cpp b/client/red_client.cpp
index 230e619..6ba834e 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -337,7 +337,9 @@ void AgentTimer::response(AbstractProcessLoop& events_loop)
 {
     Application* app = static_cast<Application*>(events_loop.get_owner());
     app->deactivate_interval_timer(this);
-    THROW_ERR(SPICEC_ERROR_CODE_AGENT_TIMEOUT, "vdagent timeout");
+
+    LOG_WARN("timeout while waiting for agent response");
+    _client->send_main_attach_channels();
 }
 
 class MainChannelLoop: public MessageHandlerImp<RedClient, SPICE_CHANNEL_MAIN> {
@@ -368,7 +370,7 @@ RedClient::RedClient(Application& application)
     , _agent_out_msg_size (0)
     , _agent_out_msg_pos (0)
     , _agent_tokens (0)
-    , _agent_timer (new AgentTimer())
+    , _agent_timer (new AgentTimer(this))
     , _agent_caps_size(0)
     , _agent_caps(NULL)
     , _migrate (*this)
diff --git a/client/red_client.h b/client/red_client.h
index 4cb8e1a..7fdba44 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -114,8 +114,14 @@ public:
     }
 };
 
+class RedClient;
+
 class AgentTimer: public Timer {
+public:
     virtual void response(AbstractProcessLoop& events_loop);
+    AgentTimer(RedClient *client) : _client(client) {};
+private:
+    RedClient *_client;
 };
 
 typedef std::map< int, RedPeer::ConnectionOptions::Type> PeerConnectionOptMap;
commit 3f8d7e59dbd94b1837503f37b5065698df3ffbc7
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 21 17:43:16 2011 +0200

    client: only send one SPICE_MSGC_MAIN_ATTACH_CHANNELS messages
    
    492f7a9b fixed unwanted timeouts during initial client startup,
    but it also caused a bad regression when connecting to
    RHEL6+agent guests: the SPICE_MSGS_MAIN_ATTACH_CHANNELS message
    was sent multiple times, once in RedClient::handle_init, then
    once again in RedClient::on_agent_announce_capabilities (which
    can even be triggered multiple times). Sending this message multiple
    times is a big NO and causes the server to close the client connection,
    and the client to die. Add a _msg_attach_message_sent boolean to
    make sure we only send this message once.
    
    rhbz #712938

diff --git a/client/red_client.cpp b/client/red_client.cpp
index 5b757b8..230e619 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -357,6 +357,7 @@ RedClient::RedClient(Application& application)
     , _auto_display_res (false)
     , _agent_reply_wait_type (-1)
     , _aborting (false)
+    , _msg_attach_channels_sent(false)
     , _agent_connected (false)
     , _agent_mon_config_sent (false)
     , _agent_disp_config_sent (false)
@@ -967,16 +968,12 @@ void RedClient::handle_init(RedPeer::InMessage* message)
         if (_auto_display_res) {
            send_agent_monitors_config();
         }
-        if (_auto_display_res || !_display_setting.is_empty()) {
-            _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT);
-        } else {
-            post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
-        }
+        _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT);
     } else {
         if (_auto_display_res || !_display_setting.is_empty()) {
             LOG_WARN("no agent running, display options have been ignored");
         }
-        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+        send_main_attach_channels();
     }
 }
 
@@ -1023,6 +1020,15 @@ void RedClient::handle_agent_disconnected(RedPeer::InMessage* message)
     _agent_connected = false;
 }
 
+void RedClient::send_main_attach_channels(void)
+{
+    if (_msg_attach_channels_sent)
+        return;
+
+    post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+    _msg_attach_channels_sent = true;
+}
+
 void RedClient::on_agent_announce_capabilities(
     VDAgentAnnounceCapabilities* caps, uint32_t msg_size)
 {
@@ -1053,7 +1059,7 @@ void RedClient::on_agent_announce_capabilities(
         if (!_display_setting.is_empty()) {
             LOG_WARN("display options have been requested, but the agent doesn't support these options");
         }
-        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+        send_main_attach_channels();
         _application.deactivate_interval_timer(*_agent_timer);
     }
 }
@@ -1073,7 +1079,7 @@ void RedClient::on_agent_reply(VDAgentReply* reply)
     case VD_AGENT_MONITORS_CONFIG:
     case VD_AGENT_DISPLAY_CONFIG:
         if (_agent_reply_wait_type == reply->type) {
-            post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+            send_main_attach_channels();
             _application.deactivate_interval_timer(*_agent_timer);
             _agent_reply_wait_type = -1;
         }
diff --git a/client/red_client.h b/client/red_client.h
index ae52d9f..4cb8e1a 100644
--- a/client/red_client.h
+++ b/client/red_client.h
@@ -262,6 +262,7 @@ public:
 
     void set_mm_time(uint32_t time);
     uint32_t get_mm_time();
+    void send_main_attach_channels(void);
 
 protected:
     virtual void on_connecting();
@@ -321,6 +322,7 @@ private:
     int _agent_reply_wait_type;
 
     bool _aborting;
+    bool _msg_attach_channels_sent;
 
     bool _agent_connected;
     bool _agent_mon_config_sent;
commit 858596bb483c495998d738f394d39104e14931be
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Thu Jul 21 10:07:57 2011 +0300

    client: fix endless recursion in rearrange_monitors, RHBZ #692976
    
    I changed RedScreen::resize not to call rearrange_monitors. Instead,
    the monitor should be configured correctly from Application, before
    calling resize.
    In addition, I made some cleanups to allow reusing rearrange_monitors code.

diff --git a/client/application.cpp b/client/application.cpp
index 810a6dd..b43cf1d 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -665,25 +665,9 @@ RedScreen* Application::get_screen(int id)
 
         if (id != 0) {
             if (_full_screen) {
-                bool capture;
-
                 mon = get_monitor(id);
-                capture = release_capture();
                 screen->set_monitor(mon);
-                prepare_monitors();
-                position_screens();
-                screen->show_full_screen();
-                if (screen->is_out_of_sync()) {
-                    _out_of_sync = true;
-                    /* If the client monitor cannot handle the guest resolution
-                       drop back to windowed mode */
-                    exit_full_screen();
-                }
-
-                if (capture) {
-                    _main_screen->activate();
-                    _main_screen->capture_mouse();
-                }
+                rearrange_monitors(false, true, screen);
             } else {
                 screen->show(false, _main_screen);
             }
@@ -771,13 +755,7 @@ void Application::on_screen_destroyed(int id, bool was_captured)
     }
     _screens[id] = NULL;
     if (reposition) {
-        bool capture = was_captured || release_capture();
-        prepare_monitors();
-        position_screens();
-        if (capture) {
-            _main_screen->activate();
-            _main_screen->capture_mouse();
-        }
+        rearrange_monitors(was_captured, false);
     }
 }
 
@@ -1388,20 +1366,51 @@ void Application::on_screen_unlocked(RedScreen& screen)
     screen.resize(SCREEN_INIT_WIDTH, SCREEN_INIT_HEIGHT);
 }
 
-bool Application::rearrange_monitors(RedScreen& screen)
+void Application::rearrange_monitors(bool force_capture,
+                                     bool enter_full_screen,
+                                     RedScreen* screen)
 {
-    if (!_full_screen) {
-        return false;
+    bool capture;
+    bool toggle_full_screen;
+
+    if (!_full_screen && !enter_full_screen) {
+        return;
+    }
+
+    toggle_full_screen = enter_full_screen && !screen;
+    capture = release_capture();
+#ifndef WIN32
+    if (toggle_full_screen) {
+        /* performing hide during resolution changes resulted in
+           missing WM_KEYUP events */
+        hide();
     }
-    bool capture = release_capture();
+#endif
     prepare_monitors();
     position_screens();
-    if (capture && _main_screen != &screen) {
-        capture = false;
-        _main_screen->activate();
+    if (enter_full_screen) {
+        // toggling to full screen
+        if (toggle_full_screen) {
+            show_full_screen();
+            _main_screen->activate();
+
+        } else { // already in full screen mode and a new screen is displayed
+            screen->show_full_screen();
+            if (screen->is_out_of_sync()) {
+                _out_of_sync = true;
+                /* If the client monitor cannot handle the guest resolution
+                    drop back to windowed mode */
+                exit_full_screen();
+            }
+        }
+    } 
+
+    if (force_capture || capture) {
+        if (!toggle_full_screen) {
+            _main_screen->activate();
+        }
         _main_screen->capture_mouse();
     }
-    return capture;
 }
 
 Monitor* Application::find_monitor(int id)
@@ -1518,20 +1527,8 @@ void Application::enter_full_screen()
 {
     LOG_INFO("");
     _changing_screens = true;
-    bool capture = release_capture();
     assign_monitors();
-#ifndef WIN32
-    /* performing hide during resolution changes resulted in
-       missing WM_KEYUP events */
-    hide();
-#endif
-    prepare_monitors();
-    position_screens();
-    show_full_screen();
-    _main_screen->activate();
-    if (capture) {
-        _main_screen->capture_mouse();
-    }
+    rearrange_monitors(false, true);
     _changing_screens = false;
     _full_screen = true;
     /* If the client monitor cannot handle the guest resolution drop back
@@ -1593,7 +1590,14 @@ bool Application::toggle_full_screen()
 
 void Application::resize_screen(RedScreen *screen, int width, int height)
 {
+    Monitor* mon;
+    if (_full_screen) {
+        if ((mon = screen->get_monitor())) {
+            mon->set_mode(width, height);
+        }
+    }
     screen->resize(width, height);
+    rearrange_monitors(false, false);
     if (screen->is_out_of_sync()) {
         _out_of_sync = true;
         /* If the client monitor cannot handle the guest resolution
diff --git a/client/application.h b/client/application.h
index 4133dfe..8079753 100644
--- a/client/application.h
+++ b/client/application.h
@@ -216,7 +216,6 @@ public:
     void on_disconnecting();
     void on_visibility_start(int screen_id);
 
-    bool rearrange_monitors(RedScreen& screen);
     void enter_full_screen();
     void exit_full_screen();
     bool toggle_full_screen();
@@ -308,6 +307,9 @@ private:
     void assign_monitors();
     void restore_monitors();
     void prepare_monitors();
+    void rearrange_monitors(bool force_capture,
+                            bool enter_full_screen,
+                            RedScreen* screen = NULL);
     void position_screens();
     void show_full_screen();
     void send_key_down(RedKey key);
diff --git a/client/screen.cpp b/client/screen.cpp
index caa5d4f..e085781 100644
--- a/client/screen.cpp
+++ b/client/screen.cpp
@@ -186,11 +186,7 @@ void RedScreen::resize(int width, int height)
     _size.y = height;
     create_composit_area();
     if (_full_screen) {
-        bool cuptur = _owner.rearrange_monitors(*this);
         __show_full_screen();
-        if (cuptur) {
-            capture_mouse();
-        }
     } else {
         bool cuptur = is_mouse_captured();
         if (cuptur) {
diff --git a/client/screen.h b/client/screen.h
index 2b40d77..e7db4ef 100644
--- a/client/screen.h
+++ b/client/screen.h
@@ -62,6 +62,8 @@ public:
     void attach_layer(ScreenLayer& layer);
     void detach_layer(ScreenLayer& layer);
     void on_layer_changed(ScreenLayer& layer);
+    /* When resizing on full screen mode, the monitor must be configured 
+     * correctly before calling resize*/
     void resize(int width, int height);
     void set_name(const std::string& name);
     uint64_t invalidate(const SpiceRect& rect, bool urgent);
commit 3bc4fd4621798674b2a6d9537180d91ccde8ee0d
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Jul 13 13:42:52 2011 +0300

    server/red_worker: send surface images to client on-demand after S3/4 wakeup
    
    When surfaces are being reloaded to the worker, we
    will send them to the client only if and when it needs them.
    (cherry picked from commit 51628f512456cd26c8c6b417be6b34f3889b33d2)

diff --git a/server/red_worker.c b/server/red_worker.c
index 1630ca2..2880f8c 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -3518,9 +3518,9 @@ static inline void red_process_drawable(RedWorker *worker, RedDrawable *drawable
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id,uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid);
+                                      void *line_0, int data_is_valid, int send_client);
 
-static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface, uint32_t group_id, int data_is_valid)
+static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface, uint32_t group_id, int loadvm)
 {
     int surface_id;
     RedSurface *red_surface;
@@ -3535,6 +3535,7 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
     case QXL_SURFACE_CMD_CREATE: {
         uint32_t height = surface->u.surface_create.height;
         int32_t stride = surface->u.surface_create.stride;
+        int reloaded_surface = loadvm || (surface->flags & QXL_SURF_FLAG_KEEP_DATA);
 
         data = surface->u.surface_create.data;
         if (stride < 0) {
@@ -3542,7 +3543,9 @@ static inline void red_process_surface(RedWorker *worker, RedSurfaceCmd *surface
         }
         red_create_surface(worker, surface_id, surface->u.surface_create.width,
                            height, stride, surface->u.surface_create.format, data,
-                           data_is_valid);
+                           reloaded_surface,
+                           // reloaded surfaces will be sent on demand
+                           !reloaded_surface);
         set_surface_release_info(worker, surface_id, 1, surface->release_info, group_id);
         break;
     }
@@ -4396,7 +4399,7 @@ static int red_process_commands(RedWorker *worker, uint32_t max_pipe_size, int *
 
             red_get_surface_cmd(&worker->mem_slots, ext_cmd.group_id,
                                 surface, ext_cmd.cmd.data);
-            red_process_surface(worker, surface, ext_cmd.group_id, 0);
+            red_process_surface(worker, surface, ext_cmd.group_id, FALSE);
             break;
         }
         default:
@@ -8655,7 +8658,7 @@ static inline void red_create_surface_item(RedWorker *worker, int surface_id)
 
 static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, uint32_t width,
                                       uint32_t height, int32_t stride, uint32_t format,
-                                      void *line_0, int data_is_valid)
+                                      void *line_0, int data_is_valid, int send_client)
 {
     uint32_t i;
     RedSurface *surface = &worker->surfaces[surface_id];
@@ -8688,7 +8691,12 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
             PANIC("drawing canvas creating failed - can`t create same type canvas");
         }
 
-        red_create_surface_item(worker, surface_id);
+        if (send_client) {
+            red_create_surface_item(worker, surface_id);
+            if (data_is_valid) {
+                red_add_surface_image(worker, surface_id);
+            }
+        }
         return;
     }
 
@@ -8698,7 +8706,12 @@ static inline void red_create_surface(RedWorker *worker, uint32_t surface_id, ui
                                                             surface->context.format, line_0);
         if (surface->context.canvas) { //no need canvas check
             worker->renderer = worker->renderers[i];
-            red_create_surface_item(worker, surface_id);
+            if (send_client) {
+                red_create_surface_item(worker, surface_id);
+                if (data_is_valid) {
+                    red_add_surface_image(worker, surface_id);
+                }
+            }
             return;
         }
     }
@@ -9836,7 +9849,7 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     }
 
     red_create_surface(worker, 0, surface.width, surface.height, surface.stride, surface.format,
-                       line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA);
+                       line_0, surface.flags & QXL_SURF_FLAG_KEEP_DATA, TRUE);
 
     if (worker->display_channel) {
         red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_MARK);
@@ -10131,7 +10144,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
                 surface_cmd = spice_new0(RedSurfaceCmd, 1);
                 red_get_surface_cmd(&worker->mem_slots, ext.group_id,
                                     surface_cmd, ext.cmd.data);
-                red_process_surface(worker, surface_cmd, ext.group_id, 1);
+                red_process_surface(worker, surface_cmd, ext.group_id, TRUE);
                 break;
             default:
                 red_printf("unhandled loadvm command type (%d)", ext.cmd.type);
commit 1024d3ec3d9ceb1b9c498a2fefdca5f7686428f0
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 7 12:22:55 2011 +0200

    server/spice.h: bump QXL_MINOR because of QXLWorker and QXLInterface changes
    (cherry picked from commit 3be08d68c01618c81e0dff6caab125a53b4c047e)

diff --git a/server/spice.h b/server/spice.h
index 95626c8..ee19e5a 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -90,7 +90,7 @@ struct SpiceCoreInterface {
 
 #define SPICE_INTERFACE_QXL "qxl"
 #define SPICE_INTERFACE_QXL_MAJOR 3
-#define SPICE_INTERFACE_QXL_MINOR 0
+#define SPICE_INTERFACE_QXL_MINOR 1
 typedef struct QXLInterface QXLInterface;
 typedef struct QXLInstance QXLInstance;
 typedef struct QXLState QXLState;
commit 32d2817ef0c7f1dba4e4c012d3b7580b55e6b3be
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 7 17:25:19 2011 +0200

    server: add QXLWorker.flush_surfaces_async for S3/S4 support
    
    This does the following, all to remove any referenced memory on the pci bars:
        flush_all_qxl_commands(worker);
        flush_all_surfaces(worker);
        red_wait_outgoing_item((RedChannel *)worker->display_channel);
        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
    
    The added api is specifically async, i.e. it calls async_complete
    when done.
    (cherry picked from commit 2a4d97fb780cf3ce2d9060751d0bec2fdc9800a9)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index cda8898..1dfb551 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -538,6 +538,18 @@ static void qxl_worker_start(QXLWorker *qxl_worker)
     red_dispatcher_start((RedDispatcher*)qxl_worker);
 }
 
+static void red_dispatcher_flush_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+}
+
 static void red_dispatcher_stop(RedDispatcher *dispatcher)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_STOP;
@@ -785,6 +797,12 @@ void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id,
     red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 1, cookie);
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie)
+{
+    red_dispatcher_flush_surfaces_async(instance->st->dispatcher, cookie);
+}
+
 void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
 {
     pthread_mutex_lock(&dispatcher->async_lock);
@@ -803,6 +821,8 @@ void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t co
         break;
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
         break;
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
+        break;
     default:
         red_printf("unexpected message");
     }
diff --git a/server/red_worker.c b/server/red_worker.c
index 3b0f461..1630ca2 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9867,18 +9867,31 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     red_cursor_reset(worker);
 }
 
-static void handle_dev_stop(RedWorker *worker)
+static void flush_all_surfaces(RedWorker *worker)
 {
     int x;
 
-    ASSERT(worker->running);
-    worker->running = FALSE;
-    red_display_clear_glz_drawables(worker->display_channel);
     for (x = 0; x < NUM_SURFACES; ++x) {
         if (worker->surfaces[x].context.canvas) {
             red_current_flush(worker, x);
         }
     }
+}
+
+static void handle_dev_flush_surfaces(RedWorker *worker)
+{
+    flush_all_qxl_commands(worker);
+    flush_all_surfaces(worker);
+    red_wait_outgoing_item((RedChannel *)worker->display_channel);
+    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+}
+
+static void handle_dev_stop(RedWorker *worker)
+{
+    ASSERT(worker->running);
+    worker->running = FALSE;
+    red_display_clear_glz_drawables(worker->display_channel);
+    flush_all_surfaces(worker);
     red_wait_outgoing_item((RedChannel *)worker->display_channel);
     red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
 }
@@ -9919,6 +9932,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
         call_async_complete = 1;
         receive_data(worker->channel, &cookie, sizeof(cookie));
         break;
@@ -10127,6 +10141,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         }
         break;
     }
+    case RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC:
+        handle_dev_flush_surfaces(worker);
+        break;
     default:
         red_error("message error");
     }
diff --git a/server/red_worker.h b/server/red_worker.h
index 961da93..e65ab19 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -75,6 +75,8 @@ enum {
     RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
     RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
+    /* suspend/windows resolution change command */
+    RED_WORKER_MESSAGE_FLUSH_SURFACES_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index 1d42782..826c562 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -79,4 +79,5 @@ global:
     spice_qxl_destroy_primary_surface_async;
     spice_qxl_create_primary_surface_async;
     spice_qxl_destroy_surface_async;
+    spice_qxl_flush_surfaces_async;
 } SPICE_SERVER_0.8.1;
diff --git a/server/spice.h b/server/spice.h
index 4085ebf..95626c8 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -153,6 +153,8 @@ void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t sur
 void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
                                 QXLDevSurfaceCreate *surface, uint64_t cookie);
 void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
+/* suspend and resolution change on windows drivers */
+void spice_qxl_flush_surfaces_async(QXLInstance *instance, uint64_t cookie);
 
 typedef struct QXLDrawArea {
     uint8_t *buf;
commit c72dc24756e57c283bf3d03e5b795c49022f901e
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 6 19:31:57 2011 +0200

    server: add QXLInterface::update_area_complete callback
    
    when update_area_async is called update_area_complete will be called with
    the surfaces dirty rectangle list.
    (cherry picked from commit b26f0532c170068e91e4946592eab2fd9d6cbae5)

diff --git a/server/red_worker.c b/server/red_worker.c
index 04c46e4..3b0f461 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9618,12 +9618,39 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_unref_channel(channel);
 }
 
+static void surface_dirty_region_to_rects(RedSurface *surface,
+                                          QXLRect *qxl_dirty_rects,
+                                          uint32_t num_dirty_rects,
+                                          int clear_dirty_region)
+{
+    QRegion *surface_dirty_region;
+    SpiceRect *dirty_rects;
+    int i;
+
+    surface_dirty_region = &surface->draw_dirty_region;
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    region_ret_rects(surface_dirty_region, dirty_rects, num_dirty_rects);
+    if (clear_dirty_region) {
+        region_clear(surface_dirty_region);
+    }
+    for (i = 0; i < num_dirty_rects; i++) {
+        qxl_dirty_rects[i].top    = dirty_rects[i].top;
+        qxl_dirty_rects[i].left   = dirty_rects[i].left;
+        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
+        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+    }
+    free(dirty_rects);
+}
+
 static inline void handle_dev_update_async(RedWorker *worker)
 {
     QXLRect qxl_rect;
     SpiceRect rect;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
+    QXLRect *qxl_dirty_rects;
+    uint32_t num_dirty_rects;
+    RedSurface *surface;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
     receive_data(worker->channel, &qxl_rect, sizeof(QXLRect));
@@ -9636,6 +9663,20 @@ static inline void handle_dev_update_async(RedWorker *worker)
 
     validate_surface(worker, surface_id);
     red_update_area(worker, &rect, surface_id);
+    if (!worker->qxl->st->qif->update_area_complete) {
+        return;
+    }
+    surface = &worker->surfaces[surface_id];
+    num_dirty_rects = pixman_region32_n_rects(&surface->draw_dirty_region);
+    if (num_dirty_rects == 0) {
+        return;
+    }
+    qxl_dirty_rects = spice_new0(QXLRect, num_dirty_rects);
+    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
+                                  clear_dirty_region);
+    worker->qxl->st->qif->update_area_complete(worker->qxl, surface_id,
+                                          qxl_dirty_rects, num_dirty_rects);
+    free(qxl_dirty_rects);
 }
 
 static inline void handle_dev_update(RedWorker *worker)
@@ -9643,12 +9684,10 @@ static inline void handle_dev_update(RedWorker *worker)
     const QXLRect *qxl_rect;
     SpiceRect *rect = spice_new0(SpiceRect, 1);
     QXLRect *qxl_dirty_rects;
-    SpiceRect *dirty_rects;
     RedSurface *surface;
     uint32_t num_dirty_rects;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
-    int i;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
     receive_data(worker->channel, &qxl_rect, sizeof(QXLRect *));
@@ -9656,7 +9695,7 @@ static inline void handle_dev_update(RedWorker *worker)
     receive_data(worker->channel, &num_dirty_rects, sizeof(uint32_t));
     receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
 
-    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    surface = &worker->surfaces[surface_id];
     red_get_rect_ptr(rect, qxl_rect);
     flush_display_commands(worker);
 
@@ -9666,19 +9705,8 @@ static inline void handle_dev_update(RedWorker *worker)
     red_update_area(worker, rect, surface_id);
     free(rect);
 
-    surface = &worker->surfaces[surface_id];
-    region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
-
-    if (clear_dirty_region) {
-        region_clear(&surface->draw_dirty_region);
-    }
-    for (i = 0; i < num_dirty_rects; i++) {
-        qxl_dirty_rects[i].top    = dirty_rects[i].top;
-        qxl_dirty_rects[i].left   = dirty_rects[i].left;
-        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
-        qxl_dirty_rects[i].right  = dirty_rects[i].right;
-    }
-    free(dirty_rects);
+    surface_dirty_region_to_rects(surface, qxl_dirty_rects, num_dirty_rects,
+                                  clear_dirty_region);
 }
 
 static inline void handle_dev_add_memslot(RedWorker *worker)
diff --git a/server/spice.h b/server/spice.h
index aa4212e..4085ebf 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -223,6 +223,9 @@ struct QXLInterface {
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
     int (*flush_resources)(QXLInstance *qin);
     void (*async_complete)(QXLInstance *qin, uint64_t cookie);
+    void (*update_area_complete)(QXLInstance *qin, uint32_t surface_id,
+                                 struct QXLRect *updated_rects,
+                                 uint32_t num_updated_rects);
 };
 
 struct QXLInstance {
commit deea6ac96b6a1b3a64854e20aeb4455668fc6d87
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Jul 19 10:50:30 2011 +0300

    server/red_worker: handle_dev_input: reuse write_ready introduced for async
    (cherry picked from commit f300de20d9fd7731881ab99c87226fa44a80695b)

diff --git a/server/red_worker.c b/server/red_worker.c
index cd7acc9..04c46e4 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9900,6 +9900,10 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
+    case RED_WORKER_MESSAGE_RESET_CURSOR:
+    case RED_WORKER_MESSAGE_RESET_IMAGE_CACHE:
+    case RED_WORKER_MESSAGE_STOP:
+    case RED_WORKER_MESSAGE_LOADVM_COMMANDS:
         write_ready = 1;
     default:
         break;
@@ -9931,13 +9935,9 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         break;
     case RED_WORKER_MESSAGE_RESET_CURSOR:
         red_cursor_reset(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     case RED_WORKER_MESSAGE_RESET_IMAGE_CACHE:
         image_cache_reset(&worker->image_cache);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
@@ -9972,8 +9972,6 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     case RED_WORKER_MESSAGE_STOP: {
         red_printf("stop");
         handle_dev_stop(worker);
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     }
     case RED_WORKER_MESSAGE_START:
@@ -10099,8 +10097,6 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
             }
             count--;
         }
-        message = RED_WORKER_MESSAGE_READY;
-        write_message(worker->channel, &message);
         break;
     }
     default:
commit b233761b91bef3461fbf0a7985ebfcbcc3e019b0
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 6 02:12:19 2011 +0200

    server: add async io support
    
    The new _ASYNC io's in qxl_dev listed at the end get six new api
    functions, and an additional callback function "async_complete". When
    the async version of a specific io is used, completion is notified by
    calling async_complete, and no READY message is written or expected by
    the dispatcher.
    
    update_area has been changed to push QXLRects to the worker thread, where
    the conversion to SpiceRect takes place.
    
    A cookie has been added to each async call to QXLWorker, and is passed back via
    async_complete.
    
    Added api:
    
    QXLWorker:
        update_area_async
        add_memslot_async
        destroy_surfaces_async
        destroy_primary_surface_async
        create_primary_surface_async
        destroy_surface_wait_async
    
    QXLInterface:
        async_complete
    
    (cherry picked from commit 096f49afbf4e83ccee80f58479b3ff05bd355660)

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 3896cd2..cda8898 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -40,7 +40,6 @@ static int num_active_workers = 0;
 
 //volatile
 
-typedef struct RedDispatcher RedDispatcher;
 struct RedDispatcher {
     QXLWorker base;
     QXLInstance *qxl;
@@ -52,6 +51,9 @@ struct RedDispatcher {
     int y_res;
     int use_hardware_cursor;
     RedDispatcher *next;
+    RedWorkerMessage async_message;
+    pthread_mutex_t  async_lock;
+    QXLDevSurfaceCreate *surface_create;
 };
 
 typedef struct RedWorkeState {
@@ -211,30 +213,49 @@ static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surfa
                                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
-    SpiceRect *dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
-    SpiceRect *area = spice_new0(SpiceRect, 1);
-    int i;
-
-    red_get_rect_ptr(area, qxl_area);
 
     write_message(dispatcher->channel, &message);
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    send_data(dispatcher->channel, &area, sizeof(SpiceRect *));
-    send_data(dispatcher->channel, &dirty_rects, sizeof(SpiceRect *));
+    send_data(dispatcher->channel, &qxl_area, sizeof(QXLRect *));
+    send_data(dispatcher->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     send_data(dispatcher->channel, &num_dirty_rects, sizeof(uint32_t));
     send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
+}
 
-    for (i = 0; i < num_dirty_rects; i++) {
-        qxl_dirty_rects[i].top    = dirty_rects[i].top;
-        qxl_dirty_rects[i].left   = dirty_rects[i].left;
-        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
-        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+static RedWorkerMessage red_dispatcher_async_start(RedDispatcher *dispatcher,
+                                                   RedWorkerMessage message)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    if (dispatcher->async_message != RED_WORKER_MESSAGE_NOP) {
+        red_printf("error: async clash. second async ignored");
+        pthread_mutex_unlock(&dispatcher->async_lock);
+        return RED_WORKER_MESSAGE_NOP;
     }
+    dispatcher->async_message = message;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    return message;
+}
+
+static void red_dispatcher_update_area_async(RedDispatcher *dispatcher,
+                                         uint32_t surface_id,
+                                         QXLRect *qxl_area,
+                                         uint32_t clear_dirty_region,
+                                         uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_UPDATE_ASYNC);
 
-    free(dirty_rects);
-    free(area);
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    send_data(dispatcher->channel, qxl_area, sizeof(QXLRect));
+    send_data(dispatcher->channel, &clear_dirty_region, sizeof(uint32_t));
 }
 
 static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
@@ -260,6 +281,19 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
     red_dispatcher_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
 }
 
+static void red_dispatcher_add_memslot_async(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot, uint64_t cookie)
+{
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                          RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC);
+
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
+    write_message(dispatcher->channel, &message);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    send_data(dispatcher->channel, mem_slot, sizeof(QXLDevMemSlot));
+}
+
 static void red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id)
 {
     RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
@@ -288,15 +322,20 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
     red_dispatcher_destroy_surfaces((RedDispatcher*)qxl_worker);
 }
 
-static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t surface_id)
+static void red_dispatcher_destroy_surfaces_async(RedDispatcher *dispatcher, uint64_t cookie)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    RedWorkerMessage message = red_dispatcher_async_start(dispatcher,
+                                                      RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC);
 
+    if (message == RED_WORKER_MESSAGE_NOP) {
+        return;
+    }
     write_message(dispatcher->channel, &message);
-    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
+    send_data(dispatcher->channel, &cookie, sizeof(cookie));
+}
 
+static void red_dispatcher_destroy_primary_surface_complete(RedDispatcher *dispatcher)
+{
     dispatcher->x_res = 0;
     dispatcher->y_res = 0;
     dispatcher->use_hardware_cursor = FALSE;
@@ -305,34 +344,86 @@ static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t s
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+static void
+red_dispatcher_destroy_primary_surface(RedDispatcher *dispatcher,
+                                       uint32_t surface_id, int async, uint64_t cookie)
 {
-    red_dispatcher_destroy_primary((RedDispatcher*)qxl_worker, surface_id);
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
+    }
+
+    write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
+    send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+    }
 }
 
-static void red_dispatcher_create_primary(RedDispatcher *dispatcher, uint32_t surface_id,
-                                      QXLDevSurfaceCreate *surface)
+static void qxl_worker_destroy_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary_surface((RedDispatcher*)qxl_worker, surface_id, 0, 0);
+}
+
+static void red_dispatcher_create_primary_surface_complete(RedDispatcher *dispatcher)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    QXLDevSurfaceCreate *surface = dispatcher->surface_create;
 
     dispatcher->x_res = surface->width;
     dispatcher->y_res = surface->height;
     dispatcher->use_hardware_cursor = surface->mouse_mode;
     dispatcher->primary_active = TRUE;
 
+    update_client_mouse_allowed();
+    dispatcher->surface_create = NULL;
+}
+
+static void
+red_dispatcher_create_primary_surface(RedDispatcher *dispatcher, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface, int async, uint64_t cookie)
+{
+    RedWorkerMessage message;
+
+    if (async) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
+    }
+    dispatcher->surface_create = surface;
+
     write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
     send_data(dispatcher->channel, surface, sizeof(QXLDevSurfaceCreate));
-    read_message(dispatcher->channel, &message);
-    ASSERT(message == RED_WORKER_MESSAGE_READY);
-
-    update_client_mouse_allowed();
+    if (!async) {
+        read_message(dispatcher->channel, &message);
+        ASSERT(message == RED_WORKER_MESSAGE_READY);
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+    }
 }
 
-static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+static void qxl_worker_create_primary_surface(QXLWorker *qxl_worker, uint32_t surface_id,
                                       QXLDevSurfaceCreate *surface)
 {
-    red_dispatcher_create_primary((RedDispatcher*)qxl_worker, surface_id, surface);
+    red_dispatcher_create_primary_surface((RedDispatcher*)qxl_worker, surface_id, surface, 0, 0);
 }
 
 static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher)
@@ -363,19 +454,36 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
     red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker);
 }
 
-static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id)
+static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id,
+                                                int async, uint64_t cookie)
 {
-    RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    RedWorkerMessage message;
+
+    if (async ) {
+        message = red_dispatcher_async_start(dispatcher,
+                                             RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC);
+        if (message == RED_WORKER_MESSAGE_NOP) {
+            return;
+        }
+    } else {
+        message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
+    }
 
     write_message(dispatcher->channel, &message);
+    if (async) {
+        send_data(dispatcher->channel, &cookie, sizeof(cookie));
+    }
     send_data(dispatcher->channel, &surface_id, sizeof(uint32_t));
+    if (async) {
+        return;
+    }
     read_message(dispatcher->channel, &message);
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
 static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
 {
-    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id);
+    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id, 0, 0);
 }
 
 static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher)
@@ -604,14 +712,14 @@ void spice_qxl_destroy_surfaces(QXLInstance *instance)
 SPICE_GNUC_VISIBLE
 void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id)
 {
-    red_dispatcher_destroy_primary(instance->st->dispatcher, surface_id);
+    red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
 void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
                                 QXLDevSurfaceCreate *surface)
 {
-    red_dispatcher_create_primary(instance->st->dispatcher, surface_id, surface);
+    red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
@@ -629,7 +737,7 @@ void spice_qxl_reset_cursor(QXLInstance *instance)
 SPICE_GNUC_VISIBLE
 void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id)
 {
-    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id);
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 0, 0);
 }
 
 SPICE_GNUC_VISIBLE
@@ -638,6 +746,71 @@ void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext,
     red_dispatcher_loadvm_commands(instance->st->dispatcher, ext, count);
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXLRect *qxl_area,
+                                 uint32_t clear_dirty_region, uint64_t cookie)
+{
+    red_dispatcher_update_area_async(instance->st->dispatcher, surface_id, qxl_area,
+                                     clear_dirty_region, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot, uint64_t cookie)
+{
+    red_dispatcher_add_memslot_async(instance->st->dispatcher, slot, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie)
+{
+    red_dispatcher_destroy_surfaces_async(instance->st->dispatcher, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie)
+{
+    red_dispatcher_destroy_primary_surface(instance->st->dispatcher, surface_id, 1, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface, uint64_t cookie)
+{
+    red_dispatcher_create_primary_surface(instance->st->dispatcher, surface_id, surface, 1, cookie);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie)
+{
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id, 1, cookie);
+}
+
+void red_dispatcher_async_complete(struct RedDispatcher *dispatcher, uint64_t cookie)
+{
+    pthread_mutex_lock(&dispatcher->async_lock);
+    switch (dispatcher->async_message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+        break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_create_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+        red_dispatcher_destroy_primary_surface_complete(dispatcher);
+        break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+        break;
+    default:
+        red_printf("unexpected message");
+    }
+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_unlock(&dispatcher->async_lock);
+    dispatcher->qxl->st->qif->async_complete(dispatcher->qxl, cookie);
+}
+
 RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
 {
     RedDispatcher *dispatcher;
@@ -670,6 +843,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     init_data.num_renderers = num_renderers;
     memcpy(init_data.renderers, renderers, sizeof(init_data.renderers));
 
+    dispatcher->async_message = RED_WORKER_MESSAGE_NOP;
+    pthread_mutex_init(&dispatcher->async_lock, NULL);
     init_data.image_compression = image_compression;
     init_data.jpeg_state = jpeg_state;
     init_data.zlib_glz_state = zlib_glz_state;
@@ -686,8 +861,8 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatcher->base.del_memslot = qxl_worker_del_memslot;
     dispatcher->base.reset_memslots = qxl_worker_reset_memslots;
     dispatcher->base.destroy_surfaces = qxl_worker_destroy_surfaces;
-    dispatcher->base.create_primary_surface = qxl_worker_create_primary;
-    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary;
+    dispatcher->base.create_primary_surface = qxl_worker_create_primary_surface;
+    dispatcher->base.destroy_primary_surface = qxl_worker_destroy_primary_surface;
 
     dispatcher->base.reset_image_cache = qxl_worker_reset_image_cache;
     dispatcher->base.reset_cursor = qxl_worker_reset_cursor;
@@ -702,6 +877,7 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     init_data.num_memslots_groups = init_info.num_memslots_groups;
     init_data.internal_groupslot_id = init_info.internal_groupslot_id;
     init_data.n_surfaces = init_info.n_surfaces;
+    init_data.dispatcher = dispatcher;
 
     num_active_workers = 1;
 
@@ -742,4 +918,3 @@ RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
     dispatchers = dispatcher;
     return dispatcher;
 }
-
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 3f3c1ae..fa347f1 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -18,7 +18,6 @@
 #ifndef _H_RED_DISPATCHER
 #define _H_RED_DISPATCHER
 
-
 struct RedDispatcher *red_dispatcher_init(QXLInstance *qxl);
 
 void red_dispatcher_set_mm_time(uint32_t);
@@ -29,5 +28,7 @@ int red_dispatcher_count(void);
 int red_dispatcher_add_renderer(const char *name);
 uint32_t red_dispatcher_qxl_ram_size(void);
 int red_dispatcher_qxl_count(void);
+void red_dispatcher_async_complete(struct RedDispatcher*, uint64_t);
+
 #endif
 
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index 380765d..653ce66 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -145,7 +145,7 @@ static void red_get_point16_ptr(SpicePoint16 *red, QXLPoint16 *qxl)
     red->y = qxl->y;
 }
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl)
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl)
 {
     red->top    = qxl->top;
     red->left   = qxl->left;
diff --git a/server/red_parse_qxl.h b/server/red_parse_qxl.h
index 5de0325..a713dcf 100644
--- a/server/red_parse_qxl.h
+++ b/server/red_parse_qxl.h
@@ -110,7 +110,7 @@ typedef struct RedCursorCmd {
     uint8_t *device_data;
 } RedCursorCmd;
 
-void red_get_rect_ptr(SpiceRect *red, QXLRect *qxl);
+void red_get_rect_ptr(SpiceRect *red, const QXLRect *qxl);
 
 void red_get_drawable(RedMemSlotInfo *slots, int group_id,
                       RedDrawable *red, QXLPHYSICAL addr, uint32_t flags);
diff --git a/server/red_worker.c b/server/red_worker.c
index 12ad74a..cd7acc9 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -57,6 +57,7 @@
 #include "demarshallers.h"
 #include "generated_marshallers.h"
 #include "zlib_encoder.h"
+#include "red_dispatcher.h"
 
 //#define COMPRESS_STAT
 //#define DUMP_BITMAP
@@ -843,6 +844,7 @@ typedef struct RedWorker {
     DisplayChannel *display_channel;
     CursorChannel *cursor_channel;
     QXLInstance *qxl;
+    RedDispatcher *dispatcher;
     int id;
     int channel;
     int running;
@@ -9616,28 +9618,53 @@ static void red_wait_pipe_item_sent(RedChannel *channel, PipeItem *item)
     red_unref_channel(channel);
 }
 
+static inline void handle_dev_update_async(RedWorker *worker)
+{
+    QXLRect qxl_rect;
+    SpiceRect rect;
+    uint32_t surface_id;
+    uint32_t clear_dirty_region;
+
+    receive_data(worker->channel, &surface_id, sizeof(uint32_t));
+    receive_data(worker->channel, &qxl_rect, sizeof(QXLRect));
+    receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
+
+    red_get_rect_ptr(&rect, &qxl_rect);
+    flush_display_commands(worker);
+
+    ASSERT(worker->running);
+
+    validate_surface(worker, surface_id);
+    red_update_area(worker, &rect, surface_id);
+}
+
 static inline void handle_dev_update(RedWorker *worker)
 {
-    RedWorkerMessage message;
-    const SpiceRect *rect;
+    const QXLRect *qxl_rect;
+    SpiceRect *rect = spice_new0(SpiceRect, 1);
+    QXLRect *qxl_dirty_rects;
     SpiceRect *dirty_rects;
     RedSurface *surface;
     uint32_t num_dirty_rects;
     uint32_t surface_id;
     uint32_t clear_dirty_region;
+    int i;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
-    receive_data(worker->channel, &rect, sizeof(SpiceRect *));
-    receive_data(worker->channel, &dirty_rects, sizeof(SpiceRect *));
+    receive_data(worker->channel, &qxl_rect, sizeof(QXLRect *));
+    receive_data(worker->channel, &qxl_dirty_rects, sizeof(QXLRect *));
     receive_data(worker->channel, &num_dirty_rects, sizeof(uint32_t));
     receive_data(worker->channel, &clear_dirty_region, sizeof(uint32_t));
 
+    dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
+    red_get_rect_ptr(rect, qxl_rect);
     flush_display_commands(worker);
 
     ASSERT(worker->running);
 
     validate_surface(worker, surface_id);
     red_update_area(worker, rect, surface_id);
+    free(rect);
 
     surface = &worker->surfaces[surface_id];
     region_ret_rects(&surface->draw_dirty_region, dirty_rects, num_dirty_rects);
@@ -9645,15 +9672,17 @@ static inline void handle_dev_update(RedWorker *worker)
     if (clear_dirty_region) {
         region_clear(&surface->draw_dirty_region);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
+    for (i = 0; i < num_dirty_rects; i++) {
+        qxl_dirty_rects[i].top    = dirty_rects[i].top;
+        qxl_dirty_rects[i].left   = dirty_rects[i].left;
+        qxl_dirty_rects[i].bottom = dirty_rects[i].bottom;
+        qxl_dirty_rects[i].right  = dirty_rects[i].right;
+    }
+    free(dirty_rects);
 }
 
-
 static inline void handle_dev_add_memslot(RedWorker *worker)
 {
-    RedWorkerMessage message;
     QXLDevMemSlot dev_slot;
 
     receive_data(worker->channel, &dev_slot, sizeof(QXLDevMemSlot));
@@ -9661,9 +9690,6 @@ static inline void handle_dev_add_memslot(RedWorker *worker)
     red_memslot_info_add_slot(&worker->mem_slots, dev_slot.slot_group_id, dev_slot.slot_id,
                               dev_slot.addr_delta, dev_slot.virt_start, dev_slot.virt_end,
                               dev_slot.generation);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_del_memslot(RedWorker *worker)
@@ -9699,7 +9725,6 @@ static inline void destroy_surface_wait(RedWorker *worker, int surface_id)
 
 static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9711,9 +9736,6 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
     if (worker->surfaces[0].context.canvas) {
         destroy_surface_wait(worker, 0);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void red_cursor_reset(RedWorker *worker)
@@ -9741,8 +9763,7 @@ static inline void red_cursor_reset(RedWorker *worker)
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
     int i;
-    RedWorkerMessage message;
-    red_printf("");
+
     flush_all_qxl_commands(worker);
     //to handle better
     for (i = 0; i < NUM_SURFACES; ++i) {
@@ -9764,14 +9785,10 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     red_display_clear_glz_drawables(worker->display_channel);
 
     red_cursor_reset(worker);
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_create_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
     QXLDevSurfaceCreate surface;
     uint8_t *line_0;
@@ -9801,14 +9818,10 @@ static inline void handle_dev_create_primary_surface(RedWorker *worker)
     if (worker->cursor_channel) {
         red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_CURSOR_INIT);
     }
-
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
 }
 
 static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 {
-    RedWorkerMessage message;
     uint32_t surface_id;
 
     receive_data(worker->channel, &surface_id, sizeof(uint32_t));
@@ -9824,20 +9837,78 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     ASSERT(!worker->surfaces[surface_id].context.canvas);
 
     red_cursor_reset(worker);
+}
 
-    message = RED_WORKER_MESSAGE_READY;
-    write_message(worker->channel, &message);
+static void handle_dev_stop(RedWorker *worker)
+{
+    int x;
+
+    ASSERT(worker->running);
+    worker->running = FALSE;
+    red_display_clear_glz_drawables(worker->display_channel);
+    for (x = 0; x < NUM_SURFACES; ++x) {
+        if (worker->surfaces[x].context.canvas) {
+            red_current_flush(worker, x);
+        }
+    }
+    red_wait_outgoing_item((RedChannel *)worker->display_channel);
+    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+}
+
+static void handle_dev_start(RedWorker *worker)
+{
+    RedChannel *cursor_red_channel = &worker->cursor_channel->base;
+    RedChannel *display_red_channel = &worker->display_channel->base;
+
+    ASSERT(!worker->running);
+    if (worker->cursor_channel) {
+        cursor_red_channel->migrate = FALSE;
+    }
+    if (worker->display_channel) {
+        display_red_channel->migrate = FALSE;
+    }
+    worker->running = TRUE;
 }
 
 static void handle_dev_input(EventListener *listener, uint32_t events)
 {
     RedWorker *worker = SPICE_CONTAINEROF(listener, RedWorker, dev_listener);
     RedWorkerMessage message;
+
     int ring_is_empty;
+    int call_async_complete = 0;
+    int write_ready = 0;
+    uint64_t cookie;
 
     read_message(worker->channel, &message);
 
+    /* for async messages we do the common work in the handler, and
+     * send a ready or call async_complete from here, hence the added switch. */
+    switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
+        call_async_complete = 1;
+        receive_data(worker->channel, &cookie, sizeof(cookie));
+        break;
+    case RED_WORKER_MESSAGE_UPDATE:
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES:
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
+        write_ready = 1;
+    default:
+        break;
+    }
+
     switch (message) {
+    case RED_WORKER_MESSAGE_UPDATE_ASYNC:
+        handle_dev_update_async(worker);
+        break;
     case RED_WORKER_MESSAGE_UPDATE:
         handle_dev_update(worker);
         break;
@@ -9868,15 +9939,19 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT:
         handle_dev_destroy_surface_wait(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_SURFACES:
         handle_dev_destroy_surfaces(worker);
         break;
+    case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE:
         handle_dev_create_primary_surface(worker);
         break;
+    case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC:
     case RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE:
         handle_dev_destroy_primary_surface(worker);
         break;
@@ -9895,33 +9970,15 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         red_disconnect_display((RedChannel *)worker->display_channel);
         break;
     case RED_WORKER_MESSAGE_STOP: {
-        int x;
-
         red_printf("stop");
-        ASSERT(worker->running);
-        worker->running = FALSE;
-        red_display_clear_glz_drawables(worker->display_channel);
-        for (x = 0; x < NUM_SURFACES; ++x) {
-            if (worker->surfaces[x].context.canvas) {
-                red_current_flush(worker, x);
-            }
-        }
-        red_wait_outgoing_item((RedChannel *)worker->display_channel);
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+        handle_dev_stop(worker);
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
     }
     case RED_WORKER_MESSAGE_START:
         red_printf("start");
-        ASSERT(!worker->running);
-        if (worker->cursor_channel) {
-            worker->cursor_channel->base.migrate = FALSE;
-        }
-        if (worker->display_channel) {
-            worker->display_channel->base.migrate = FALSE;
-        }
-        worker->running = TRUE;
+        handle_dev_start(worker);
         break;
     case RED_WORKER_MESSAGE_DISPLAY_MIGRATE:
         red_printf("migrate");
@@ -10003,6 +10060,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         receive_data(worker->channel, &worker->mouse_mode, sizeof(uint32_t));
         red_printf("mouse mode %u", worker->mouse_mode);
         break;
+    case RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC:
     case RED_WORKER_MESSAGE_ADD_MEMSLOT:
         handle_dev_add_memslot(worker);
         break;
@@ -10048,6 +10106,13 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
     default:
         red_error("message error");
     }
+    if (call_async_complete) {
+        red_dispatcher_async_complete(worker->dispatcher, cookie);
+    }
+    if (write_ready) {
+        message = RED_WORKER_MESSAGE_READY;
+        write_message(worker->channel, &message);
+    }
 }
 
 static void red_init(RedWorker *worker, WorkerInitData *init_data)
@@ -10059,6 +10124,7 @@ static void red_init(RedWorker *worker, WorkerInitData *init_data)
     ASSERT(sizeof(CursorItem) <= QXL_CURSUR_DEVICE_DATA_SIZE);
 
     memset(worker, 0, sizeof(RedWorker));
+    worker->dispatcher = init_data->dispatcher;
     worker->qxl = init_data->qxl;
     worker->id = init_data->id;
     worker->channel = init_data->channel;
diff --git a/server/red_worker.h b/server/red_worker.h
index ae2eaee..961da93 100644
--- a/server/red_worker.h
+++ b/server/red_worker.h
@@ -68,6 +68,13 @@ enum {
     RED_WORKER_MESSAGE_RESET_IMAGE_CACHE,
     RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT,
     RED_WORKER_MESSAGE_LOADVM_COMMANDS,
+    /* async commands */
+    RED_WORKER_MESSAGE_UPDATE_ASYNC,
+    RED_WORKER_MESSAGE_ADD_MEMSLOT_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACES_ASYNC,
+    RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE_ASYNC,
+    RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT_ASYNC,
 };
 
 typedef uint32_t RedWorkerMessage;
@@ -81,6 +88,8 @@ enum {
     RED_RENDERER_OGL_PIXMAP,
 };
 
+typedef struct RedDispatcher RedDispatcher;
+
 typedef struct WorkerInitData {
     struct QXLInstance *qxl;
     int id;
@@ -98,6 +107,7 @@ typedef struct WorkerInitData {
     uint8_t memslot_id_bits;
     uint8_t internal_groupslot_id;
     uint32_t n_surfaces;
+    RedDispatcher *dispatcher;
 } WorkerInitData;
 
 void *red_worker_main(void *arg);
diff --git a/server/spice-server.syms b/server/spice-server.syms
index e14bb1c..1d42782 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -73,4 +73,10 @@ global:
     spice_qxl_reset_cursor;
     spice_qxl_destroy_surface_wait;
     spice_qxl_loadvm_commands;
+    spice_qxl_update_area_async;
+    spice_qxl_add_memslot_async;
+    spice_qxl_destroy_surfaces_async;
+    spice_qxl_destroy_primary_surface_async;
+    spice_qxl_create_primary_surface_async;
+    spice_qxl_destroy_surface_async;
 } SPICE_SERVER_0.8.1;
diff --git a/server/spice.h b/server/spice.h
index 61bf886..aa4212e 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -20,6 +20,7 @@
 
 #include <stdint.h>
 #include <sys/socket.h>
+#include <spice/qxl_dev.h>
 
 #define SPICE_SERVER_VERSION 0x000801 /* release 0.8.1 */
 
@@ -143,6 +144,15 @@ void spice_qxl_reset_image_cache(QXLInstance *instance);
 void spice_qxl_reset_cursor(QXLInstance *instance);
 void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id);
 void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count);
+/* async versions of commands. when complete spice calls async_complete */
+void spice_qxl_update_area_async(QXLInstance *instance, uint32_t surface_id, QXLRect *qxl_area,
+                                 uint32_t clear_dirty_region, uint64_t cookie);
+void spice_qxl_add_memslot_async(QXLInstance *instance, QXLDevMemSlot *slot, uint64_t cookie);
+void spice_qxl_destroy_surfaces_async(QXLInstance *instance, uint64_t cookie);
+void spice_qxl_destroy_primary_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
+void spice_qxl_create_primary_surface_async(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface, uint64_t cookie);
+void spice_qxl_destroy_surface_async(QXLInstance *instance, uint32_t surface_id, uint64_t cookie);
 
 typedef struct QXLDrawArea {
     uint8_t *buf;
@@ -212,6 +222,7 @@ struct QXLInterface {
     int (*req_cursor_notification)(QXLInstance *qin);
     void (*notify_update)(QXLInstance *qin, uint32_t update_id);
     int (*flush_resources)(QXLInstance *qin);
+    void (*async_complete)(QXLInstance *qin, uint64_t cookie);
 };
 
 struct QXLInstance {
commit 84ff23cd2b641af4eb92f2ba83c641016db34653
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Jul 4 11:12:33 2011 +0300

    server: replace redundant code with red_cursor_reset
    
    In addition (1) make handle_dev_destroy_surfaces call red_release_cursor
    (2) call red_wait_outgoing_item(cursor_channel) only after adding msgs to pipe
    
    [3d3066b175ee2dec8e73c8c56f418a6ae98b1c26 cherry-pick with modifications]

diff --git a/server/red_worker.c b/server/red_worker.c
index 4568696..12ad74a 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -9716,6 +9716,27 @@ static inline void handle_dev_destroy_surface_wait(RedWorker *worker)
     write_message(worker->channel, &message);
 }
 
+static inline void red_cursor_reset(RedWorker *worker)
+{
+    if (worker->cursor) {
+        red_release_cursor(worker, worker->cursor);
+        worker->cursor = NULL;
+    }
+
+    worker->cursor_visible = TRUE;
+    worker->cursor_position.x = worker->cursor_position.y = 0;
+    worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
+
+    if (worker->cursor_channel) {
+        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
+        if (!worker->cursor_channel->base.migrate) {
+            red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
+        }
+        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
+        ASSERT(!worker->cursor_channel->base.send_data.item);
+    }
+}
+
 /* called upon device reset */
 static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 {
@@ -9735,15 +9756,6 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
     }
     ASSERT(ring_is_empty(&worker->streams));
 
-    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-    if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        if (!worker->cursor_channel->base.migrate) {
-            red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
-        }
-        ASSERT(!worker->cursor_channel->base.send_data.item);
-    }
-
     if (worker->display_channel) {
         red_pipe_add_type(&worker->display_channel->base, PIPE_ITEM_TYPE_INVAL_PALLET_CACHE);
         red_pipe_add_verb(&worker->display_channel->base, SPICE_MSG_DISPLAY_STREAM_DESTROY_ALL);
@@ -9751,9 +9763,7 @@ static inline void handle_dev_destroy_surfaces(RedWorker *worker)
 
     red_display_clear_glz_drawables(worker->display_channel);
 
-    worker->cursor_visible = TRUE;
-    worker->cursor_position.x = worker->cursor_position.y = 0;
-    worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
+    red_cursor_reset(worker);
 
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
@@ -9806,20 +9816,6 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
     PANIC_ON(surface_id != 0);
     PANIC_ON(!worker->surfaces[surface_id].context.canvas);
 
-    if (worker->cursor) {
-        red_release_cursor(worker, worker->cursor);
-        worker->cursor = NULL;
-    }
-
-    red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-    if (worker->cursor_channel) {
-        red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-        if (!worker->cursor_channel->base.migrate) {
-            red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
-        }
-        ASSERT(!worker->cursor_channel->base.send_data.item);
-    }
-
     flush_all_qxl_commands(worker);
     destroy_surface_wait(worker, 0);
     red_destroy_surface(worker, 0);
@@ -9827,9 +9823,7 @@ static inline void handle_dev_destroy_primary_surface(RedWorker *worker)
 
     ASSERT(!worker->surfaces[surface_id].context.canvas);
 
-    worker->cursor_visible = TRUE;
-    worker->cursor_position.x = worker->cursor_position.y = 0;
-    worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
+    red_cursor_reset(worker);
 
     message = RED_WORKER_MESSAGE_READY;
     write_message(worker->channel, &message);
@@ -9865,24 +9859,7 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
         clear_bit(RED_WORKER_PENDING_OOM, worker->pending);
         break;
     case RED_WORKER_MESSAGE_RESET_CURSOR:
-        if (worker->cursor) {
-            red_release_cursor(worker, worker->cursor);
-            worker->cursor = NULL;
-        }
-
-        red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
-        if (worker->cursor_channel) {
-            red_pipe_add_type(&worker->cursor_channel->base, PIPE_ITEM_TYPE_INVAL_CURSOR_CACHE);
-            if (!worker->cursor_channel->base.migrate) {
-                red_pipe_add_verb(&worker->cursor_channel->base, SPICE_MSG_CURSOR_RESET);
-            }
-            ASSERT(!worker->cursor_channel->base.send_data.item);
-
-            worker->cursor_visible = TRUE;
-            worker->cursor_position.x = worker->cursor_position.y = 0;
-            worker->cursor_trail_length = worker->cursor_trail_frequency = 0;
-        }
-
+        red_cursor_reset(worker);
         message = RED_WORKER_MESSAGE_READY;
         write_message(worker->channel, &message);
         break;
commit 7db7212c3a336c9499bfcd10d2affbf76bf1d6b1
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Apr 19 23:23:18 2011 +0200

    use foo(void) instead of foo() in prototypes
    
    In C, the latter isn't a prototype for a function with no arg,
    but declares a function with an undefined number of args.
    
    [picked from master with changes since no main_channel, spice_common,
     and a bunch of functions aren't there yet]

diff --git a/common/gdi_canvas.c b/common/gdi_canvas.c
index eda1529..310e388 100644
--- a/common/gdi_canvas.c
+++ b/common/gdi_canvas.c
@@ -1828,7 +1828,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
     return (SpiceCanvas *)canvas;
 }
 
-void gdi_canvas_init() //unsafe global function
+void gdi_canvas_init(void) //unsafe global function
 {
     if (!need_init) {
         return;
diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h
index 5cdffb3..86be9e1 100644
--- a/common/gdi_canvas.h
+++ b/common/gdi_canvas.h
@@ -38,7 +38,7 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
                                SpiceJpegDecoder *jpeg_decoder,
                                SpiceZlibDecoder *zlib_decoder);
 
-void gdi_canvas_init();
+void gdi_canvas_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/common/gl_canvas.c b/common/gl_canvas.c
index 3edb2c7..9867c4f 100644
--- a/common/gl_canvas.c
+++ b/common/gl_canvas.c
@@ -870,7 +870,7 @@ static void gl_canvas_destroy(SpiceCanvas *spice_canvas)
     free(canvas);
 }
 
-void gl_canvas_init() //unsafe global function
+void gl_canvas_init(void) //unsafe global function
 {
     if (!need_init) {
         return;
diff --git a/common/gl_canvas.h b/common/gl_canvas.h
index 4a15668..6776379 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -40,7 +40,7 @@ SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
                            , SpiceZlibDecoder *zlib_decoder
                            );
 void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
-void gl_canvas_init();
+void gl_canvas_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/common/quic.c b/common/quic.c
index e2c211d..cd3aee8 100644
--- a/common/quic.c
+++ b/common/quic.c
@@ -1690,7 +1690,7 @@ void quic_destroy(QuicContext *quic)
     encoder->usr->free(encoder->usr, encoder);
 }
 
-void quic_init()
+void quic_init(void)
 {
     if (!need_init) {
         return;
diff --git a/common/quic.h b/common/quic.h
index d031777..6047da8 100644
--- a/common/quic.h
+++ b/common/quic.h
@@ -63,7 +63,7 @@ int quic_decode(QuicContext *quic, QuicImageType type, uint8_t *buf, int stride)
 QuicContext *quic_create(QuicUsrContext *usr);
 void quic_destroy(QuicContext *quic);
 
-void quic_init();
+void quic_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/common/rop3.c b/common/rop3.c
index 77f0a71..83880fe 100644
--- a/common/rop3.c
+++ b/common/rop3.c
@@ -381,7 +381,7 @@ ROP3_HANDLERS(DPSoo, *src | *pat | *dest, 0xfe);
     rop3_test_handlers_32[index] = rop3_test32_##op;             \
     rop3_test_handlers_16[index] = rop3_test16_##op;
 
-void rop3_init()
+void rop3_init(void)
 {
     static int need_init = 1;
     int i;
diff --git a/common/rop3.h b/common/rop3.h
index 549b02c..3307649 100644
--- a/common/rop3.h
+++ b/common/rop3.h
@@ -33,7 +33,7 @@ void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, Sp
 void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                         uint32_t rgb);
 
-void rop3_init();
+void rop3_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/common/sw_canvas.c b/common/sw_canvas.c
index 9891d85..e95a971 100644
--- a/common/sw_canvas.c
+++ b/common/sw_canvas.c
@@ -1276,7 +1276,7 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format,
                                 );
 }
 
-void sw_canvas_init() //unsafe global function
+void sw_canvas_init(void) //unsafe global function
 {
     if (!need_init) {
         return;
diff --git a/common/sw_canvas.h b/common/sw_canvas.h
index 42f2573..5465526 100644
--- a/common/sw_canvas.h
+++ b/common/sw_canvas.h
@@ -57,7 +57,7 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
                            );
 
 
-void sw_canvas_init();
+void sw_canvas_init(void);
 
 #ifdef __cplusplus
 }
diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index d5fa616..3896cd2 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -170,12 +170,12 @@ int red_dispatcher_add_renderer(const char *name)
     return TRUE;
 }
 
-int red_dispatcher_qxl_count()
+int red_dispatcher_qxl_count(void)
 {
     return num_active_workers;
 }
 
-static void update_client_mouse_allowed()
+static void update_client_mouse_allowed(void)
 {
     static int allowed = FALSE;
     int allow_now = FALSE;
@@ -474,7 +474,7 @@ void red_dispatcher_set_mm_time(uint32_t mm_time)
     }
 }
 
-static inline int calc_compression_level()
+static inline int calc_compression_level(void)
 {
     ASSERT(streaming_video != STREAM_VIDEO_INVALID);
     if ((streaming_video != STREAM_VIDEO_OFF) ||
@@ -485,7 +485,7 @@ static inline int calc_compression_level()
     }
 }
 
-void red_dispatcher_on_ic_change()
+void red_dispatcher_on_ic_change(void)
 {
     int compression_level = calc_compression_level();
     RedDispatcher *now = dispatchers;
@@ -498,7 +498,7 @@ void red_dispatcher_on_ic_change()
     }
 }
 
-void red_dispatcher_on_sv_change()
+void red_dispatcher_on_sv_change(void)
 {
     int compression_level = calc_compression_level();
     RedDispatcher *now = dispatchers;
@@ -522,7 +522,7 @@ void red_dispatcher_set_mouse_mode(uint32_t mode)
     }
 }
 
-int red_dispatcher_count()
+int red_dispatcher_count(void)
 {
     RedDispatcher *now = dispatchers;
     int ret = 0;
@@ -534,7 +534,7 @@ int red_dispatcher_count()
     return ret;
 }
 
-uint32_t red_dispatcher_qxl_ram_size()
+uint32_t red_dispatcher_qxl_ram_size(void)
 {
     QXLDevInitInfo qxl_info;
     if (!dispatchers) {
diff --git a/server/red_dispatcher.h b/server/red_dispatcher.h
index 7f8973a..3f3c1ae 100644
--- a/server/red_dispatcher.h
+++ b/server/red_dispatcher.h
@@ -22,12 +22,12 @@
 struct RedDispatcher *red_dispatcher_init(QXLInstance *qxl);
 
 void red_dispatcher_set_mm_time(uint32_t);
-void red_dispatcher_on_ic_change();
-void red_dispatcher_on_sv_change();
+void red_dispatcher_on_ic_change(void);
+void red_dispatcher_on_sv_change(void);
 void red_dispatcher_set_mouse_mode(uint32_t mode);
-int red_dispatcher_count();
+int red_dispatcher_count(void);
 int red_dispatcher_add_renderer(const char *name);
-uint32_t red_dispatcher_qxl_ram_size();
-int red_dispatcher_qxl_count();
+uint32_t red_dispatcher_qxl_ram_size(void);
+int red_dispatcher_qxl_count(void);
 #endif
 
diff --git a/server/reds.c b/server/reds.c
index 2a62fa2..9f881c3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4100,7 +4100,7 @@ static void key_modifiers_sender(void *opaque)
     reds_send_keyboard_modifiers(kbd_get_leds(keyboard));
 }
 
-uint32_t reds_get_mm_time()
+uint32_t reds_get_mm_time(void)
 {
     struct timespec time_space;
     clock_gettime(CLOCK_MONOTONIC, &time_space);
@@ -4112,7 +4112,7 @@ void reds_update_mm_timer(uint32_t mm_time)
     red_dispatcher_set_mm_time(mm_time);
 }
 
-void reds_enable_mm_timer()
+void reds_enable_mm_timer(void)
 {
     SpiceMsgMainMultiMediaTime time_mes;
     RedsOutItem *item;
@@ -4128,7 +4128,7 @@ void reds_enable_mm_timer()
     reds_push_pipe_item(item);
 }
 
-void reds_desable_mm_timer()
+void reds_desable_mm_timer(void)
 {
     core->timer_cancel(reds->mm_timer);
 }
diff --git a/server/reds.h b/server/reds.h
index 7b25747..463c94f 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -126,10 +126,10 @@ 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_desable_mm_timer(void);
+void reds_enable_mm_timer(void);
 void reds_update_mm_timer(uint32_t mm_time);
-uint32_t reds_get_mm_time();
+uint32_t reds_get_mm_time(void);
 void reds_set_client_mouse_allowed(int is_client_mouse_allowed,
                                    int x_res, int y_res);
 void reds_register_channel(Channel *channel);
diff --git a/server/smartcard.h b/server/smartcard.h
index b901183..cc74d9b 100644
--- a/server/smartcard.h
+++ b/server/smartcard.h
@@ -29,7 +29,7 @@
 int smartcard_device_connect(SpiceCharDeviceInstance *char_device);
 void smartcard_device_disconnect(SpiceCharDeviceInstance *char_device);
 
-void smartcard_channel_init();
+void smartcard_channel_init(void);
 
 #endif // __SMART_CARD_H__
 
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 6c7055e..f88cf3a 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -1271,7 +1271,7 @@ void snd_set_playback_compression(int on)
     }
 }
 
-int snd_get_playback_compression()
+int snd_get_playback_compression(void)
 {
     return (playback_compression == SPICE_AUDIO_DATA_MODE_RAW) ? FALSE : TRUE;
 }
diff --git a/server/snd_worker.h b/server/snd_worker.h
index 4d5a1b4..7659cb2 100644
--- a/server/snd_worker.h
+++ b/server/snd_worker.h
@@ -27,7 +27,7 @@ void snd_attach_record(SpiceRecordInstance *sin);
 void snd_detach_record(SpiceRecordInstance *sin);
 
 void snd_set_playback_compression(int on);
-int snd_get_playback_compression();
+int snd_get_playback_compression(void);
 
 #endif
 
commit 0d1a9a3c89d9c31f7cc03b849bcec9ba698abb63
Author: Alon Levy <alevy at redhat.com>
Date:   Thu Jul 14 13:12:21 2011 +0300

    bump required spice-protocol to 0.8.1 for qxl_dev async and s3 updates

diff --git a/configure.ac b/configure.ac
index f158136..01872c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -126,7 +126,7 @@ fi
 dnl =========================================================================
 dnl Check deps
 
-PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.7.0)
+PKG_CHECK_MODULES(PROTOCOL, spice-protocol >= 0.8.1)
 AC_SUBST(PROTOCOL_CFLAGS)
 
 AC_CHECK_LIBM
commit c9c84c9f8d5f56fd19d5728672e167628f3b804c
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Jul 19 16:05:04 2011 +0300

    server: api: add spice_qxl_* calls based on QXLWorker contents
    
    For each callback in QXLWorker, for example QXLWorker::update_area, add
    a direct call named spice_qxl_update_area.
    
    This will (a) remove the pointless indirection and (b) make shared
    library versioning alot easier as we'll get new linker symbols which
    we can tag with the version they appeared in the shared library.
    
    [cherry-picked from master]

diff --git a/server/red_dispatcher.c b/server/red_dispatcher.c
index 75e0670..d5fa616 100644
--- a/server/red_dispatcher.c
+++ b/server/red_dispatcher.c
@@ -206,11 +206,10 @@ static void update_client_mouse_allowed()
     }
 }
 
-static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+static void red_dispatcher_update_area(RedDispatcher *dispatcher, uint32_t surface_id,
                                    QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
                                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_UPDATE;
     SpiceRect *dirty_rects = spice_new0(SpiceRect, num_dirty_rects);
     SpiceRect *area = spice_new0(SpiceRect, 1);
@@ -238,9 +237,16 @@ static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
     free(area);
 }
 
-static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
+static void qxl_worker_update_area(QXLWorker *qxl_worker, uint32_t surface_id,
+                                   QXLRect *qxl_area, QXLRect *qxl_dirty_rects,
+                                   uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    red_dispatcher_update_area((RedDispatcher*)qxl_worker, surface_id, qxl_area,
+                               qxl_dirty_rects, num_dirty_rects, clear_dirty_region);
+}
+
+static void red_dispatcher_add_memslot(RedDispatcher *dispatcher, QXLDevMemSlot *mem_slot)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_ADD_MEMSLOT;
 
     write_message(dispatcher->channel, &message);
@@ -249,9 +255,13 @@ static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slo
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
+static void qxl_worker_add_memslot(QXLWorker *qxl_worker, QXLDevMemSlot *mem_slot)
+{
+    red_dispatcher_add_memslot((RedDispatcher*)qxl_worker, mem_slot);
+}
+
+static void red_dispatcher_del_memslot(RedDispatcher *dispatcher, uint32_t slot_group_id, uint32_t slot_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DEL_MEMSLOT;
 
     write_message(dispatcher->channel, &message);
@@ -259,9 +269,13 @@ static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id
     send_data(dispatcher->channel, &slot_id, sizeof(uint32_t));
 }
 
-static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
+static void qxl_worker_del_memslot(QXLWorker *qxl_worker, uint32_t slot_group_id, uint32_t slot_id)
+{
+    red_dispatcher_del_memslot((RedDispatcher*)qxl_worker, slot_group_id, slot_id);
+}
+
+static void red_dispatcher_destroy_surfaces(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACES;
 
     write_message(dispatcher->channel, &message);
@@ -269,9 +283,13 @@ static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_destroy_surfaces(QXLWorker *qxl_worker)
+{
+    red_dispatcher_destroy_surfaces((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_destroy_primary(RedDispatcher *dispatcher, uint32_t surface_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_PRIMARY_SURFACE;
 
     write_message(dispatcher->channel, &message);
@@ -287,10 +305,14 @@ static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_i
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+static void qxl_worker_destroy_primary(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary((RedDispatcher*)qxl_worker, surface_id);
+}
+
+static void red_dispatcher_create_primary(RedDispatcher *dispatcher, uint32_t surface_id,
                                       QXLDevSurfaceCreate *surface)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_CREATE_PRIMARY_SURFACE;
 
     dispatcher->x_res = surface->width;
@@ -307,9 +329,14 @@ static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id
     update_client_mouse_allowed();
 }
 
-static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
+static void qxl_worker_create_primary(QXLWorker *qxl_worker, uint32_t surface_id,
+                                      QXLDevSurfaceCreate *surface)
+{
+    red_dispatcher_create_primary((RedDispatcher*)qxl_worker, surface_id, surface);
+}
+
+static void red_dispatcher_reset_image_cache(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_IMAGE_CACHE;
 
     write_message(dispatcher->channel, &message);
@@ -317,9 +344,13 @@ static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
+static void qxl_worker_reset_image_cache(QXLWorker *qxl_worker)
+{
+    red_dispatcher_reset_image_cache((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_reset_cursor(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_CURSOR;
 
     write_message(dispatcher->channel, &message);
@@ -327,9 +358,13 @@ static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+static void qxl_worker_reset_cursor(QXLWorker *qxl_worker)
+{
+    red_dispatcher_reset_cursor((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_destroy_surface_wait(RedDispatcher *dispatcher, uint32_t surface_id)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_DESTROY_SURFACE_WAIT;
 
     write_message(dispatcher->channel, &message);
@@ -338,18 +373,25 @@ static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surf
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
+static void qxl_worker_destroy_surface_wait(QXLWorker *qxl_worker, uint32_t surface_id)
+{
+    red_dispatcher_destroy_surface_wait((RedDispatcher*)qxl_worker, surface_id);
+}
+
+static void red_dispatcher_reset_memslots(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_RESET_MEMSLOTS;
 
     write_message(dispatcher->channel, &message);
 }
 
-static void qxl_worker_wakeup(QXLWorker *qxl_worker)
+static void qxl_worker_reset_memslots(QXLWorker *qxl_worker)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
+    red_dispatcher_reset_memslots((RedDispatcher*)qxl_worker);
+}
 
+static void red_dispatcher_wakeup(RedDispatcher *dispatcher)
+{
     if (!test_bit(RED_WORKER_PENDING_WAKEUP, dispatcher->pending)) {
         RedWorkerMessage message = RED_WORKER_MESSAGE_WAKEUP;
         set_bit(RED_WORKER_PENDING_WAKEUP, &dispatcher->pending);
@@ -357,9 +399,13 @@ static void qxl_worker_wakeup(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_oom(QXLWorker *qxl_worker)
+static void qxl_worker_wakeup(QXLWorker *qxl_worker)
+{
+    red_dispatcher_wakeup((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_oom(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     if (!test_bit(RED_WORKER_PENDING_OOM, dispatcher->pending)) {
         RedWorkerMessage message = RED_WORKER_MESSAGE_OOM;
         set_bit(RED_WORKER_PENDING_OOM, &dispatcher->pending);
@@ -367,17 +413,25 @@ static void qxl_worker_oom(QXLWorker *qxl_worker)
     }
 }
 
-static void qxl_worker_start(QXLWorker *qxl_worker)
+static void qxl_worker_oom(QXLWorker *qxl_worker)
+{
+    red_dispatcher_oom((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_start(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_START;
 
     write_message(dispatcher->channel, &message);
 }
 
-static void qxl_worker_stop(QXLWorker *qxl_worker)
+static void qxl_worker_start(QXLWorker *qxl_worker)
+{
+    red_dispatcher_start((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_stop(RedDispatcher *dispatcher)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_STOP;
 
     write_message(dispatcher->channel, &message);
@@ -385,10 +439,15 @@ static void qxl_worker_stop(QXLWorker *qxl_worker)
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
-void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
-                                struct QXLCommandExt *ext, uint32_t count)
+static void qxl_worker_stop(QXLWorker *qxl_worker)
+{
+    red_dispatcher_stop((RedDispatcher*)qxl_worker);
+}
+
+static void red_dispatcher_loadvm_commands(RedDispatcher *dispatcher,
+                                           struct QXLCommandExt *ext,
+                                           uint32_t count)
 {
-    RedDispatcher *dispatcher = (RedDispatcher *)qxl_worker;
     RedWorkerMessage message = RED_WORKER_MESSAGE_LOADVM_COMMANDS;
 
     red_printf("");
@@ -399,6 +458,13 @@ void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
     ASSERT(message == RED_WORKER_MESSAGE_READY);
 }
 
+static void qxl_worker_loadvm_commands(QXLWorker *qxl_worker,
+                                       struct QXLCommandExt *ext,
+                                       uint32_t count)
+{
+    red_dispatcher_loadvm_commands((RedDispatcher*)qxl_worker, ext, count);
+}
+
 void red_dispatcher_set_mm_time(uint32_t mm_time)
 {
     RedDispatcher *now = dispatchers;
@@ -478,6 +544,100 @@ uint32_t red_dispatcher_qxl_ram_size()
     return qxl_info.qxl_ram_size;
 }
 
+SPICE_GNUC_VISIBLE
+void spice_qxl_wakeup(QXLInstance *instance)
+{
+    red_dispatcher_wakeup(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_oom(QXLInstance *instance)
+{
+    red_dispatcher_oom(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_start(QXLInstance *instance)
+{
+    red_dispatcher_start(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_stop(QXLInstance *instance)
+{
+    red_dispatcher_stop(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
+                    struct QXLRect *area, struct QXLRect *dirty_rects,
+                    uint32_t num_dirty_rects, uint32_t clear_dirty_region)
+{
+    red_dispatcher_update_area(instance->st->dispatcher, surface_id, area, dirty_rects,
+                               num_dirty_rects, clear_dirty_region);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot)
+{
+    red_dispatcher_add_memslot(instance->st->dispatcher, slot);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id, uint32_t slot_id)
+{
+    red_dispatcher_del_memslot(instance->st->dispatcher, slot_group_id, slot_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_memslots(QXLInstance *instance)
+{
+    red_dispatcher_reset_memslots(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surfaces(QXLInstance *instance)
+{
+    red_dispatcher_destroy_surfaces(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id)
+{
+    red_dispatcher_destroy_primary(instance->st->dispatcher, surface_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
+                                QXLDevSurfaceCreate *surface)
+{
+    red_dispatcher_create_primary(instance->st->dispatcher, surface_id, surface);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_image_cache(QXLInstance *instance)
+{
+    red_dispatcher_reset_image_cache(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_reset_cursor(QXLInstance *instance)
+{
+    red_dispatcher_reset_cursor(instance->st->dispatcher);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id)
+{
+    red_dispatcher_destroy_surface_wait(instance->st->dispatcher, surface_id);
+}
+
+SPICE_GNUC_VISIBLE
+void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count)
+{
+    red_dispatcher_loadvm_commands(instance->st->dispatcher, ext, count);
+}
+
 RedDispatcher *red_dispatcher_init(QXLInstance *qxl)
 {
     RedDispatcher *dispatcher;
diff --git a/server/spice-server.syms b/server/spice-server.syms
index 638f4ee..e14bb1c 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -58,4 +58,19 @@ SPICE_SERVER_0.8.2 {
 global:
     spice_server_set_sasl;
     spice_server_set_sasl_appname;
+    spice_qxl_wakeup;
+    spice_qxl_oom;
+    spice_qxl_start;
+    spice_qxl_stop;
+    spice_qxl_update_area;
+    spice_qxl_add_memslot;
+    spice_qxl_del_memslot;
+    spice_qxl_reset_memslots;
+    spice_qxl_destroy_surfaces;
+    spice_qxl_destroy_primary_surface;
+    spice_qxl_create_primary_surface;
+    spice_qxl_reset_image_cache;
+    spice_qxl_reset_cursor;
+    spice_qxl_destroy_surface_wait;
+    spice_qxl_loadvm_commands;
 } SPICE_SERVER_0.8.1;
diff --git a/server/spice.h b/server/spice.h
index d22425b..61bf886 100644
--- a/server/spice.h
+++ b/server/spice.h
@@ -104,6 +104,7 @@ struct QXLRect;
 struct QXLWorker {
     uint32_t minor_version;
     uint32_t major_version;
+    /* These calls are deprecated. Pleaes use the spice_qxl_* calls instead */
     void (*wakeup)(QXLWorker *worker);
     void (*oom)(QXLWorker *worker);
     void (*start)(QXLWorker *worker);
@@ -124,6 +125,25 @@ struct QXLWorker {
     void (*loadvm_commands)(QXLWorker *worker, struct QXLCommandExt *ext, uint32_t count);
 };
 
+void spice_qxl_wakeup(QXLInstance *instance);
+void spice_qxl_oom(QXLInstance *instance);
+void spice_qxl_start(QXLInstance *instance);
+void spice_qxl_stop(QXLInstance *instance);
+void spice_qxl_update_area(QXLInstance *instance, uint32_t surface_id,
+                   struct QXLRect *area, struct QXLRect *dirty_rects,
+                   uint32_t num_dirty_rects, uint32_t clear_dirty_region);
+void spice_qxl_add_memslot(QXLInstance *instance, QXLDevMemSlot *slot);
+void spice_qxl_del_memslot(QXLInstance *instance, uint32_t slot_group_id, uint32_t slot_id);
+void spice_qxl_reset_memslots(QXLInstance *instance);
+void spice_qxl_destroy_surfaces(QXLInstance *instance);
+void spice_qxl_destroy_primary_surface(QXLInstance *instance, uint32_t surface_id);
+void spice_qxl_create_primary_surface(QXLInstance *instance, uint32_t surface_id,
+                               QXLDevSurfaceCreate *surface);
+void spice_qxl_reset_image_cache(QXLInstance *instance);
+void spice_qxl_reset_cursor(QXLInstance *instance);
+void spice_qxl_destroy_surface_wait(QXLInstance *instance, uint32_t surface_id);
+void spice_qxl_loadvm_commands(QXLInstance *instance, struct QXLCommandExt *ext, uint32_t count);
+
 typedef struct QXLDrawArea {
     uint8_t *buf;
     uint32_t size;
commit 66ad3e84f3f698c05b18c47334efe8c0c5aa7041
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Jun 21 09:43:42 2011 +0200

    s/__visible__/SPICE_GNUC_VISIBLE
    
    The C specification reserves use of identifiers starting with __
    to the compiler so we shouldn't use one such symbol.
    
    [cherry-pick from master]

diff --git a/server/red_tunnel_worker.c b/server/red_tunnel_worker.c
index 4793f62..46cccb5 100644
--- a/server/red_tunnel_worker.c
+++ b/server/red_tunnel_worker.c
@@ -961,8 +961,8 @@ static TunneledBufferProcessQueue *tunnel_socket_alloc_simple_print_reply_proces
                                                       PROCESS_DIRECTION_TYPE_REPLY);
 }
 
-__visible__ void spice_server_net_wire_recv_packet(SpiceNetWireInstance *sin,
-                                                   const uint8_t *pkt, int pkt_len)
+SPICE_GNUC_VISIBLE void spice_server_net_wire_recv_packet(SpiceNetWireInstance *sin,
+                                                          const uint8_t *pkt, int pkt_len)
 {
     TunnelWorker *worker = sin->st->worker;
     ASSERT(worker);
diff --git a/server/reds.c b/server/reds.c
index e97cd77..2a62fa2 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4164,7 +4164,7 @@ static void attach_to_red_agent(SpiceCharDeviceInstance *sin)
     reds_send_agent_connected();
 }
 
-__visible__ void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin)
+SPICE_GNUC_VISIBLE void spice_server_char_device_wakeup(SpiceCharDeviceInstance* sin)
 {
     (*sin->st->wakeup)(sin);
 }
@@ -4180,7 +4180,7 @@ const char *spice_server_char_device_recognized_subtypes_list[] = {
     NULL,
 };
 
-__visible__ const char** spice_server_char_device_recognized_subtypes()
+SPICE_GNUC_VISIBLE const char** spice_server_char_device_recognized_subtypes()
 {
     return spice_server_char_device_recognized_subtypes_list;
 }
@@ -4228,8 +4228,8 @@ static void spice_server_char_device_remove_interface(SpiceBaseInstance *sin)
 #endif
 }
 
-__visible__ int spice_server_add_interface(SpiceServer *s,
-                                           SpiceBaseInstance *sin)
+SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *s,
+                                                  SpiceBaseInstance *sin)
 {
     const SpiceBaseInterface *interface = sin->sif;
 
@@ -4350,7 +4350,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
     return 0;
 }
 
-__visible__ int spice_server_remove_interface(SpiceBaseInstance *sin)
+SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin)
 {
     const SpiceBaseInterface *interface = sin->sif;
 
@@ -4536,7 +4536,7 @@ err:
 }
 
 /* new interface */
-__visible__ SpiceServer *spice_server_new(void)
+SPICE_GNUC_VISIBLE SpiceServer *spice_server_new(void)
 {
     /* we can't handle multiple instances (yet) */
     ASSERT(reds == NULL);
@@ -4545,7 +4545,7 @@ __visible__ SpiceServer *spice_server_new(void)
     return reds;
 }
 
-__visible__ int spice_server_init(SpiceServer *s, SpiceCoreInterface *core)
+SPICE_GNUC_VISIBLE int spice_server_init(SpiceServer *s, SpiceCoreInterface *core)
 {
     int ret;
 
@@ -4557,19 +4557,19 @@ __visible__ int spice_server_init(SpiceServer *s, SpiceCoreInterface *core)
     return ret;
 }
 
-__visible__ void spice_server_destroy(SpiceServer *s)
+SPICE_GNUC_VISIBLE void spice_server_destroy(SpiceServer *s)
 {
     ASSERT(reds == s);
     reds_exit();
 }
 
-__visible__ spice_compat_version_t spice_get_current_compat_version(void)
+SPICE_GNUC_VISIBLE spice_compat_version_t spice_get_current_compat_version(void)
 {
     return SPICE_COMPAT_VERSION_CURRENT;
 }
 
-__visible__ int spice_server_set_compat_version(SpiceServer *s,
-                                                spice_compat_version_t version)
+SPICE_GNUC_VISIBLE int spice_server_set_compat_version(SpiceServer *s,
+                                                       spice_compat_version_t version)
 {
     if (version < SPICE_COMPAT_VERSION_0_6) {
         /* We don't support 0.4 compat mode atm */
@@ -4583,7 +4583,7 @@ __visible__ int spice_server_set_compat_version(SpiceServer *s,
     return 0;
 }
 
-__visible__ int spice_server_set_port(SpiceServer *s, int port)
+SPICE_GNUC_VISIBLE int spice_server_set_port(SpiceServer *s, int port)
 {
     ASSERT(reds == s);
     if (port < 0 || port > 0xffff) {
@@ -4593,7 +4593,7 @@ __visible__ int spice_server_set_port(SpiceServer *s, int port)
     return 0;
 }
 
-__visible__ void spice_server_set_addr(SpiceServer *s, const char *addr, int flags)
+SPICE_GNUC_VISIBLE void spice_server_set_addr(SpiceServer *s, const char *addr, int flags)
 {
     ASSERT(reds == s);
     strncpy(spice_addr, addr, sizeof(spice_addr));
@@ -4605,7 +4605,7 @@ __visible__ void spice_server_set_addr(SpiceServer *s, const char *addr, int fla
     }
 }
 
-__visible__ int spice_server_set_noauth(SpiceServer *s)
+SPICE_GNUC_VISIBLE int spice_server_set_noauth(SpiceServer *s)
 {
     ASSERT(reds == s);
     memset(taTicket.password, 0, sizeof(taTicket.password));
@@ -4613,7 +4613,7 @@ __visible__ int spice_server_set_noauth(SpiceServer *s)
     return 0;
 }
 
-__visible__ int spice_server_set_sasl(SpiceServer *s, int enabled)
+SPICE_GNUC_VISIBLE int spice_server_set_sasl(SpiceServer *s, int enabled)
 {
     ASSERT(reds == s);
 #if HAVE_SASL
@@ -4624,7 +4624,7 @@ __visible__ int spice_server_set_sasl(SpiceServer *s, int enabled)
 #endif
 }
 
-__visible__ int spice_server_set_sasl_appname(SpiceServer *s, const char *appname)
+SPICE_GNUC_VISIBLE int spice_server_set_sasl_appname(SpiceServer *s, const char *appname)
 {
     ASSERT(reds == s);
 #if HAVE_SASL
@@ -4636,10 +4636,10 @@ __visible__ int spice_server_set_sasl_appname(SpiceServer *s, const char *appnam
 #endif
 }
 
-__visible__ int spice_server_set_ticket(SpiceServer *s,
-                                        const char *passwd, int lifetime,
-                                        int fail_if_connected,
-                                        int disconnect_if_connected)
+SPICE_GNUC_VISIBLE int spice_server_set_ticket(SpiceServer *s,
+                                               const char *passwd, int lifetime,
+                                               int fail_if_connected,
+                                               int disconnect_if_connected)
 {
     ASSERT(reds == s);
 
@@ -4669,10 +4669,10 @@ __visible__ int spice_server_set_ticket(SpiceServer *s,
     return 0;
 }
 
-__visible__ int spice_server_set_tls(SpiceServer *s, int port,
-                                     const char *ca_cert_file, const char *certs_file,
-                                     const char *private_key_file, const char *key_passwd,
-                                     const char *dh_key_file, const char *ciphersuite)
+SPICE_GNUC_VISIBLE int spice_server_set_tls(SpiceServer *s, int port,
+                                            const char *ca_cert_file, const char *certs_file,
+                                            const char *private_key_file, const char *key_passwd,
+                                            const char *dh_key_file, const char *ciphersuite)
 {
     ASSERT(reds == s);
     if (port == 0 || ca_cert_file == NULL || certs_file == NULL ||
@@ -4707,21 +4707,21 @@ __visible__ int spice_server_set_tls(SpiceServer *s, int port,
     return 0;
 }
 
-__visible__ int spice_server_set_image_compression(SpiceServer *s,
-                                                   spice_image_compression_t comp)
+SPICE_GNUC_VISIBLE int spice_server_set_image_compression(SpiceServer *s,
+                                                          spice_image_compression_t comp)
 {
     ASSERT(reds == s);
     set_image_compression(comp);
     return 0;
 }
 
-__visible__ spice_image_compression_t spice_server_get_image_compression(SpiceServer *s)
+SPICE_GNUC_VISIBLE spice_image_compression_t spice_server_get_image_compression(SpiceServer *s)
 {
     ASSERT(reds == s);
     return image_compression;
 }
 
-__visible__ int spice_server_set_jpeg_compression(SpiceServer *s, spice_wan_compression_t comp)
+SPICE_GNUC_VISIBLE int spice_server_set_jpeg_compression(SpiceServer *s, spice_wan_compression_t comp)
 {
     ASSERT(reds == s);
     if (comp == SPICE_WAN_COMPRESSION_INVALID) {
@@ -4733,7 +4733,7 @@ __visible__ int spice_server_set_jpeg_compression(SpiceServer *s, spice_wan_comp
     return 0;
 }
 
-__visible__ int spice_server_set_zlib_glz_compression(SpiceServer *s, spice_wan_compression_t comp)
+SPICE_GNUC_VISIBLE int spice_server_set_zlib_glz_compression(SpiceServer *s, spice_wan_compression_t comp)
 {
     ASSERT(reds == s);
     if (comp == SPICE_WAN_COMPRESSION_INVALID) {
@@ -4745,7 +4745,7 @@ __visible__ int spice_server_set_zlib_glz_compression(SpiceServer *s, spice_wan_
     return 0;
 }
 
-__visible__ int spice_server_set_channel_security(SpiceServer *s, const char *channel, int security)
+SPICE_GNUC_VISIBLE int spice_server_set_channel_security(SpiceServer *s, const char *channel, int security)
 {
     static const char *names[] = {
         [ SPICE_CHANNEL_MAIN     ] = "main",
@@ -4778,7 +4778,7 @@ __visible__ int spice_server_set_channel_security(SpiceServer *s, const char *ch
     return -1;
 }
 
-__visible__ int spice_server_get_sock_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
+SPICE_GNUC_VISIBLE int spice_server_get_sock_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
 {
     ASSERT(reds == s);
     if (!reds->stream) {
@@ -4790,7 +4790,7 @@ __visible__ int spice_server_get_sock_info(SpiceServer *s, struct sockaddr *sa,
     return 0;
 }
 
-__visible__ int spice_server_get_peer_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
+SPICE_GNUC_VISIBLE int spice_server_get_peer_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
 {
     ASSERT(reds == s);
     if (!reds->stream) {
@@ -4802,7 +4802,7 @@ __visible__ int spice_server_get_peer_info(SpiceServer *s, struct sockaddr *sa,
     return 0;
 }
 
-__visible__ int spice_server_add_renderer(SpiceServer *s, const char *name)
+SPICE_GNUC_VISIBLE int spice_server_add_renderer(SpiceServer *s, const char *name)
 {
     ASSERT(reds == s);
     if (!red_dispatcher_add_renderer(name)) {
@@ -4812,13 +4812,13 @@ __visible__ int spice_server_add_renderer(SpiceServer *s, const char *name)
     return 0;
 }
 
-__visible__ int spice_server_kbd_leds(SpiceKbdInstance *sin, int leds)
+SPICE_GNUC_VISIBLE int spice_server_kbd_leds(SpiceKbdInstance *sin, int leds)
 {
     reds_on_keyboard_leds_change(NULL, leds);
     return 0;
 }
 
-__visible__ int spice_server_set_streaming_video(SpiceServer *s, int value)
+SPICE_GNUC_VISIBLE int spice_server_set_streaming_video(SpiceServer *s, int value)
 {
     ASSERT(reds == s);
     if (value != SPICE_STREAM_VIDEO_OFF &&
@@ -4830,14 +4830,14 @@ __visible__ int spice_server_set_streaming_video(SpiceServer *s, int value)
     return 0;
 }
 
-__visible__ int spice_server_set_playback_compression(SpiceServer *s, int enable)
+SPICE_GNUC_VISIBLE int spice_server_set_playback_compression(SpiceServer *s, int enable)
 {
     ASSERT(reds == s);
     snd_set_playback_compression(enable);
     return 0;
 }
 
-__visible__ int spice_server_set_agent_mouse(SpiceServer *s, int enable)
+SPICE_GNUC_VISIBLE int spice_server_set_agent_mouse(SpiceServer *s, int enable)
 {
     ASSERT(reds == s);
     agent_mouse = enable;
@@ -4845,7 +4845,7 @@ __visible__ int spice_server_set_agent_mouse(SpiceServer *s, int enable)
     return 0;
 }
 
-__visible__ int spice_server_set_agent_copypaste(SpiceServer *s, int enable)
+SPICE_GNUC_VISIBLE int spice_server_set_agent_copypaste(SpiceServer *s, int enable)
 {
     ASSERT(reds == s);
     agent_copypaste = enable;
@@ -4854,7 +4854,7 @@ __visible__ int spice_server_set_agent_copypaste(SpiceServer *s, int enable)
     return 0;
 }
 
-__visible__ int spice_server_migrate_info(SpiceServer *s, const char* dest,
+SPICE_GNUC_VISIBLE int spice_server_migrate_info(SpiceServer *s, const char* dest,
                                           int port, int secure_port,
                                           const char* cert_subject)
 {
@@ -4879,7 +4879,7 @@ __visible__ int spice_server_migrate_info(SpiceServer *s, const char* dest,
 }
 
 /* interface for seamless migration */
-__visible__ int spice_server_migrate_start(SpiceServer *s)
+SPICE_GNUC_VISIBLE int spice_server_migrate_start(SpiceServer *s)
 {
     ASSERT(reds == s);
 
@@ -4895,7 +4895,7 @@ __visible__ int spice_server_migrate_start(SpiceServer *s)
     return 0;
 }
 
-__visible__ int spice_server_migrate_client_state(SpiceServer *s)
+SPICE_GNUC_VISIBLE int spice_server_migrate_client_state(SpiceServer *s)
 {
     ASSERT(reds == s);
 
@@ -4909,7 +4909,7 @@ __visible__ int spice_server_migrate_client_state(SpiceServer *s)
     return 0;
 }
 
-__visible__ int spice_server_migrate_end(SpiceServer *s, int completed)
+SPICE_GNUC_VISIBLE int spice_server_migrate_end(SpiceServer *s, int completed)
 {
     ASSERT(reds == s);
     reds_mig_finished(completed);
@@ -4917,7 +4917,7 @@ __visible__ int spice_server_migrate_end(SpiceServer *s, int completed)
 }
 
 /* interface for switch-host migration */
-__visible__ int spice_server_migrate_switch(SpiceServer *s)
+SPICE_GNUC_VISIBLE int spice_server_migrate_switch(SpiceServer *s)
 {
     ASSERT(reds == s);
     reds_mig_switch();
diff --git a/server/reds.h b/server/reds.h
index 61ad691..7b25747 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -28,7 +28,7 @@
 #include <sasl/sasl.h>
 #endif
 
-#define __visible__ __attribute__ ((visibility ("default")))
+#define SPICE_GNUC_VISIBLE __attribute__ ((visibility ("default")))
 
 typedef struct RedsStream RedsStream;
 
diff --git a/server/snd_worker.c b/server/snd_worker.c
index 1a4840c..6c7055e 100644
--- a/server/snd_worker.c
+++ b/server/snd_worker.c
@@ -820,7 +820,7 @@ static void snd_set_command(SndChannel *channel, uint32_t command)
     channel->command |= command;
 }
 
-__visible__ void spice_server_playback_start(SpicePlaybackInstance *sin)
+SPICE_GNUC_VISIBLE void spice_server_playback_start(SpicePlaybackInstance *sin)
 {
     SndChannel *channel = sin->st->worker.connection;
     PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
@@ -839,7 +839,7 @@ __visible__ void spice_server_playback_start(SpicePlaybackInstance *sin)
     }
 }
 
-__visible__ void spice_server_playback_stop(SpicePlaybackInstance *sin)
+SPICE_GNUC_VISIBLE void spice_server_playback_stop(SpicePlaybackInstance *sin)
 {
     SndChannel *channel = sin->st->worker.connection;
     PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
@@ -866,8 +866,8 @@ __visible__ void spice_server_playback_stop(SpicePlaybackInstance *sin)
     }
 }
 
-__visible__ void spice_server_playback_get_buffer(SpicePlaybackInstance *sin,
-                                                  uint32_t **frame, uint32_t *num_samples)
+SPICE_GNUC_VISIBLE void spice_server_playback_get_buffer(SpicePlaybackInstance *sin,
+                                                         uint32_t **frame, uint32_t *num_samples)
 {
     SndChannel *channel = sin->st->worker.connection;
     PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
@@ -884,7 +884,7 @@ __visible__ void spice_server_playback_get_buffer(SpicePlaybackInstance *sin,
     *num_samples = FRAME_SIZE;
 }
 
-__visible__ void spice_server_playback_put_samples(SpicePlaybackInstance *sin, uint32_t *samples)
+SPICE_GNUC_VISIBLE void spice_server_playback_put_samples(SpicePlaybackInstance *sin, uint32_t *samples)
 {
     SndChannel *channel = sin->st->worker.connection;
     PlaybackChannel *playback_channel = SPICE_CONTAINEROF(channel, PlaybackChannel, base);
@@ -1003,7 +1003,7 @@ static void snd_record_migrate(Channel *channel)
     }
 }
 
-__visible__ void spice_server_record_start(SpiceRecordInstance *sin)
+SPICE_GNUC_VISIBLE void spice_server_record_start(SpiceRecordInstance *sin)
 {
     SndChannel *channel = sin->st->worker.connection;
     RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
@@ -1023,7 +1023,7 @@ __visible__ void spice_server_record_start(SpiceRecordInstance *sin)
     }
 }
 
-__visible__ void spice_server_record_stop(SpiceRecordInstance *sin)
+SPICE_GNUC_VISIBLE void spice_server_record_stop(SpiceRecordInstance *sin)
 {
     SndChannel *channel = sin->st->worker.connection;
     RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
@@ -1041,8 +1041,8 @@ __visible__ void spice_server_record_stop(SpiceRecordInstance *sin)
     }
 }
 
-__visible__ uint32_t spice_server_record_get_samples(SpiceRecordInstance *sin,
-                                                     uint32_t *samples, uint32_t bufsize)
+SPICE_GNUC_VISIBLE uint32_t spice_server_record_get_samples(SpiceRecordInstance *sin,
+                                                            uint32_t *samples, uint32_t bufsize)
 {
     SndChannel *channel = sin->st->worker.connection;
     RecordChannel *record_channel = SPICE_CONTAINEROF(channel, RecordChannel, base);
commit f3ee396dfe396abcc4978704d69e8db77d9c161f
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 10:59:47 2011 +0300

    server: spice-server.syms: move sasl symbols to 0.8.2
    
    [0.8: there are no 0.10.0 symbols]

diff --git a/server/spice-server.syms b/server/spice-server.syms
index acd05aa..638f4ee 100644
--- a/server/spice-server.syms
+++ b/server/spice-server.syms
@@ -53,3 +53,9 @@ SPICE_SERVER_0.8.1 {
 global:
     spice_server_set_agent_copypaste;
 } SPICE_SERVER_0.8.0;
+
+SPICE_SERVER_0.8.2 {
+global:
+    spice_server_set_sasl;
+    spice_server_set_sasl_appname;
+} SPICE_SERVER_0.8.1;
commit c685a3d4ebe7e8dde9bb8bc4897856b8ad2c8580
Author: Uri Lublin <uril at redhat.com>
Date:   Fri Jul 8 13:24:34 2011 +0200

    client: rename connect_unsecure to connect_to_peer
    
    Both connect_secure() and connect_unsecure() call connect_to_peer().
    
    Prior to this commit spicec.log reported all connections as unsecure,
    as connect_secure() called connect_unsecure() to make the connection.
    This fixes RH bug #653545

diff --git a/client/red_peer.cpp b/client/red_peer.cpp
index 63b66bb..61120b9 100644
--- a/client/red_peer.cpp
+++ b/client/red_peer.cpp
@@ -70,7 +70,7 @@ void RedPeer::cleanup()
     }
 }
 
-void RedPeer::connect_unsecure(const char* host, int portnr)
+void RedPeer::connect_to_peer(const char* host, int portnr)
 {
     struct addrinfo ai, *result = NULL, *e;
     char uaddr[INET6_ADDRSTRLEN+1];
@@ -106,7 +106,7 @@ void RedPeer::connect_unsecure(const char* host, int portnr)
             getnameinfo((struct sockaddr*)e->ai_addr, e->ai_addrlen,
                         uaddr,INET6_ADDRSTRLEN, uport,32,
                         NI_NUMERICHOST | NI_NUMERICSERV);
-            LOG_INFO("Trying %s %s", uaddr, uport);
+            DBG(0, "Trying %s %s", uaddr, uport);
             if (::connect(_peer, e->ai_addr, e->ai_addrlen) == SOCKET_ERROR) {
                 err = sock_error();
                 LOG_INFO("Connect failed: %s (%d)",
@@ -115,7 +115,7 @@ void RedPeer::connect_unsecure(const char* host, int portnr)
                 _peer = -1;
                 continue;
             }
-            LOG_INFO("Connected to %s %s", uaddr, uport);
+            DBG(0, "Connected to %s %s", uaddr, uport);
             break;
         }
         lock.unlock();
@@ -132,6 +132,13 @@ void RedPeer::connect_unsecure(const char* host, int portnr)
     }
 }
 
+void RedPeer::connect_unsecure(const char* host, int portnr)
+{
+    connect_to_peer(host, portnr);
+    ASSERT(_ctx == NULL && _ssl == NULL && _peer != INVALID_SOCKET);
+    LOG_INFO("Connected to %s %d", host, portnr);
+}
+
 bool RedPeer::verify_pubkey(X509* cert, const HostAuthOptions::PublicKey& key)
 {
     EVP_PKEY* cert_pubkey = NULL;
@@ -472,9 +479,11 @@ void RedPeer::connect_secure(const ConnectionOptions& options, const char* host)
     int return_code;
     int auth_flags;
     SslVerifyCbData auth_data;
+    int portnr = options.secure_port;
 
-    connect_unsecure(host, options.secure_port);
+    connect_to_peer(host, portnr);
     ASSERT(_ctx == NULL && _ssl == NULL && _peer != INVALID_SOCKET);
+    LOG_INFO("Connected to %s %d", host, portnr);
 
     try {
 #if OPENSSL_VERSION_NUMBER >= 0x10000000L
diff --git a/client/red_peer.h b/client/red_peer.h
index a4310e6..53fd3c9 100644
--- a/client/red_peer.h
+++ b/client/red_peer.h
@@ -136,6 +136,7 @@ protected:
     void cleanup();
 
 private:
+    void connect_to_peer(const char* host, int port);
     void shutdown();
 
 private:
commit edce17a574257a4551fd93562040969f5b47b6eb
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Mon Jul 4 14:27:11 2011 +0200

    Fix spice-server/qemu channel version checks
    
    When qemu creates a channel, reds.c contains code to check the
    minor/major channel versions known to QEMU (ie the ones that were
    current in spice-server when QEMU was compiled) and to compare these
    versions against the current ones the currently installed spice-server
    version.
    
    According to kraxel [1], the rules for these interface numbers are:
    
    "The purpose of the versions is exactly to avoid the need for a new
    soname.  The rules are basically:
    
       (1) You add stuff to the interface, strictly append-only to not break
           binary compatibility.
       (2) You bump the minor version of the interface.
       (3) You check the minor version at runtime to figure whenever the
           added fields contain valid stuff or not.
    
    An example is here (core interface, minor goes from 2 to 3, new
    channel_event callback):
    
    http://cgit.freedesktop.org/spice/spice/commit/?id=97f33fa86aa6edd25111b173dc0d9599ac29f879
    "
    
    The code currently refuses to create a channel if QEMU minor version is
    less than the current spice-server version. This does not correspond
    to the intended behaviour, this patch changes to fail is qemu was compiled
    with a spice-server that is *newer* than the one currently installed. This
    case is something we cannot support nicely.
    
    [1] http://lists.freedesktop.org/archives/spice-devel/2011-July/004440.html

diff --git a/server/reds.c b/server/reds.c
index c74b214..e97cd77 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4242,7 +4242,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
             return -1;
         }
         if (interface->major_version != SPICE_INTERFACE_KEYBOARD_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_KEYBOARD_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_KEYBOARD_MINOR) {
             red_printf("unsupported keyboard interface");
             return -1;
         }
@@ -4256,7 +4256,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
             return -1;
         }
         if (interface->major_version != SPICE_INTERFACE_MOUSE_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_MOUSE_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_MOUSE_MINOR) {
             red_printf("unsupported mouse interface");
             return -1;
         }
@@ -4268,7 +4268,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
 
         red_printf("SPICE_INTERFACE_QXL");
         if (interface->major_version != SPICE_INTERFACE_QXL_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_QXL_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_QXL_MINOR) {
             red_printf("unsupported qxl interface");
             return -1;
         }
@@ -4285,7 +4285,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
             return -1;
         }
         if (interface->major_version != SPICE_INTERFACE_TABLET_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_TABLET_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_TABLET_MINOR) {
             red_printf("unsupported tablet interface");
             return -1;
         }
@@ -4302,7 +4302,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
     } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
         red_printf("SPICE_INTERFACE_PLAYBACK");
         if (interface->major_version != SPICE_INTERFACE_PLAYBACK_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_PLAYBACK_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_PLAYBACK_MINOR) {
             red_printf("unsupported playback interface");
             return -1;
         }
@@ -4311,7 +4311,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
     } else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
         red_printf("SPICE_INTERFACE_RECORD");
         if (interface->major_version != SPICE_INTERFACE_RECORD_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_RECORD_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_RECORD_MINOR) {
             red_printf("unsupported record interface");
             return -1;
         }
@@ -4319,7 +4319,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
 
     } else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
         if (interface->major_version != SPICE_INTERFACE_CHAR_DEVICE_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_CHAR_DEVICE_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_CHAR_DEVICE_MINOR) {
             red_printf("unsupported char device interface");
             return -1;
         }
@@ -4334,7 +4334,7 @@ __visible__ int spice_server_add_interface(SpiceServer *s,
             return -1;
         }
         if (interface->major_version != SPICE_INTERFACE_NET_WIRE_MAJOR ||
-            interface->minor_version < SPICE_INTERFACE_NET_WIRE_MINOR) {
+            interface->minor_version > SPICE_INTERFACE_NET_WIRE_MINOR) {
             red_printf("unsupported net wire interface");
             return -1;
         }
commit c44878ff8d7c2af53c243579c930211ab34c3e42
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Jul 6 16:26:01 2011 +0200

    client: don't crash when agent is missing WAN support
    
    If you try to connect to a linux guest with WAN options, SPICE window opens up
    and is blank - it then fails with vdagent timeout message.  It should give a
    warning that this is only applicable for windows guest and still connect to
    guest.
    
    It all starts in RedClient::handle_init
    This function checks whether we have an agent or not, because if we have an
    agent, there will be some kind of handshake to check both sides capabilities
    before all the spice channels are created.
    
    When there is no agent running, the startup process goes on with
    SPICE_MSGC_MAIN_ATTACH_CHANNELS
    
    When there is a windows agent running, VD_AGENT_ANNOUNCE_CAPABILITIES and
    VD_AGENT_DISPLAY_CONFIG messages are sent to the agent, and when processing the
    agent answer to the VD_AGENT_DISPLAY_CONFIG message,
    SPICE_MSGC_MAIN_ATTACH_CHANNELS will be sent and the startup process will go
    on.
    
    However, when there is no agent running but --color-depth was used, handle_init
    won't send the SPICE_MSGC_MAIN_ATTACH_CHANNELS message but will wait for the
    agent handshake to proceed to its end, which won't happen, so it will timeout
    waiting for agent answers.
    
    Similarly, the linux agent handles VD_AGENT_ANNOUNCE_CAPABILITIES messages, but
    it doesn't handle VD_AGENT_DISPLAY_CONFIG messages, so we'll never reach the
    point where a SPICE_MSGC_MAIN_ATTACH_CHANNELS will be sent.
    
    This commit fixes this in 2 places:
    - unconditionnally send SPICE_MSGC_ATTACH_CHANNELS when no agent is running in
    handle_init
    - send SPICE_MSGC_MAIN_ATTACH_CHANNELS in
    RedClient::on_agent_announce_capabilities if the agent doesn't have the
    VD_AGENT_CAP_DISPLAY_CONFIG capability
    
    This fixes RH bug #712938

diff --git a/client/red_client.cpp b/client/red_client.cpp
index 4e3b2dd..5b757b8 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -963,19 +963,20 @@ void RedClient::handle_init(RedPeer::InMessage* message)
         agent_start.num_tokens = ~0;
         _marshallers->msgc_main_agent_start(msg->marshaller(), &agent_start);
         post_message(msg);
-    }
-
-    if (_agent_connected) {
         send_agent_announce_capabilities(true);
         if (_auto_display_res) {
            send_agent_monitors_config();
         }
-    }
-
-    if (!_auto_display_res && _display_setting.is_empty()) {
-        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+        if (_auto_display_res || !_display_setting.is_empty()) {
+            _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT);
+        } else {
+            post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+        }
     } else {
-        _application.activate_interval_timer(*_agent_timer, AGENT_TIMEOUT);
+        if (_auto_display_res || !_display_setting.is_empty()) {
+            LOG_WARN("no agent running, display options have been ignored");
+        }
+        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
     }
 }
 
@@ -1043,6 +1044,17 @@ void RedClient::on_agent_announce_capabilities(
         // not sending the color depth through send_agent_monitors_config, since
         // it applies only for attached screens.
         send_agent_display_config();
+    } else if (!_auto_display_res) {
+        /* some agents don't support monitors/displays agent messages, so
+         * we'll never reach on_agent_reply which sends this
+         * ATTACH_CHANNELS message which is needed for client startup to go
+         * on.
+         */
+        if (!_display_setting.is_empty()) {
+            LOG_WARN("display options have been requested, but the agent doesn't support these options");
+        }
+        post_message(new Message(SPICE_MSGC_MAIN_ATTACH_CHANNELS));
+        _application.deactivate_interval_timer(*_agent_timer);
     }
 }
 
commit 0e5452b0ba2e743a67d700744092b2cd48f36615
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 7 10:09:04 2011 +0200

    client: improve WAN option description
    
    The WAN options (--color-depth and --disable-effects) need
    support from the guest agent to be working. Currently they are
    only supported on Windows. While I don't want to explicitly
    mention Windows in --help output, we can hint that it won't
    work with all guests in --help. This fixes RH bug #712941

diff --git a/client/application.cpp b/client/application.cpp
index 9b787c1..810a6dd 100644
--- a/client/application.cpp
+++ b/client/application.cpp
@@ -2270,11 +2270,14 @@ bool Application::process_cmd_line(int argc, char** argv, bool &full_screen)
     parser.add(SPICE_OPT_CANVAS_TYPE, "canvas-type", "set rendering canvas", "canvas_type", true);
     parser.set_multi(SPICE_OPT_CANVAS_TYPE, ',');
 
-    parser.add(SPICE_OPT_DISPLAY_COLOR_DEPTH, "color-depth", "guest display color depth",
+    parser.add(SPICE_OPT_DISPLAY_COLOR_DEPTH, "color-depth",
+               "guest display color depth (if supported by the guest vdagent)",
                "16/32", true);
 
     parser.add(SPICE_OPT_DISABLE_DISPLAY_EFFECTS, "disable-effects",
-               "disable guest display effects", "wallpaper/font-smooth/animation/all", true);
+               "disable guest display effects " \
+               "(if supported by the guest vdagent)",
+               "wallpaper/font-smooth/animation/all", true);
     parser.set_multi(SPICE_OPT_DISABLE_DISPLAY_EFFECTS, ',');
 
     parser.add(SPICE_OPT_CONTROLLER, "controller", "enable external controller");
commit 0021a096e5076fe601a04da9cab5a1f50a91eadb
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 7 16:13:27 2011 +0200

    x11: don't return freed memory from get_clipboard
    
    There is a double free in client/x11/platform.cpp.
    In get_selection(), in the exit: case with ret_val == -1 and data != NULL,
    *data_ret (which is returned to the caller) has already been
    assigned "data", so it will be pointing to freed memory when "data" is
    XFree'd'. Then in handle_selection_notify, get_selection_free is called on
    this pointer, which causes a double free.
    When the length of the read data = 0, set the returned value to NULL,
    this way subsequent free attempts will be a noop.
    Fixes RH bug #710461

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index 1256ce7..1facf73 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -2572,8 +2572,12 @@ static int get_selection(XEvent &event, Atom type, Atom prop, int format,
         }
         len = clipboard_data_size;
         *data_ret = clipboard_data;
-    } else
-        *data_ret = data;
+    } else {
+        if (len > 0)
+            *data_ret = data;
+        else
+            *data_ret = NULL;
+    }
 
     if (len > 0)
         ret_val = len;
commit f6df14e5339ef104be37476fe06d8b9c94ac5f03
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Jul 7 20:03:21 2011 +0200

    client: match delete[] with new[]
    
    vinfo in x11/platform.cpp is allocated using new[] so it needs to
    be freed with delete[]

diff --git a/client/x11/platform.cpp b/client/x11/platform.cpp
index dbd2b6a..1256ce7 100644
--- a/client/x11/platform.cpp
+++ b/client/x11/platform.cpp
@@ -2878,7 +2878,7 @@ static void cleanup(void)
         for (i = 0; i < ScreenCount(x_display); ++i) {
             XFree(vinfo[i]);
         }
-        delete vinfo;
+        delete[] vinfo;
         vinfo = NULL;
     }
 #ifdef USE_OGL
commit 4c44be35b05670051d240ff2877940cef3d9b18c
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Tue Jul 12 08:50:34 2011 +0300

    server: fix access to a released drawable. RHBZ #713474
    
    red_pipe_add_drawable can lead to removal of drawables from current tree
    (since it calls red_handle_drawable_surfaces_client_synced), which can
    also lead to releasing these drawables.
    Before the fix, red_current_add_equal, called red_pipe_add_drawable,
    without assuring afterwards that the drawables it refers to are still alive or
    still in the current tree.

diff --git a/server/red_worker.c b/server/red_worker.c
index 72bdc31..4568696 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -2817,22 +2817,29 @@ static inline int red_current_add_equal(RedWorker *worker, DrawItem *item, TreeI
         int add_after = !!other_drawable->stream && is_drawable_independent_from_surfaces(drawable);
         red_stream_maintenance(worker, drawable, other_drawable);
         __current_add_drawable(worker, drawable, &other->siblings_link);
+        other_drawable->refs++;
+        current_remove_drawable(worker, other_drawable);
         if (add_after) {
             red_pipe_add_drawable_after(worker, drawable, other_drawable);
         } else {
             red_pipe_add_drawable(worker, drawable);
         }
-        remove_drawable(worker, other_drawable);
+        red_pipe_remove_drawable(worker, other_drawable);
+        release_drawable(worker, other_drawable);
         return TRUE;
     }
 
     switch (item->effect) {
     case QXL_EFFECT_REVERT_ON_DUP:
         if (is_same_drawable(worker, drawable, other_drawable)) {
+            other_drawable->refs++;
+            current_remove_drawable(worker, other_drawable);
             if (!ring_item_is_linked(&other_drawable->pipe_item.link)) {
                 red_pipe_add_drawable(worker, drawable);
+            } else {
+                red_pipe_remove_drawable(worker, other_drawable);
             }
-            remove_drawable(worker, other_drawable);
+            release_drawable(worker, other_drawable);
             return TRUE;
         }
         break;
commit e22354141e6b2cfdc71380e0815ff52d7f5131f6
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Wed Jun 15 17:21:02 2011 +0300

    server: add missing calls to red_handle_drawable_surfaces_client_synced
    
    red_handle_drawable_surfaces_client_synced was called only from red_pipe_add_drawable, while it
    should also be called from red_pipe_add_drawable_after. Otherwise, the client
    might receive a command with a reference to a surface it doesn't hold and crash.

diff --git a/server/red_worker.c b/server/red_worker.c
index f62db9f..72bdc31 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -1258,6 +1258,7 @@ static inline void red_pipe_add_drawable_to_tail(RedWorker *worker, Drawable *dr
     if (!worker->display_channel) {
         return;
     }
+    red_handle_drawable_surfaces_client_synced(worker, drawable);
     drawable->refs++;
     red_pipe_add_tail(&worker->display_channel->base, &drawable->pipe_item);
 }
@@ -1273,6 +1274,7 @@ static inline void red_pipe_add_drawable_after(RedWorker *worker, Drawable *draw
         red_pipe_add_drawable(worker, drawable);
         return;
     }
+    red_handle_drawable_surfaces_client_synced(worker, drawable);
     drawable->refs++;
     red_pipe_add_after(&worker->display_channel->base, &drawable->pipe_item, &pos_after->pipe_item);
 }
commit ec6198218a8280f3b5cd800c840ad30b41eff433
Author: Yonit Halperin <yhalperi at redhat.com>
Date:   Mon Jul 4 10:59:43 2011 +0300

    server: removing local cursor, this solves RHBZ #714801
    
    When the worker was stoped, the cursor was copied from guest ram to the host ram,
    and its corresponding qxl command was released.
    This is unecessary, since the qxl ram still exists (we keep references
    to the surfaces in the same manner).
    It also led to BSOD on guest upon migration: the device tracks cursor set commands and it stores
    a reference to the last one. Then, it replays it to the destination server when migrating to it.
    However, the command the qxl replayed has already been released from the pci by the original
    worker, upon STOP.
    
    Conflicts:
    
    	server/red_worker.c

diff --git a/server/red_worker.c b/server/red_worker.c
index 52070ee..f62db9f 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -232,7 +232,6 @@ enum {
     PIPE_ITEM_TYPE_INVAL_ONE,
     PIPE_ITEM_TYPE_CURSOR,
     PIPE_ITEM_TYPE_MIGRATE,
-    PIPE_ITEM_TYPE_LOCAL_CURSOR,
     PIPE_ITEM_TYPE_SET_ACK,
     PIPE_ITEM_TYPE_CURSOR_INIT,
     PIPE_ITEM_TYPE_IMAGE,
@@ -299,17 +298,10 @@ typedef struct SurfaceDestroyItem {
     PipeItem pipe_item;
 } SurfaceDestroyItem;
 
-enum {
-    CURSOR_TYPE_INVALID,
-    CURSOR_TYPE_DEV,
-    CURSOR_TYPE_LOCAL,
-};
-
 typedef struct CursorItem {
     PipeItem pipe_data;
     uint32_t group_id;
     int refs;
-    int type;
     RedCursorCmd *red_cursor;
 } CursorItem;
 
@@ -4182,11 +4174,6 @@ static void red_release_cursor(RedWorker *worker, CursorItem *cursor)
         QXLReleaseInfoExt release_info_ext;
         RedCursorCmd *cursor_cmd;
 
-        if (cursor->type == CURSOR_TYPE_LOCAL) {
-            free(cursor);
-            return;
-        }
-
         cursor_cmd = cursor->red_cursor;
         release_info_ext.group_id = cursor->group_id;
         release_info_ext.info = cursor_cmd->release_info;
@@ -4241,7 +4228,6 @@ static CursorItem *get_cursor_item(RedWorker *worker, RedCursorCmd *cmd, uint32_
 
     cursor_item->refs = 1;
     red_pipe_item_init(&cursor_item->pipe_data, PIPE_ITEM_TYPE_CURSOR);
-    cursor_item->type = CURSOR_TYPE_INVALID;
     cursor_item->group_id = group_id;
     cursor_item->red_cursor = cmd;
 
@@ -4256,7 +4242,6 @@ void qxl_process_cursor(RedWorker *worker, RedCursorCmd *cursor_cmd, uint32_t gr
     switch (cursor_cmd->type) {
     case QXL_CURSOR_SET:
         worker->cursor_visible = cursor_cmd->u.set.visible;
-        item->type = CURSOR_TYPE_DEV;
         red_set_cursor(worker, item);
         break;
     case QXL_CURSOR_MOVE:
@@ -6000,6 +5985,7 @@ static void fill_attr(DisplayChannel *display_channel, SpiceMarshaller *m, Spice
 
 static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor, CursorItem *cursor, AddBufInfo *addbuf)
 {
+    RedCursorCmd *cursor_cmd;
     addbuf->data = NULL;
 
     if (!cursor) {
@@ -6007,35 +5993,23 @@ static void fill_cursor(CursorChannel *cursor_channel, SpiceCursor *red_cursor,
         return;
     }
 
-    if (cursor->type == CURSOR_TYPE_DEV) {
-        RedCursorCmd *cursor_cmd;
-
-        cursor_cmd = cursor->red_cursor;
-        *red_cursor = cursor_cmd->u.set.shape;
+    cursor_cmd = cursor->red_cursor;
+    *red_cursor = cursor_cmd->u.set.shape;
 
-        if (red_cursor->header.unique) {
-            if (red_cursor_cache_find(cursor_channel, red_cursor->header.unique)) {
-                red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
-                return;
-            }
-            if (red_cursor_cache_add(cursor_channel, red_cursor->header.unique, 1)) {
-                red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
-            }
+    if (red_cursor->header.unique) {
+        if (red_cursor_cache_find(cursor_channel, red_cursor->header.unique)) {
+            red_cursor->flags |= SPICE_CURSOR_FLAGS_FROM_CACHE;
+            return;
         }
-
-        if (red_cursor->data_size) {
-            addbuf->type = BUF_TYPE_RAW;
-            addbuf->data = red_cursor->data;
-            addbuf->size = red_cursor->data_size;
+        if (red_cursor_cache_add(cursor_channel, red_cursor->header.unique, 1)) {
+            red_cursor->flags |= SPICE_CURSOR_FLAGS_CACHE_ME;
         }
-    } else {
-        LocalCursor *local_cursor;
-        ASSERT(cursor->type == CURSOR_TYPE_LOCAL);
-        local_cursor = (LocalCursor *)cursor;
-        *red_cursor = local_cursor->red_cursor;
+    }
+
+    if (red_cursor->data_size) {
         addbuf->type = BUF_TYPE_RAW;
-        addbuf->data = local_cursor->red_cursor.data;
-        addbuf->size = local_cursor->data_size;
+        addbuf->data = red_cursor->data;
+        addbuf->size = red_cursor->data_size;
     }
 }
 
@@ -8144,28 +8118,6 @@ static void red_send_cursor_init(CursorChannel *channel)
     red_begin_send_message(&channel->base, worker->cursor);
 }
 
-static void red_send_local_cursor(CursorChannel *cursor_channel, LocalCursor *cursor)
-{
-    RedChannel *channel;
-    SpiceMsgCursorSet cursor_set;
-    AddBufInfo info;
-
-    ASSERT(cursor_channel);
-
-    channel = &cursor_channel->base;
-    channel->send_data.header->type = SPICE_MSG_CURSOR_SET;
-    cursor_set.position = cursor->position;
-    cursor_set.visible = channel->worker->cursor_visible;
-
-    fill_cursor(cursor_channel, &cursor_set.cursor, &cursor->base, &info);
-    spice_marshall_msg_cursor_set(channel->send_data.marshaller, &cursor_set);
-    add_buf_from_info(channel, channel->send_data.marshaller, &info);
-
-    red_begin_send_message(channel, cursor);
-
-    red_release_cursor(channel->worker, (CursorItem *)cursor);
-}
-
 static void cursor_channel_send_migrate(CursorChannel *cursor_channel)
 {
     SpiceMsgMigrate migrate;
@@ -8394,9 +8346,6 @@ static void cursor_channel_push(RedWorker *worker)
         case PIPE_ITEM_TYPE_CURSOR:
             red_send_cursor(cursor_channel, (CursorItem *)pipe_item);
             break;
-        case PIPE_ITEM_TYPE_LOCAL_CURSOR:
-            red_send_local_cursor(cursor_channel, (LocalCursor *)pipe_item);
-            break;
         case PIPE_ITEM_TYPE_INVAL_ONE:
             red_cursor_send_inval(cursor_channel, (CacheItem *)pipe_item);
             free(pipe_item);
@@ -9590,52 +9539,6 @@ typedef struct __attribute__ ((__packed__)) CursorData {
     SpiceCursor _cursor;
 } CursorData;
 
-static LocalCursor *_new_local_cursor(SpiceCursorHeader *header, int data_size, SpicePoint16 position)
-{
-    LocalCursor *local;
-
-    local = (LocalCursor *)spice_malloc0(sizeof(LocalCursor) + data_size);
-
-    red_pipe_item_init(&local->base.pipe_data, PIPE_ITEM_TYPE_LOCAL_CURSOR);
-    local->base.refs = 1;
-    local->base.type = CURSOR_TYPE_LOCAL;
-
-    local->red_cursor.header = *header;
-    local->red_cursor.header.unique = 0;
-
-    local->red_cursor.flags = 0;
-    local->red_cursor.data = (uint8_t*)(local+1);
-
-    local->position = position;
-    local->data_size = data_size;
-    return local;
-}
-
-static void red_cursor_flush(RedWorker *worker)
-{
-    RedCursorCmd *cursor_cmd;
-    SpiceCursor *cursor;
-    LocalCursor *local;
-
-    if (!worker->cursor || worker->cursor->type == CURSOR_TYPE_LOCAL) {
-        return;
-    }
-
-    ASSERT(worker->cursor->type == CURSOR_TYPE_DEV);
-
-    cursor_cmd = worker->cursor->red_cursor;
-    ASSERT(cursor_cmd->type == QXL_CURSOR_SET);
-    cursor = &cursor_cmd->u.set.shape;
-
-    local = _new_local_cursor(&cursor->header, cursor->data_size,
-                              worker->cursor_position);
-    ASSERT(local);
-    memcpy(local->red_cursor.data, cursor->data, local->data_size);
-
-    red_set_cursor(worker, &local->base);
-    red_release_cursor(worker, &local->base);
-}
-
 static void red_wait_outgoing_item(RedChannel *channel)
 {
     uint64_t end_time;
@@ -10017,7 +9920,6 @@ static void handle_dev_input(EventListener *listener, uint32_t events)
                 red_current_flush(worker, x);
             }
         }
-        red_cursor_flush(worker);
         red_wait_outgoing_item((RedChannel *)worker->display_channel);
         red_wait_outgoing_item((RedChannel *)worker->cursor_channel);
         message = RED_WORKER_MESSAGE_READY;
commit a3a62248209a8a5a7c623b2a870e983424396fb9
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 13:40:12 2011 +0300

    server/smartcard: register channel only when hardware is available

diff --git a/server/reds.c b/server/reds.c
index 3488342..c74b214 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -4527,10 +4527,6 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
 
     inputs_init();
 
-#ifdef USE_SMARTCARD
-    smartcard_channel_init();
-#endif
-
     reds->mouse_mode = SPICE_MOUSE_MODE_SERVER;
     atexit(reds_exit);
     return 0;
diff --git a/server/smartcard.c b/server/smartcard.c
index 272098e..20a31f2 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -77,6 +77,7 @@ static void smartcard_on_message_from_device(
     SmartCardChannel *smartcard_channel, VSCMsgHeader *vheader);
 static SmartCardDeviceState* smartcard_device_state_new();
 static void smartcard_device_state_free(SmartCardDeviceState* st);
+static void smartcard_register_channel(void);
 
 void smartcard_char_device_wakeup(SpiceCharDeviceInstance *sin)
 {
@@ -162,6 +163,7 @@ static int smartcard_char_device_add_to_readers(SpiceCharDeviceInstance *char_de
     }
     state->reader_id = g_smartcard_readers.num;
     g_smartcard_readers.sin[g_smartcard_readers.num++] = char_device;
+    smartcard_register_channel();
     return 0;
 }
 
@@ -520,10 +522,16 @@ static void smartcard_migrate(Channel *channel)
 {
 }
 
-void smartcard_channel_init()
+static void smartcard_register_channel(void)
 {
     Channel *channel;
+    static int registered = 0;
 
+    if (registered) {
+        return;
+    }
+    red_printf("registering smartcard channel");
+    registered = 1;
     channel = spice_new0(Channel, 1);
     channel->type = SPICE_CHANNEL_SMARTCARD;
     channel->link = smartcard_link;
@@ -531,4 +539,3 @@ void smartcard_channel_init()
     channel->migrate = smartcard_migrate;
     reds_register_channel(channel);
 }
-
commit d830cf0553f1de1eb3a6eed1bf2e3dca880278d1
Author: Alon Levy <alevy at redhat.com>
Date:   Wed Jul 20 13:40:11 2011 +0300

    server/smartcard: handle BaseChannel messages
    
    According to spice.proto the smartcard channel can receive acks and any
    other message defined in BaseChannel. While the spicec implementation didn't
    send an ACK spice-gtk does, so handle it.

diff --git a/server/smartcard.c b/server/smartcard.c
index 7136d11..272098e 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -449,6 +449,11 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
     VSCMsgHeader* vheader = (VSCMsgHeader*)msg;
     SmartCardChannel* smartcard_channel = (SmartCardChannel*)channel;
 
+    if (header->type != SPICE_MSGC_SMARTCARD_DATA) {
+        /* handle ack's, spicy sends them while spicec does not */
+        return red_channel_handle_message(channel, header, msg);
+    }
+
     ASSERT(header->size == vheader->length + sizeof(VSCMsgHeader));
     switch (vheader->type) {
         case VSC_ReaderAdd:
commit b759a52fcdf18334b03555840fa23e9b7b9d5db5
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu May 19 15:59:07 2011 +0200

    add check for pyparsing
    
    Check both in configure.ac (after checking if we need to rebuild
    the marshalling files) and in the python script using pyparsing
    (for people modifying .proto files in tarballs)

diff --git a/configure.ac b/configure.ac
index 1064304..f158136 100644
--- a/configure.ac
+++ b/configure.ac
@@ -205,6 +205,16 @@ AC_SUBST(CELT051_LIBS)
 AC_SUBST(CELT051_LIBDIR)
 SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
 
+if test ! -e client/generated_marshallers.cpp; then
+AC_MSG_CHECKING([for pyparsing python module])
+echo "import pyparsing" | python - >/dev/null 2&>1
+if test $? -ne 0 ; then
+    AC_MSG_RESULT([not found])
+    AC_MSG_ERROR([pyparsing python module is required to compile this package])
+fi
+AC_MSG_RESULT([found])
+fi
+
 if test "$os_linux" = yes; then
 	PKG_CHECK_MODULES(ALSA, alsa)
 	AC_SUBST(ALSA_CFLAGS)
diff --git a/python_modules/spice_parser.py b/python_modules/spice_parser.py
index 43e930c..1d775bf 100644
--- a/python_modules/spice_parser.py
+++ b/python_modules/spice_parser.py
@@ -1,6 +1,11 @@
-from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
-        Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
-        alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
+try:
+    from pyparsing import Literal, CaselessLiteral, Word, OneOrMore, ZeroOrMore, \
+            Forward, delimitedList, Group, Optional, Combine, alphas, nums, restOfLine, cStyleComment, \
+            alphanums, ParseException, ParseResults, Keyword, StringEnd, replaceWith
+except ImportError:
+    print "Module pyparsing not found."
+    exit(1)
+
 
 import ptypes
 import sys
commit e482c1f640e397dfb277900873400015884adb1b
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Sun May 29 12:15:50 2011 +0300

    client/windows: enable image randomization (ASLR) rhbz#701111
    
    Enable image randomized base address, hindering some types of
    security attacks by making it more difficult for an attacker
    to predict target addresses.

diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index a937001..effb20c 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -249,7 +249,7 @@
 				SubSystem="2"
 				OptimizeReferences="2"
 				EnableCOMDATFolding="2"
-				RandomizedBaseAddress="1"
+				RandomizedBaseAddress="2"
 				DataExecutionPrevention="0"
 				TargetMachine="1"
 			/>
@@ -333,7 +333,7 @@
 				SubSystem="2"
 				OptimizeReferences="2"
 				EnableCOMDATFolding="2"
-				RandomizedBaseAddress="1"
+				RandomizedBaseAddress="2"
 				DataExecutionPrevention="0"
 				TargetMachine="17"
 			/>
commit e35b6804db1169fd09d630537f172eb16ee636a7
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Thu May 12 12:12:36 2011 +0300

    client/windows: undef SIZE_MAX in stdint.h
    
    eliminating redefinition warning

diff --git a/client/windows/stdint.h b/client/windows/stdint.h
index 45b133e..768ca03 100644
--- a/client/windows/stdint.h
+++ b/client/windows/stdint.h
@@ -293,7 +293,7 @@ typedef unsigned long long   uintmax_t;
 #define SIG_ATOMIC_MAX INT32_MAX
 
 
-
+#undef SIZE_MAX
 #define SIZE_MAX UINT32_MAX
 
 
commit 51bc5479219111af7cb215e58712f40228d723ca
Author: Zeeshan Ali (Khattak) <zeeshanak at gnome.org>
Date:   Wed May 4 20:39:20 2011 +0300

    server: Unset executable bit of red_tunnel_worker.h

diff --git a/server/red_tunnel_worker.h b/server/red_tunnel_worker.h
old mode 100755
new mode 100644
commit bc9d04576065b9bcdb6d1c62b48b37c332b10394
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date:   Tue Jan 25 16:17:12 2011 +0100

    common: spice_memdup could accept NULL
    
    (this patch is not to solve a crash fix, but to align with glib API)

diff --git a/common/mem.c b/common/mem.c
index a9bd6cc..db22d39 100644
--- a/common/mem.c
+++ b/common/mem.c
@@ -71,6 +71,10 @@ void *spice_memdup(const void *mem, size_t n_bytes)
 {
     void *copy;
 
+    if (mem == NULL) {
+        return NULL;
+    }
+
     copy = spice_malloc(n_bytes);
     memcpy(copy, mem, n_bytes);
     return copy;
commit 551ad336c1367c64d331e31dd3ea23e17e721b9b
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Apr 21 12:35:42 2011 +0200

    add missing "LGPLv2.1 or later" header to source files

diff --git a/client/gui/gui.cpp b/client/gui/gui.cpp
index d8513c6..eba241f 100644
--- a/client/gui/gui.cpp
+++ b/client/gui/gui.cpp
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "common.h"
 
 #include <limits.h>
diff --git a/client/gui/gui.h b/client/gui/gui.h
index 3b76b68..457c351 100644
--- a/client/gui/gui.h
+++ b/client/gui/gui.h
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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_GUI
 #define _H_GUI
 
diff --git a/client/gui/resource_provider.cpp b/client/gui/resource_provider.cpp
index 52e3381..2b5c44f 100644
--- a/client/gui/resource_provider.cpp
+++ b/client/gui/resource_provider.cpp
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "common.h"
 
 #include "resource_provider.h"
diff --git a/client/gui/resource_provider.h b/client/gui/resource_provider.h
index c313688..6f59cb8 100644
--- a/client/gui/resource_provider.h
+++ b/client/gui/resource_provider.h
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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_RESOURCE_PROVIDER
 #define _H_RESOURCE_PROVIDER
 
diff --git a/client/gui/softrenderer.cpp b/client/gui/softrenderer.cpp
index 87fffb8..bdc7a6c 100644
--- a/client/gui/softrenderer.cpp
+++ b/client/gui/softrenderer.cpp
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "common.h"
 #ifdef HAVE_CONFIG_H
 #include "config.h"
diff --git a/client/gui/softrenderer.h b/client/gui/softrenderer.h
index f5155ad..f25f79e 100644
--- a/client/gui/softrenderer.h
+++ b/client/gui/softrenderer.h
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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 _directfbrenderer_h_
 #define _directfbrenderer_h_
 
diff --git a/client/gui/softtexture.cpp b/client/gui/softtexture.cpp
index 562edea..a633f24 100644
--- a/client/gui/softtexture.cpp
+++ b/client/gui/softtexture.cpp
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "common.h"
 
 #ifdef HAVE_CONFIG_H
diff --git a/client/gui/softtexture.h b/client/gui/softtexture.h
index 788795f..65a4ece 100644
--- a/client/gui/softtexture.h
+++ b/client/gui/softtexture.h
@@ -1,4 +1,20 @@
-
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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 _softtexture_h_
 #define _softtexture_h_
 
diff --git a/client/smartcard_channel.cpp b/client/smartcard_channel.cpp
index 98f24a8..b086ad7 100644
--- a/client/smartcard_channel.cpp
+++ b/client/smartcard_channel.cpp
@@ -1,3 +1,19 @@
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include <spice/enums.h>
 
 #include "client/red_client.h"
diff --git a/client/smartcard_channel.h b/client/smartcard_channel.h
index 752713b..a84cbfd 100644
--- a/client/smartcard_channel.h
+++ b/client/smartcard_channel.h
@@ -1,3 +1,19 @@
+/*
+   Copyright (C) 2010 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 __SMART_CARD_H__
 #define __SMART_CARD_H__
 
diff --git a/client/zlib_decoder.cpp b/client/zlib_decoder.cpp
index 68b1b33..9cdadb3 100644
--- a/client/zlib_decoder.cpp
+++ b/client/zlib_decoder.cpp
@@ -1,3 +1,19 @@
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "common.h"
 #include "zlib_decoder.h"
 #include "debug.h"
diff --git a/server/smartcard.c b/server/smartcard.c
index 852110b..7136d11 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include <arpa/inet.h>
 
 #include "server/char_device.h"
diff --git a/server/smartcard.h b/server/smartcard.h
index 790eb87..b901183 100644
--- a/server/smartcard.h
+++ b/server/smartcard.h
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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 __SMART_CARD_H__
 #define __SMART_CARD_H__
 
diff --git a/server/zlib_encoder.c b/server/zlib_encoder.c
index e0d8d83..214180e 100644
--- a/server/zlib_encoder.c
+++ b/server/zlib_encoder.c
@@ -1,3 +1,20 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2010 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/>.
+*/
 #include "red_common.h"
 #include "zlib_encoder.h"
 #include <zlib.h>
commit 6bd492fa7975b90a3be31c65ba1fbafdd0002f0f
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Apr 19 22:58:36 2011 +0200

    common: add extern "C" guards to headers
    
    Since some spice C++ code is using code from common/, the C
    functions need to be marked as such for the C++ compiler, otherwise
    we'll get linkage issues.

diff --git a/common/canvas_base.h b/common/canvas_base.h
index 2166dcf..ff0f972 100644
--- a/common/canvas_base.h
+++ b/common/canvas_base.h
@@ -25,6 +25,10 @@
 #include "region.h"
 #include "draw.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef void (*spice_destroy_fn_t)(void *data);
 
 typedef struct _SpiceImageCache SpiceImageCache;
@@ -310,4 +314,8 @@ struct _SpiceCanvas {
   SpiceCanvasOps *ops;
 };
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/canvas_utils.h b/common/canvas_utils.h
index b87b816..ffed927 100644
--- a/common/canvas_utils.h
+++ b/common/canvas_utils.h
@@ -24,6 +24,10 @@
 #include "pixman_utils.h"
 #include "lz.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct PixmanData {
 #ifdef WIN32
     HBITMAP bitmap;
@@ -65,4 +69,8 @@ typedef struct LzDecodeUsrData {
 pixman_image_t *alloc_lz_image_surface(LzDecodeUsrData *canvas_data,
                                        pixman_format_code_t pixman_format, int width,
                                        int height, int gross_pixels, int top_down);
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/draw.h b/common/draw.h
index 95f07b8..68a083b 100644
--- a/common/draw.h
+++ b/common/draw.h
@@ -35,6 +35,10 @@
 #include <spice/enums.h>
 #include "mem.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define SPICE_GET_ADDRESS(addr) ((void *)(unsigned long)(addr))
 #define SPICE_SET_ADDRESS(addr, val) ((addr) = (unsigned long)(val))
 
@@ -271,4 +275,8 @@ typedef struct SpiceCursorHeader {
     uint16_t hot_spot_y;
 } SpiceCursorHeader;
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _H_SPICE_DRAW */
diff --git a/common/gdi_canvas.h b/common/gdi_canvas.h
index b3d4b15..5cdffb3 100644
--- a/common/gdi_canvas.h
+++ b/common/gdi_canvas.h
@@ -21,6 +21,10 @@
 
 #include <stdint.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #include "pixman_utils.h"
 #include "canvas_base.h"
 #include "region.h"
@@ -36,4 +40,8 @@ SpiceCanvas *gdi_canvas_create(int width, int height,
 
 void gdi_canvas_init();
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/gl_canvas.h b/common/gl_canvas.h
index d7125e6..4a15668 100644
--- a/common/gl_canvas.h
+++ b/common/gl_canvas.h
@@ -20,6 +20,13 @@
 #include "canvas_base.h"
 #include "region.h"
 
+#ifndef _H__GL_CANVAS
+#define _H__GL_CANVAS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
 #ifdef SW_CANVAS_CACHE
                            , SpiceImageCache *bits_cache
@@ -35,3 +42,8 @@ SpiceCanvas *gl_canvas_create(int width, int height, uint32_t format
 void gl_canvas_set_textures_lost(SpiceCanvas *canvas, int textures_lost);
 void gl_canvas_init();
 
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/common/gl_utils.h b/common/gl_utils.h
index eecff26..175f131 100644
--- a/common/gl_utils.h
+++ b/common/gl_utils.h
@@ -21,6 +21,10 @@
 #ifndef GL_UTILS_H
 #define GL_UTILS_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef RED_DEBUG
 #define GLC_ERROR_TEST_FLUSH {                                        \
     GLenum gl_err;  glFlush();                                        \
@@ -102,4 +106,8 @@ static inline int gl_get_to_power_two(unsigned int val)
     return 1 << find_msb(val);
 }
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/glc.h b/common/glc.h
index a6b8579..d77f003 100644
--- a/common/glc.h
+++ b/common/glc.h
@@ -23,6 +23,10 @@
 
 #include <stdint.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef void * GLCCtx;
 typedef void * GLCPattern;
 typedef void * GLCPath;
@@ -156,4 +160,8 @@ void glc_clear(GLCCtx glc);
 GLCCtx glc_create(int width, int height);
 void glc_destroy(GLCCtx glc, int textures_lost);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/lines.h b/common/lines.h
index 1d092f0..73eef9b 100644
--- a/common/lines.h
+++ b/common/lines.h
@@ -54,6 +54,10 @@ SOFTWARE.
 #include <string.h>
 #include "draw.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct lineGC lineGC;
 
 typedef struct {
@@ -127,4 +131,8 @@ extern int spice_canvas_clip_spans(pixman_region32_t *clip_region,
                                    int *new_widths,
                                    int sorted);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* LINES_H */
diff --git a/common/lz.h b/common/lz.h
index 993609f..472e34d 100644
--- a/common/lz.h
+++ b/common/lz.h
@@ -10,6 +10,10 @@
 #include "lz_config.h"
 #include "draw.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef void *LzContext;
 
 typedef struct LzUsrContext LzUsrContext;
@@ -71,5 +75,8 @@ LzContext *lz_create(LzUsrContext *usr);
 
 void lz_destroy(LzContext *lz);
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif  // __LZ_H
diff --git a/common/lz_common.h b/common/lz_common.h
index 34276af..4156cff 100644
--- a/common/lz_common.h
+++ b/common/lz_common.h
@@ -23,6 +23,10 @@
 #ifndef _LZ_COMMON_H
 #define _LZ_COMMON_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 //#define DEBUG
 
 /* change the max window size will require change in the encoding format*/
@@ -58,5 +62,8 @@ static const int RGB_BYTES_PER_PIXEL[] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 4, 4};
 #define LZ_VERSION_MINOR 1U
 #define LZ_VERSION ((LZ_VERSION_MAJOR << 16) | (LZ_VERSION_MINOR & 0xffff))
 
+#ifdef __cplusplus
+}
+#endif
 
 #endif  // _LZ_COMMON_H
diff --git a/common/marshaller.h b/common/marshaller.h
index 4d77140..0a61fef 100644
--- a/common/marshaller.h
+++ b/common/marshaller.h
@@ -25,6 +25,10 @@
 #include <sys/uio.h>
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct SpiceMarshaller SpiceMarshaller;
 typedef void (*spice_marshaller_item_free_func)(uint8_t *data, void *opaque);
 
@@ -63,4 +67,8 @@ void *spice_marshaller_add_int8(SpiceMarshaller *m, int8_t v);
 
 void  spice_marshaller_set_uint32(SpiceMarshaller *m, void *ref, uint32_t v);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/mem.h b/common/mem.h
index 797bba0..e5937fd 100644
--- a/common/mem.h
+++ b/common/mem.h
@@ -22,6 +22,10 @@
 #include <stdlib.h>
 #include <spice/macros.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct SpiceChunk {
     uint8_t *data;
     uint32_t len;
@@ -120,4 +124,8 @@ 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);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
diff --git a/common/messages.h b/common/messages.h
index 1a60a9f..6fcd8be 100644
--- a/common/messages.h
+++ b/common/messages.h
@@ -34,6 +34,10 @@
 #include <spice/protocol.h>
 #include "draw.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct SpiceMsgData {
     uint32_t data_size;
     uint8_t data[0];
@@ -494,6 +498,8 @@ typedef struct SpiceMsgcTunnelSocketTokens {
     uint32_t num_tokens;
 } SpiceMsgcTunnelSocketTokens;
 
-#endif /* _H_SPICE_PROTOCOL */
-
+#ifdef __cplusplus
+}
+#endif
 
+#endif /* _H_SPICE_PROTOCOL */
diff --git a/common/mutex.h b/common/mutex.h
index a2d35de..6789b8f 100644
--- a/common/mutex.h
+++ b/common/mutex.h
@@ -18,6 +18,11 @@
 
 #ifndef _H_MUTEX
 #define _H_MUTEX
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef _WIN32
 #include <windows.h>
 typedef CRITICAL_SECTION mutex_t;
@@ -32,4 +37,8 @@ typedef pthread_mutex_t mutex_t;
 #define MUTEX_UNLOCK(mutex) pthread_mutex_unlock(&mutex)
 #endif
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif // _H_MUTEX
diff --git a/common/ogl_ctx.h b/common/ogl_ctx.h
index 3abe6d7..ae2ce7e 100644
--- a/common/ogl_ctx.h
+++ b/common/ogl_ctx.h
@@ -19,6 +19,10 @@
 #ifndef _H_GLCTX
 #define _H_GLCTX
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct OGLCtx OGLCtx;
 
 const char *oglctx_type_str(OGLCtx *ctx);
@@ -27,5 +31,9 @@ OGLCtx *pbuf_create(int width, int heigth);
 OGLCtx *pixmap_create(int width, int heigth);
 void oglctx_destroy(OGLCtx *ctx);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/pixman_utils.h b/common/pixman_utils.h
index e15b682..61eaddd 100644
--- a/common/pixman_utils.h
+++ b/common/pixman_utils.h
@@ -26,6 +26,10 @@
 
 #include "draw.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /* This lists all possible 2 argument binary raster ops.
  * This enum has the same values as the X11 GXcopy type
  * and same as the GL constants (GL_AND etc) if you
@@ -125,4 +129,8 @@ void spice_pixman_copy_rect(pixman_image_t *image,
                             int w, int h,
                             int dest_x, int dest_y);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _H__PIXMAN_UTILS */
diff --git a/common/quic.h b/common/quic.h
index f4ef854..d031777 100644
--- a/common/quic.h
+++ b/common/quic.h
@@ -21,6 +21,10 @@
 
 #include "quic_config.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef enum {
     QUIC_IMAGE_TYPE_INVALID,
     QUIC_IMAGE_TYPE_GRAY,
@@ -61,5 +65,9 @@ void quic_destroy(QuicContext *quic);
 
 void quic_init();
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/quic_config.h b/common/quic_config.h
index 1273dbc..da5e51c 100644
--- a/common/quic_config.h
+++ b/common/quic_config.h
@@ -21,6 +21,10 @@
 
 #include <spice/types.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef __GNUC__
 
 #include <string.h>
@@ -47,5 +51,9 @@
 
 #endif
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/rect.h b/common/rect.h
index cdd4335..6d7c446 100644
--- a/common/rect.h
+++ b/common/rect.h
@@ -22,6 +22,10 @@
 #include "draw.h"
 #include <spice/macros.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 static inline void rect_sect(SpiceRect* r, const SpiceRect* bounds)
 {
     r->left = MAX(r->left, bounds->left);
@@ -73,6 +77,10 @@ static inline int rect_is_same_size(const SpiceRect *r1, const SpiceRect *r2)
 }
 
 #ifdef __cplusplus
+}
+#endif
+
+#ifdef __cplusplus
 
 static inline void rect_sect(SpiceRect& r, const SpiceRect& bounds)
 {
diff --git a/common/region.h b/common/region.h
index bad7494..16ec6eb 100644
--- a/common/region.h
+++ b/common/region.h
@@ -23,6 +23,10 @@
 #include "draw.h"
 #include <pixman_utils.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef pixman_region32_t QRegion;
 
 #define REGION_TEST_LEFT_EXCLUSIVE (1 << 0)
@@ -59,5 +63,9 @@ void region_offset(QRegion *rgn, int32_t dx, int32_t dy);
 
 void region_dump(const QRegion *rgn, const char *prefix);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/ring.h b/common/ring.h
index defa1ed..133aad0 100644
--- a/common/ring.h
+++ b/common/ring.h
@@ -19,6 +19,10 @@
 #ifndef _H_RING2
 #define _H_RING2
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef struct Ring RingItem;
 typedef struct Ring {
     RingItem *prev;
@@ -129,5 +133,9 @@ static inline RingItem *ring_prev(Ring *ring, RingItem *pos)
     return (ret == ring) ? NULL : ret;
 }
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/rop3.h b/common/rop3.h
index 0211130..549b02c 100644
--- a/common/rop3.h
+++ b/common/rop3.h
@@ -24,11 +24,20 @@
 #include "draw.h"
 #include "pixman_utils.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 void do_rop3_with_pattern(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                           pixman_image_t *p, SpicePoint *pat_pos);
 void do_rop3_with_color(uint8_t rop3, pixman_image_t *d, pixman_image_t *s, SpicePoint *src_pos,
                         uint32_t rgb);
 
 void rop3_init();
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 
diff --git a/common/sw_canvas.h b/common/sw_canvas.h
index 99deac8..42f2573 100644
--- a/common/sw_canvas.h
+++ b/common/sw_canvas.h
@@ -26,6 +26,10 @@
 #include "canvas_base.h"
 #include "region.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 SpiceCanvas *canvas_create(int width, int height, uint32_t format
 #ifdef SW_CANVAS_CACHE
                            , SpiceImageCache *bits_cache
@@ -55,4 +59,8 @@ SpiceCanvas *canvas_create_for_data(int width, int height, uint32_t format, uint
 
 void sw_canvas_init();
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
commit 3dab7bda53901a80e15b98392fb8948b2f298ca1
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Wed Apr 20 10:06:36 2011 +0200

    configure.ac: replace tab with spaces
    
    This makes the "C++ Compiler:     ...." status output nicely
    aligned with the other messages.

diff --git a/configure.ac b/configure.ac
index e6daa26..1064304 100644
--- a/configure.ac
+++ b/configure.ac
@@ -497,7 +497,7 @@ echo "
 
         prefix:                   ${prefix}
         c compiler:               ${CC}
-        c++ compiler:	          ${CXX}
+        c++ compiler:             ${CXX}
 
         Have XRANDR 1.2:          ${have_xrandr12}
 
commit 0244f9a4b4f8a30b2e9747d9f0fa67a85826c6a7
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Apr 19 18:49:56 2011 +0200

    configure.ac: remove unused dynamic linkage flag
    
    configure.ac defines a SPICEC_STATIC_LINKAGE_BDYNAMIC variable
    when --enable-static-linkage is not set, but it's never used.
    SPICEC_STATIC_LINKAGE_BSTATIC is used in client/, but since we
    are using libtool, it might be more appropriate to use
    'make LDFLAGS="-all-static"' to achieve static link.

diff --git a/configure.ac b/configure.ac
index 2aff434..e6daa26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -271,8 +271,7 @@ AC_ARG_ENABLE(static-linkage,
 [  --enable-static-linkage will generate spice client binary with static linkage to external libraries ],,
 [enable_static_linkage="no"])
 AS_IF([test x"$enable_static_linkage" != "xno"],
-[SPICEC_STATIC_LINKAGE_BSTATIC=["-Wl,-Bstatic"]],
-[SPICEC_STATIC_LINKAGE_BDYNAMIC=["-Wl,-Bdynamic"]])
+[SPICEC_STATIC_LINKAGE_BSTATIC=["-Wl,-Bstatic"]])
 
 
 AS_IF([test "$_cflags_is_set" = "yes"], [], [
@@ -471,7 +470,6 @@ AC_SUBST(SPICE_NONPKGCONFIG_CFLAGS)
 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])])
 
commit 2f8c25d986543e202194660df2c038268ca2f9a1
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Tue Apr 19 18:42:32 2011 +0200

    configure.ac: fix use of AC_ARG_ENABLE
    
    Most uses of AC_ARG_ENABLE were buggy:
    - when passing --disable-xxx, configure.ac would behave as if it
      was passed --enable-xxx
    - passing --enable-xxx=foo would "leak" into the summary, ie the
      summary (at the end of configure) would say "xxx: foo" instead
      of "xxx: yes"
    
    This patch fixes these 2 issues.

diff --git a/configure.ac b/configure.ac
index 8f3831d..2aff434 100644
--- a/configure.ac
+++ b/configure.ac
@@ -93,33 +93,33 @@ AM_CONDITIONAL(OS_LINUX, test "$os_linux" = "yes")
 
 dnl =========================================================================
 dnl Chek optional features
-have_tunnel=no
 AC_ARG_ENABLE(tunnel,
-[  --enable-tunnel         Enable network redirection],
-[  have_tunnel=yes])
-AM_CONDITIONAL(SUPPORT_TUNNEL, test "x$have_tunnel" = "xyes")
-if test "x$have_tunnel" = "xyes"; then
+[  --enable-tunnel         Enable network redirection],,
+[enable_tunnel="no"])
+AS_IF([test x"$enable_tunnel" != "xno"], [enable_tunnel="yes"])
+AM_CONDITIONAL(SUPPORT_TUNNEL, test "x$enable_tunnel" != "xno")
+if test "x$enable_tunnel" != "xno"; then
    AC_DEFINE(USE_TUNNEL, [1], [Define if supporting tunnel proxying])
 fi
 
-use_gui=no
 AC_ARG_ENABLE(gui,
-[  --enable-gui         Enable start dialog with CEGUI],
-[  use_gui=yes])
-AM_CONDITIONAL(SUPPORT_GUI, test "x$use_gui" = "xyes")
+[  --enable-gui         Enable start dialog with CEGUI],,
+[enable_gui="no"])
+AS_IF([test x"$enable_gui" != "xno"], [enable_gui="yes"])
+AM_CONDITIONAL(SUPPORT_GUI, test "x$enable_gui" != "xno")
 
-have_opengl=no
 AC_ARG_ENABLE(opengl,
-[  --enable-opengl         Enable opengl requirement / support (not recommended)],
-[  have_opengl=yes])
-AM_CONDITIONAL(SUPPORT_GL, test "x$have_opengl" = "xyes")
+[  --enable-opengl         Enable opengl requirement / support (not recommended)],,
+[enable_opengl="no"])
+AS_IF([test x"$enable_opengl" != "xno"], [enable_opengl="yes"])
+AM_CONDITIONAL(SUPPORT_GL, test "x$enable_opengl" = "xyes")
 
-have_smartcard=no
 AC_ARG_ENABLE(smartcard,
-[  --enable-smartcard         Enable network redirection],
-[  have_smartcard=yes])
-AM_CONDITIONAL(SUPPORT_SMARTCARD, test "x$have_smartcard" = "xyes")
-if test "x$have_smartcard" = "xyes"; then
+[  --enable-smartcard         Enable network redirection],,
+[enable_smartcard="no"])
+AS_IF([test x"$enable_smartcard" != "xno"], [enable_smartcard="yes"])
+AM_CONDITIONAL(SUPPORT_SMARTCARD, test "x$enable_smartcard" != "xno")
+if test "x$enable_smartcard" = "xyes"; then
    AC_DEFINE(USE_SMARTCARD, [1], [Define if supporting smartcard proxying])
 fi
 
@@ -162,7 +162,7 @@ AC_DEFINE_UNQUOTED(POSIX_YIELD_FUNC,$posix_yield_func,[The POSIX RT yield functi
 
 SPICE_REQUIRES=""
 
-if test "x$use_gui" = "xyes"; then
+if test "x$enable_gui" = "xyes"; then
     PKG_CHECK_MODULES(CEGUI06, CEGUI-0.6 >= 0.6.0 CEGUI-0.6 < 0.7.0,
     [
         AC_SUBST(CEGUI06_CFLAGS)
@@ -177,7 +177,7 @@ if test "x$use_gui" = "xyes"; then
     ])
 fi
 
-if test "x$have_tunnel" = "xyes"; then
+if test "x$enable_tunnel" = "xyes"; then
 	PKG_CHECK_MODULES(SLIRP, slirp)
 	AC_SUBST(SLIRP_CFLAGS)
 	AC_SUBST(SLIRP_LIBS)
@@ -185,7 +185,7 @@ if test "x$have_tunnel" = "xyes"; then
 	AC_DEFINE([HAVE_SLIRP], [], [Define if we have slirp])
 fi
 
-if test "x$have_smartcard" = "xyes"; then
+if test "x$enable_smartcard" = "xyes"; then
     PKG_CHECK_MODULES(CAC_CARD, libcacard >= 0.1.2)
     SMARTCARD_LIBS="$CAC_CARD_LIBS"
     SMARTCARD_CFLAGS="$CAC_CARD_CFLAGS"
@@ -224,12 +224,12 @@ SPICE_REQUIRES+=" openssl"
 # AC_SUBST(GL_LIBS)
 # SPICE_REQUIRES+=" gl glu"
 
-if test "x$have_opengl" = "xyes"; then
-   AC_CHECK_LIB(GL, glBlendFunc, GL_LIBS="$GL_LIBS -lGL", have_opengl=no)
-   AC_CHECK_LIB(GLU, gluSphere, GL_LIBS="$GL_LIBS -lGLU", have_opengl=no)
+if test "x$enable_opengl" = "xyes"; then
+   AC_CHECK_LIB(GL, glBlendFunc, GL_LIBS="$GL_LIBS -lGL", enable_opengl=no)
+   AC_CHECK_LIB(GLU, gluSphere, GL_LIBS="$GL_LIBS -lGLU", enable_opengl=no)
    GL_CFLAGS="-DGL_GLEXT_PROTOTYPES -DUSE_OGL"
 
-   if test "x$have_opengl" = "xno"; then
+   if test "x$enable_opengl" = "xno"; then
       AC_MSG_ERROR([GL libraries not available])
    fi
 fi
@@ -267,10 +267,12 @@ fi
 
 # Add parameter for (partial) static linkage of spice client.
 # this is used to achive single binary package for all (?) distros.
-AC_ARG_ENABLE(static-linkage, 
-	[  --enable-static-linkage will generate spice client binary with static linkage to external libraries ],
-	[SPICEC_STATIC_LINKAGE_BSTATIC=["-Wl,-Bstatic"];
-	SPICEC_STATIC_LINKAGE_BDYNAMIC=["-Wl,-Bdynamic"]])
+AC_ARG_ENABLE(static-linkage,
+[  --enable-static-linkage will generate spice client binary with static linkage to external libraries ],,
+[enable_static_linkage="no"])
+AS_IF([test x"$enable_static_linkage" != "xno"],
+[SPICEC_STATIC_LINKAGE_BSTATIC=["-Wl,-Bstatic"]],
+[SPICEC_STATIC_LINKAGE_BDYNAMIC=["-Wl,-Bdynamic"]])
 
 
 AS_IF([test "$_cflags_is_set" = "yes"], [], [
@@ -501,15 +503,15 @@ echo "
 
         Have XRANDR 1.2:          ${have_xrandr12}
 
-        Support tunneling:        ${have_tunnel}
+        Support tunneling:        ${enable_tunnel}
 
         Red target:               ${red_target}
 
-        OpenGL:                   ${have_opengl}
+        OpenGL:                   ${enable_opengl}
 
-        GUI:                      ${use_gui}
+        GUI:                      ${enable_gui}
 
-        Smartcard:                ${have_smartcard}
+        Smartcard:                ${enable_smartcard}
 
         SASL support:             ${enable_sasl}
 
commit 03004a57d538b607a04d45f4b596e98f775e619a
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Apr 9 21:41:12 2011 +0300

    spice.proto: Fill.rop_descriptor type s/uint16/ropd (10x atiti)

diff --git a/spice.proto b/spice.proto
index 4eeb159..6160de1 100644
--- a/spice.proto
+++ b/spice.proto
@@ -639,7 +639,7 @@ channel DisplayChannel : BaseChannel {
 	DisplayBase base;
 	struct Fill {
 	    Brush brush @outvar(brush);
-	    uint16 rop_descriptor;
+	    ropd rop_descriptor;
 	    QMask mask @outvar(mask);
 	} data;
     } draw_fill = 302;
commit 2bd98219f37ef0ed711e61c8f4c705f0058d78eb
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Apr 14 17:02:16 2011 +0200

    client: s/reqired/required in CmdLineParser

diff --git a/client/cmd_line_parser.cpp b/client/cmd_line_parser.cpp
index f503c5c..35e43aa 100644
--- a/client/cmd_line_parser.cpp
+++ b/client/cmd_line_parser.cpp
@@ -119,7 +119,7 @@ void CmdLineParser::add(int id, const std::string& name, const std::string& help
 }
 
 void CmdLineParser::add(int id, const std::string& name, const std::string& help,
-                        const std::string& arg_name, bool reqired_arg, char short_name)
+                        const std::string& arg_name, bool required_arg, char short_name)
 {
     if (id < OPTION_FIRST_AVAILABLE) {
         THROW("invalid id");
@@ -129,7 +129,7 @@ void CmdLineParser::add(int id, const std::string& name, const std::string& help
         THROW("invalid arg name");
     }
 
-    add_private(id, name, short_name, reqired_arg ? REQUIRED_ARGUMENT : OPTIONAL_ARGUMENT, help,
+    add_private(id, name, short_name, required_arg ? REQUIRED_ARGUMENT : OPTIONAL_ARGUMENT, help,
                 arg_name);
 }
 
@@ -156,7 +156,7 @@ void CmdLineParser::set_multi(int id, char seperator)
     opt->seperator = seperator;
 }
 
-void CmdLineParser::set_reqired(int id)
+void CmdLineParser::set_required(int id)
 {
     if (_argv) {
         THROW("unexpected");
diff --git a/client/cmd_line_parser.h b/client/cmd_line_parser.h
index 6e6c6d5..37b5660 100644
--- a/client/cmd_line_parser.h
+++ b/client/cmd_line_parser.h
@@ -35,9 +35,9 @@ public:
              char short_name = 0);
 
     void add(int id, const std::string& name, const std::string& help,
-             const std::string& arg_name, bool reqired_arg, char short_name = 0);
+             const std::string& arg_name, bool required_arg, char short_name = 0);
     void set_multi(int id, char seperator);
-    void set_reqired(int id);
+    void set_required(int id);
 
     void begin(int argc, char** argv);
     int get_option(char** val);
commit fdfc940f59057fd9a540ff30b0fc027b3240d30e
Author: Christophe Fergeau <cfergeau at gmail.com>
Date:   Tue Mar 22 12:58:27 2011 +0100

    server/tests remove useless assignment
    
    This was detected by clang-static-analyzer.

diff --git a/server/tests/basic_event_loop.c b/server/tests/basic_event_loop.c
index f6570ff..1d54ed0 100644
--- a/server/tests/basic_event_loop.c
+++ b/server/tests/basic_event_loop.c
@@ -300,7 +300,6 @@ void basic_event_loop_mainloop(void)
     while (1) {
         FD_ZERO(&rfds);
         FD_ZERO(&wfds);
-        watch = (SpiceWatch*)watches.next;
         i = 0;
         RING_FOREACH_SAFE(link, next, &watches) {
             watch = (SpiceWatch*)link;
commit e77fc7e8779a63cf8e10ece822192bd81e573183
Author: Christophe Fergeau <cfergeau at gmail.com>
Date:   Tue Mar 22 11:48:54 2011 +0100

    common/pixman: remove dead assignments
    
    They were detected using clang-static-analyzer. Don't initialize
    the variable to a value to override it with a different value
    a few lines after.

diff --git a/common/pixman_utils.c b/common/pixman_utils.c
index bdc18c9..5daee27 100644
--- a/common/pixman_utils.c
+++ b/common/pixman_utils.c
@@ -785,9 +785,7 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
 
         while (height--) {
             uint8_t *d = (uint8_t *)byte_line;
-            uint8_t *s = (uint8_t *)byte_line;
-
-            s = (uint8_t *)src_line;
+            uint8_t *s = (uint8_t *)src_line;
             for (x = 0; x < width; x++) {
                 uint8_t val = *s;
                 if (val != (uint8_t)transparent_color) {
@@ -805,9 +803,8 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
 
         while (height--) {
             uint16_t *d = (uint16_t *)byte_line;
-            uint16_t *s = (uint16_t *)byte_line;
+            uint16_t *s = (uint16_t *)src_line;
 
-            s = (uint16_t *)src_line;
             for (x = 0; x < width; x++) {
                 uint16_t val = *s;
                 if (val != (uint16_t)transparent_color) {
@@ -826,10 +823,9 @@ void spice_pixman_blit_colorkey (pixman_image_t *dest,
 
         while (height--) {
             uint32_t *d = (uint32_t *)byte_line;
-            uint32_t *s = (uint32_t *)byte_line;
+            uint32_t *s = (uint32_t *)src_line;
 
             transparent_color &= 0xffffff;
-            s = (uint32_t *)src_line;
             for (x = 0; x < width; x++) {
                 uint32_t val = *s;
                 if ((0xffffff & val) != transparent_color) {
commit 96555db49a4a04c6796ed7d823a2856adb48bee7
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Apr 7 18:05:42 2011 +0200

    gl: remove unused variables
    
    gcc 4.6 warned about these.

diff --git a/client/x11/red_pixmap_gl.cpp b/client/x11/red_pixmap_gl.cpp
index 7c85966..0e7b8c1 100644
--- a/client/x11/red_pixmap_gl.cpp
+++ b/client/x11/red_pixmap_gl.cpp
@@ -175,10 +175,7 @@ void RedPixmapGL::update_texture(const SpiceRect *bbox)
 {
     RenderType rendertype;
     GLuint tex;
-    int width_powed;
-    int height_powed;
     int height;
-    int width;
 
     rendertype = ((PixelsSource_p*)get_opaque())->gl.rendertype;
 
@@ -189,9 +186,6 @@ void RedPixmapGL::update_texture(const SpiceRect *bbox)
         int is_enabled;
         GLint prev_tex;
 
-        width_powed = ((PixelsSource_p*)get_opaque())->gl.width_powed;
-        height_powed = ((PixelsSource_p*)get_opaque())->gl.height_powed;
-        width = ((PixelsSource_p*)get_opaque())->gl.width;
         height = ((PixelsSource_p*)get_opaque())->gl.height;
 
         tex = ((PixelsSource_p*)get_opaque())->gl.tex;
commit dda8e3f62c6b65356d84080799b1922f1a5164b8
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Apr 7 18:05:41 2011 +0200

    gl: use correct pixman accessor for image data
    
    Commit 774e5bd36f4 changed
    -  dest->source.pixmap.x_image->data +
    +  (uint8_t *)pixman_image_get_stride(dest->source.pixmap.pixman_image) +
    
    The correct accessor to use is pixman_image_get_data. Thanks to gcc
    4.6 for warning about a "different size" int to pointer conversion.

diff --git a/client/x11/red_drawable.cpp b/client/x11/red_drawable.cpp
index e7151ed..19dcd92 100644
--- a/client/x11/red_drawable.cpp
+++ b/client/x11/red_drawable.cpp
@@ -353,7 +353,7 @@ static inline void copy_to_pixmap_from_gltexture(const RedDrawable_p* dest,
     while (height > 0) {
         glReadPixels(src_x, y - height, area.right - area.left, 1,
                      GL_BGRA, GL_UNSIGNED_BYTE,
-                     (uint8_t *)pixman_image_get_stride(dest->source.pixmap.pixman_image) +
+                     (uint8_t *)pixman_image_get_data(dest->source.pixmap.pixman_image) +
                      (area.left + offset.x) * 4 +
                      (area.top + offset.y + height - 1) *
                      pixman_image_get_stride(dest->source.pixmap.pixman_image));
commit 416009c0c17ebd1bbe9061de686b65d1b5d2550a
Author: Christophe Fergeau <cfergeau at redhat.com>
Date:   Thu Apr 7 18:05:40 2011 +0200

    client: use silent generation rules in Makefile.am
    
    The server Makefile.am rules for marshallers generation are
    prefixed with AM_V_SILENT to integrate nicely with automake silent
    rules. The same AM_V_SILENT prefix isn't used in client/Makefile.am
    resulting in verbose output even when automake silent mode is
    enabled. This commit removes this verbosity.

diff --git a/client/Makefile.am b/client/Makefile.am
index da859f4..a5effed 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -6,16 +6,16 @@ DIST_SUBDIRS = x11 windows gui
 spice_built_sources = generated_demarshallers.cpp generated_marshallers.cpp generated_demarshallers1.cpp generated_marshallers1.cpp
 
 generated_demarshallers.cpp: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h $(top_srcdir)/spice.proto generated_demarshallers.cpp
 
 generated_demarshallers1.cpp: $(top_srcdir)/spice1.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_demarshallers1.cpp
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-demarshallers --client --include common.h --include messages.h --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_demarshallers1.cpp
 
 generated_marshallers.cpp: $(top_srcdir)/spice.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P  --include "common.h" --include messages.h --include marshallers.h --client $(top_srcdir)/spice.proto generated_marshallers.cpp
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P  --include "common.h" --include messages.h --include marshallers.h --client $(top_srcdir)/spice.proto generated_marshallers.cpp
 
 generated_marshallers1.cpp: $(top_srcdir)/spice1.proto
-	$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P  --include "common.h" --include messages.h --include marshallers.h --client --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_marshallers1.cpp
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-marshallers -P  --include "common.h" --include messages.h --include marshallers.h --client --prefix 1 --ptrsize 8 $(top_srcdir)/spice1.proto generated_marshallers1.cpp
 
 if SUPPORT_GL
 GL_SRCS =				\
commit 4ef1b8c331e03f6a41aad028dc4f44608eec7e6b
Author: Christophe Fergeau <cfergeau at gmail.com>
Date:   Tue Mar 22 17:22:08 2011 +0100

    common/gl: remove unused variable
    
    clang static analyzer warned that 'len' was computed but never
    used in glc_vertex2d. glc_stroke_line_dash has side effects so
    we have to call it, but we don't need to save its return value
    since it's not used.

diff --git a/common/glc.c b/common/glc.c
index e4263cd..e58718f 100644
--- a/common/glc.c
+++ b/common/glc.c
@@ -1147,10 +1147,9 @@ static double glc_stroke_line_dash(double x1, double y1, double x2, double y2,
 
 static void glc_vertex2d(InternaCtx *ctx, double x, double y)
 {
-    double len;
     if (ctx->path_stroke.state == GLC_STROKE_ACTIVE) {
-        len = glc_stroke_line_dash(ctx->path_stroke.x, ctx->path_stroke.y, x, y,
-                                   ctx->line_width, &ctx->line_dash);
+        glc_stroke_line_dash(ctx->path_stroke.x, ctx->path_stroke.y, x, y,
+                             ctx->line_width, &ctx->line_dash);
         ctx->path_stroke.x = x;
         ctx->path_stroke.y = y;
     } else if (ctx->path_stroke.state == GLC_STROKE_FIRST) {
commit c6b4cb056462f75ecfeee4f6568b243a3bcccef7
Author: Christophe Fergeau <cfergeau at gmail.com>
Date:   Tue Mar 22 16:16:05 2011 +0100

    opengl: fix compilation
    
    When OpenGL is enabled, build fails in DisplayChannel::create_surface
    because Canvas *canvas is declared twice. Remove the first
    declaration to fix compilation.

diff --git a/client/display_channel.cpp b/client/display_channel.cpp
index 3d2d8e8..3e43aae 100644
--- a/client/display_channel.cpp
+++ b/client/display_channel.cpp
@@ -1439,9 +1439,6 @@ void DisplayChannel::create_primary_surface(int width, int height, uint32_t form
 
 void DisplayChannel::create_surface(int surface_id, int width, int height, uint32_t format)
 {
-#ifdef USE_OGL
-    Canvas *canvas;
-#endif
     AutoRef<CreateSurfaceEvent> event(new CreateSurfaceEvent(*this, surface_id, width, height,
                                                              format));
     get_client().push_event(*event);
commit f2bb4cfe621eb53b424555651b3850c882659389
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Dec 11 15:55:19 2010 +0200

    python_modules/codegen.py: fix indent error in an unused function

diff --git a/python_modules/codegen.py b/python_modules/codegen.py
index 03c67e6..75033dc 100644
--- a/python_modules/codegen.py
+++ b/python_modules/codegen.py
@@ -11,7 +11,7 @@ def camel_to_underscores(s, upper = False):
             res = res + c.upper()
         else:
             res = res + c.lower()
-        return res
+    return res
 
 def underscores_to_camel(s):
     res = ""
commit f42e261aa689af04b2af10a493b03242ff9cc873
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
    
    Conflicts:
    
    	server/reds.c
    	server/reds.h

diff --git a/server/reds.c b/server/reds.c
index 1cc2e15..3488342 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"
@@ -52,7 +57,6 @@
 #include <spice/stats.h>
 #include "stat.h"
 #include "ring.h"
-#include "config.h"
 #include "demarshallers.h"
 #include "marshaller.h"
 #include "generated_marshallers.h"
@@ -91,6 +95,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;
@@ -1892,15 +1900,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);
 }
 
@@ -2638,6 +2651,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;
@@ -2690,16 +2801,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);
     }
@@ -2751,6 +3383,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 {
@@ -3877,6 +4514,17 @@ 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
+
     inputs_init();
 
 #ifdef USE_SMARTCARD
@@ -3969,6 +4617,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,
@@ -4259,12 +4930,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)
@@ -4295,6 +4984,20 @@ void reds_stream_free(RedsStream *s)
 
     reds_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 3b2795d..61ad691 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -18,14 +18,49 @@
 #ifndef _H_REDS
 #define _H_REDS
 
+#include "mem.h"
+
 #include <stdint.h>
 #include <openssl/ssl.h>
 #include <sys/uio.h>
 
+#if HAVE_SASL
+#include <sasl/sasl.h>
+#endif
+
 #define __visible__ __attribute__ ((visibility ("default")))
 
 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;
@@ -35,6 +70,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 fd281b7..d22425b 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 6101cb805ac1fc524f74a311e6cafafc0abc1982
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 999adfe..1cc2e15 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -319,6 +319,7 @@ typedef struct RedLinkInfo {
     SpiceLinkMess *link_mess;
     int mess_pos;
     TicketInfo tiTicketing;
+    SpiceLinkAuthMechanism auth_mechanism;
 } RedLinkInfo;
 
 typedef struct VDIPortBuf VDIPortBuf;
@@ -1881,6 +1882,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);
@@ -1914,6 +1937,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);
@@ -2655,6 +2680,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);
@@ -2669,6 +2719,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 ||
@@ -2678,6 +2730,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);
@@ -2695,10 +2750,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 bb6747b3d5ca52810eb0c9e12286262491e34559
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 9305198..999adfe 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1881,6 +1881,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 4cd2833..3b2795d 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -80,6 +80,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 159fee00c2a56426181f266570b7212744ba5e9e
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 4f87206..9305198 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1864,9 +1864,9 @@ static void reds_main_event(int fd, int event, void *data)
     }
 }
 
-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) {
@@ -1885,10 +1885,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);
@@ -1897,14 +1898,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())) {
@@ -1925,13 +1926,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 8186db28c2f56037eb4f688a7d73fcb89c13e7f1
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 95116ad..4f87206 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2543,6 +2543,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;
@@ -2573,11 +2582,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)
@@ -2646,8 +2652,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;
@@ -2821,6 +2827,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;
@@ -2916,7 +2923,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));
     }
 
@@ -2942,7 +2949,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 b1df04b9c5ef6def78203ac486217cfd9efea5cf
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
    
    Conflicts:
    
    	configure.ac

diff --git a/configure.ac b/configure.ac
index b4aa4a8..8f3831d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -299,6 +299,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
 
@@ -460,5 +511,7 @@ echo "
 
         Smartcard:                ${have_smartcard}
 
+        SASL support:             ${enable_sasl}
+
         Now type 'make' to build $PACKAGE
 "
diff --git a/server/Makefile.am b/server/Makefile.am
index 8e6e007..bd54aa2 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			\
@@ -68,6 +69,7 @@ libspice_server_la_LIBADD =			\
 	$(JPEG_LIBS)				\
 	$(PIXMAN_LIBS)				\
 	$(SSL_LIBS)				\
+	$(SASL_LIBS)				\
 	$(CELT051_LIBS)				\
 	$(SLIRP_LIBS)				\
 	$(LIBRT)				\
commit 6a0ea6711300b4dac003c897df2431f8e82ae7ca
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 a3732afda3a1d44c836c4755a332ce24215efcf0
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 d3415e3..95116ad 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -434,30 +434,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) {
@@ -2882,7 +2858,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) {
@@ -4207,7 +4183,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 26ded5e3950b2c9c552a3fc89647203e63b02411
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/red_channel.c b/server/red_channel.c
index 60eb443..da0fb9f 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -34,15 +34,15 @@ static void red_channel_pipe_clear(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;
@@ -66,14 +66,14 @@ static int red_peer_receive(RedsStream *peer, uint8_t *buf, uint32_t size)
     return pos - buf;
 }
 
-static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
+static void red_peer_handle_incoming(RedsStream *stream, IncomingHandler *handler)
 {
     int bytes_read;
 
     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) {
@@ -97,7 +97,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) {
@@ -139,7 +139,7 @@ static struct iovec *__iovec_skip(struct iovec vec[], int skip, int *vec_size)
     return now;
 }
 
-static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
+static void red_peer_handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
 {
     ssize_t n;
 
@@ -153,7 +153,7 @@ static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
     }
 
     for (;;) {
-        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:
@@ -215,7 +215,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);
 }
@@ -232,12 +232,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,
@@ -260,7 +260,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
     channel->send_item = send_item;
     channel->release_item = release_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)
@@ -289,7 +289,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);
 
@@ -297,7 +297,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
 
 error:
     free(channel);
-    reds_stream_free(peer);
+    reds_stream_free(stream);
 
     return NULL;
 }
@@ -308,19 +308,19 @@ void red_channel_destroy(RedChannel *channel)
         return;
     }
     red_channel_pipe_clear(channel);
-    reds_stream_free(channel->peer);
+    reds_stream_free(channel->stream);
     free(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;
     }
 }
 
@@ -358,7 +358,7 @@ static void red_channel_event(int fd, int event, void *data)
     RedChannel *channel = (RedChannel *)data;
 
     if (event & SPICE_WATCH_EVENT_READ) {
-        red_peer_handle_incoming(channel->peer, &channel->incoming);
+        red_peer_handle_incoming(channel->stream, &channel->incoming);
     }
     if (event & SPICE_WATCH_EVENT_WRITE) {
         red_channel_push(channel);
@@ -411,7 +411,7 @@ static inline void red_channel_fill_iovec(RedChannel *channel, struct iovec *vec
 
 static 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)
diff --git a/server/red_channel.h b/server/red_channel.h
index dfbc60f..1f131ee 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -100,7 +100,7 @@ typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
                                                PipeItem *item, int item_pushed);
 
 struct RedChannel {
-    RedsStream *peer;
+    RedsStream *stream;
     SpiceCoreInterface *core;
     int migrate;
     int handle_acks;
@@ -141,7 +141,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,
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 267de4a..4793f62 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));
     }
@@ -3420,7 +3420,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
     }
 }
 
-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)
 {
@@ -3431,7 +3431,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 a1c18b6..52070ee 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -356,7 +356,7 @@ struct RedChannel {
     uint32_t id;
     spice_parse_channel_func_t parser;
     struct RedWorker *worker;
-    RedsStream *peer;
+    RedsStream *stream;
     int migrate;
 
     Ring pipe;
@@ -7330,8 +7330,8 @@ static void red_send_data(RedChannel *channel, void *item)
         }
         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:
@@ -8506,15 +8506,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);
@@ -8525,7 +8525,7 @@ static void red_disconnect_display(RedChannel *channel)
 {
     DisplayChannel *display_channel;
 
-    if (!channel || !channel->peer) {
+    if (!channel || !channel->stream) {
         return;
     }
 
@@ -8857,7 +8857,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->base.peer) {
+        if (!display_channel->base.stream) {
             break;
         }
         if (display_channel->pixmap_cache && display_channel->glz_dict) {
@@ -9239,8 +9239,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);
@@ -9307,7 +9307,7 @@ static void red_receive(RedChannel *channel)
 }
 
 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,
                                  disconnect_channel_proc disconnect,
                                  hold_item_proc hold_item,
@@ -9319,18 +9319,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));
     }
 
@@ -9344,7 +9344,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_message = handle_message;
-    channel->peer = peer;
+    channel->stream = stream;
     channel->worker = worker;
     channel->messages_window = ~0;  // blocks send message (maybe use send_data.blocked +
                                     // block flags)
@@ -9359,7 +9359,7 @@ static RedChannel *__new_channel(RedWorker *worker, int size, uint32_t channel_i
 
     event.events = EPOLLIN | EPOLLOUT | EPOLLET;
     event.data.ptr = channel;
-    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;
     }
@@ -9371,7 +9371,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;
 }
@@ -9433,7 +9433,7 @@ static void display_channel_release_item(RedChannel *channel, void *item)
     }
 }
 
-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;
@@ -9441,7 +9441,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_item,
@@ -9513,7 +9513,7 @@ static void handle_new_display_channel(RedWorker *worker, RedsStream *peer, int
 
 static void red_disconnect_cursor(RedChannel *channel)
 {
-    if (!channel || !channel->peer) {
+    if (!channel || !channel->stream) {
         return;
     }
 
@@ -9556,14 +9556,14 @@ static void cursor_channel_release_item(RedChannel *channel, void *item)
     red_release_cursor(channel->worker, item);
 }
 
-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_item,
@@ -9992,13 +9992,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:
@@ -10040,13 +10040,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 bdf5d85..d3415e3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -209,7 +209,7 @@ typedef struct VDIPortState {
 
 typedef struct InputsState {
     Channel *channel;
-    RedsStream *peer;
+    RedsStream *stream;
     IncomingHandler in_handler;
     OutgoingHandler out_handler;
     VDAgentMouseState mouse_state;
@@ -255,7 +255,7 @@ typedef struct RedsState {
     int secure_listen_socket;
     SpiceWatch *listen_watch;
     SpiceWatch *secure_listen_watch;
-    RedsStream *peer;
+    RedsStream *stream;
     int disconnecting;
     uint32_t link_id;
     uint64_t serial; //migrate me
@@ -304,7 +304,7 @@ static uint64_t latency = 0;
 static RedsState *reds = NULL;
 
 typedef struct AsyncRead {
-    RedsStream *peer;
+    RedsStream *stream;
     void *opaque;
     uint8_t *now;
     uint8_t *end;
@@ -313,7 +313,7 @@ typedef struct AsyncRead {
 } AsyncRead;
 
 typedef struct RedLinkInfo {
-    RedsStream *peer;
+    RedsStream *stream;
     AsyncRead asyc_read;
     SpiceLinkHeader link_header;
     SpiceLinkMess *link_mess;
@@ -384,11 +384,11 @@ static ChannelSecurityOptions *find_channel_security(int id)
     return now;
 }
 
-static void reds_channel_event(RedsStream *peer, int event)
+static void reds_channel_event(RedsStream *stream, int event)
 {
     if (core->base.minor_version < 3 || core->channel_event == NULL)
         return;
-    core->channel_event(event, &peer->info);
+    core->channel_event(event, &stream->info);
 }
 
 static ssize_t stream_write_cb(RedsStream *s, const void *buf, size_t size)
@@ -468,8 +468,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;
@@ -714,7 +714,7 @@ static void reds_reset_outgoing()
 
 static void reds_disconnect()
 {
-    if (!reds->peer || reds->disconnecting) {
+    if (!reds->stream || reds->disconnecting) {
         return;
     }
 
@@ -739,8 +739,8 @@ static void reds_disconnect()
     }
 
     reds_shatdown_channels();
-    reds_stream_free(reds->peer);
-    reds->peer = NULL;
+    reds_stream_free(reds->stream);
+    reds->stream = NULL;
     reds->in_handler.shut = TRUE;
     reds->link_id = 0;
     reds->serial = 0;
@@ -758,14 +758,14 @@ static void reds_disconnect()
 
 static void reds_mig_disconnect()
 {
-    if (reds->peer) {
+    if (reds->stream) {
         reds_disconnect();
     } else {
         reds_mig_cleanup();
     }
 }
 
-static int handle_incoming(RedsStream *peer, IncomingHandler *handler)
+static int handle_incoming(RedsStream *stream, IncomingHandler *handler)
 {
     for (;;) {
         uint8_t *buf = handler->buf;
@@ -773,7 +773,7 @@ static int handle_incoming(RedsStream *peer, IncomingHandler *handler)
         uint8_t *end = buf + pos;
         SpiceDataHeader *header;
         int n;
-        n = reds_stream_read(peer, buf + pos, RECIVE_BUF_SIZE - pos);
+        n = reds_stream_read(stream, buf + pos, RECIVE_BUF_SIZE - pos);
         if (n <= 0) {
             if (n == 0) {
                 return -1;
@@ -818,7 +818,7 @@ static int handle_incoming(RedsStream *peer, IncomingHandler *handler)
     }
 }
 
-static int handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
+static int handle_outgoing(RedsStream *stream, OutgoingHandler *handler)
 {
     if (!handler->length) {
         return 0;
@@ -827,8 +827,7 @@ static int handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
     while (handler->length) {
         int n;
 
-        n = reds_stream_write(peer, handler->now, handler->length);
-
+        n = reds_stream_write(stream, handler->now, handler->length);
         if (n <= 0) {
             if (n == 0) {
                 return -1;
@@ -858,7 +857,7 @@ static int handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
 #define OUTGOING_FAILED -1
 #define OUTGOING_BLOCKED 1
 
-static int outgoing_write(RedsStream *peer, OutgoingHandler *handler, void *in_data,
+static int outgoing_write(RedsStream *stream, OutgoingHandler *handler, void *in_data,
                           int length)
 {
     uint8_t *data = in_data;
@@ -868,7 +867,7 @@ static int outgoing_write(RedsStream *peer, OutgoingHandler *handler, void *in_d
     }
 
     while (length) {
-        int n = reds_stream_write(peer, data, length);
+        int n = reds_stream_write(stream, data, length);
         if (n < 0) {
             switch (errno) {
             case EAGAIN:
@@ -952,7 +951,7 @@ static int send_ping(int size)
     RedsOutItem *item;
     SpiceMsgPing ping;
 
-    if (!reds->peer) {
+    if (!reds->stream) {
         return FALSE;
     }
     item = new_out_item(SPICE_MSG_PING);
@@ -976,8 +975,8 @@ static int send_ping(int size)
 
 static void do_ping_client(const char *opt, int has_interval, int interval)
 {
-    if (!reds->peer) {
-        red_printf("not connected to peer");
+    if (!reds->stream) {
+        red_printf("not connected to stream");
         return;
     }
 
@@ -997,8 +996,8 @@ static void do_ping_client(const char *opt, int has_interval, int interval)
 
 static void ping_timer_cb()
 {
-    if (!reds->peer) {
-        red_printf("not connected to peer, ping off");
+    if (!reds->stream) {
+        red_printf("not connected to stream, ping off");
         core->timer_cancel(reds->ping_timer);
         return;
     }
@@ -1013,7 +1012,7 @@ static void reds_send_mouse_mode()
     SpiceMsgMainMouseMode mouse_mode;
     RedsOutItem *item;
 
-    if (!reds->peer) {
+    if (!reds->stream) {
         return;
     }
 
@@ -1089,7 +1088,7 @@ static void reds_agent_remove()
     reds->agent_state.connected = 0;
     vdagent = NULL;
     reds_update_mouse_mode();
-    if (!reds->peer || !sin) {
+    if (!reds->stream || !sin) {
         return;
     }
     sif = SPICE_CONTAINEROF(sin->base.sif, SpiceCharDeviceInterface, base);
@@ -1108,7 +1107,7 @@ static void reds_send_tokens()
     SpiceMsgMainAgentTokens tokens;
     RedsOutItem *item;
 
-    if (!reds->peer) {
+    if (!reds->stream) {
         return;
     }
 
@@ -1665,7 +1664,7 @@ static void reds_main_handle_message(void *opaque, size_t size, uint32_t type, v
     switch (type) {
     case SPICE_MSGC_MAIN_AGENT_START:
         red_printf("agent start");
-        if (!reds->peer || !vdagent) {
+        if (!reds->stream || !vdagent) {
             return;
         }
         reds->agent_state.write_filter.discard_all = FALSE;
@@ -1819,10 +1818,10 @@ static int reds_send_data()
 
     ASSERT(outgoing->vec_size);
     for (;;) {
-        if ((n = reds_stream_writev(reds->peer, outgoing->vec, outgoing->vec_size)) == -1) {
+        if ((n = reds_stream_writev(reds->stream, outgoing->vec, outgoing->vec_size)) == -1) {
             switch (errno) {
             case EAGAIN:
-                core->watch_update_mask(reds->peer->watch,
+                core->watch_update_mask(reds->stream->watch,
                                         SPICE_WATCH_EVENT_READ | SPICE_WATCH_EVENT_WRITE);
                 return FALSE;
             case EINTR:
@@ -1854,7 +1853,7 @@ static void reds_push()
     RedsOutItem *item;
 
     for (;;) {
-        if (!reds->peer || outgoing->item || !(ring_item = ring_get_tail(&outgoing->pipe))) {
+        if (!reds->stream || outgoing->item || !(ring_item = ring_get_tail(&outgoing->pipe))) {
             return;
         }
         ring_remove(ring_item);
@@ -1873,7 +1872,7 @@ static void reds_push()
 static void reds_main_event(int fd, int event, void *data)
 {
     if (event & SPICE_WATCH_EVENT_READ) {
-        if (handle_incoming(reds->peer, &reds->in_handler)) {
+        if (handle_incoming(reds->stream, &reds->in_handler)) {
             reds_disconnect();
         }
     }
@@ -1881,19 +1880,19 @@ static void reds_main_event(int fd, int event, void *data)
         RedsOutgoingData *outgoing = &reds->outgoing;
         if (reds_send_data()) {
             reds_push();
-            if (!outgoing->item && reds->peer) {
-                core->watch_update_mask(reds->peer->watch,
+            if (!outgoing->item && reds->stream) {
+                core->watch_update_mask(reds->stream->watch,
                                         SPICE_WATCH_EVENT_READ);
             }
         }
     }
 }
 
-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;
@@ -1950,12 +1949,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;
@@ -1972,8 +1971,8 @@ 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,
-                                                                         sizeof(reply));
+    return sync_write(link->stream, &header, sizeof(header)) && sync_write(link->stream, &reply,
+                                                                           sizeof(reply));
 }
 
 static void reds_show_new_channel(RedLinkInfo *link, int connection_id)
@@ -1981,25 +1980,25 @@ 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_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));
 }
 
 static void reds_start_net_test()
 {
-    if (!reds->peer || reds->net_test_id) {
+    if (!reds->stream || reds->net_test_id) {
         return;
     }
 
@@ -2038,12 +2037,12 @@ static void reds_handle_main_link(RedLinkInfo *link)
     reds->mig_inprogress = FALSE;
     reds->mig_wait_connect = FALSE;
     reds->mig_wait_disconnect = FALSE;
-    reds->peer = link->peer;
+    reds->stream = link->stream;
     reds->in_handler.shut = FALSE;
 
     reds_show_new_channel(link, connection_id);
-    reds_stream_remove_watch(link->peer);
-    link->peer = NULL;
+    reds_stream_remove_watch(link->stream);
+    link->stream = NULL;
     link->link_mess = NULL;
     reds_link_free(link);
     if (vdagent) {
@@ -2056,7 +2055,7 @@ static void reds_handle_main_link(RedLinkInfo *link)
         }
         reds->agent_state.plug_generation++;
     }
-    reds->peer->watch = core->watch_add(reds->peer->socket,
+    reds->stream->watch = core->watch_add(reds->stream->socket,
                                         SPICE_WATCH_EVENT_READ,
                                         reds_main_event, NULL);
 
@@ -2152,7 +2151,7 @@ static int marshaller_outgoing_write(SpiceMarshaller *m,
 
     data = spice_marshaller_linearize(m, 0, &len, &free_data);
 
-    if (outgoing_write(state->peer, &state->out_handler, data, len) != OUTGOING_OK) {
+    if (outgoing_write(state->stream, &state->out_handler, data, len) != OUTGOING_OK) {
         return FALSE;
     }
 
@@ -2345,18 +2344,18 @@ static void inputs_event(int fd, int event, void *data)
     InputsState *inputs_state = data;
 
     if (event & SPICE_WATCH_EVENT_READ) {
-        if (handle_incoming(inputs_state->peer, &inputs_state->in_handler)) {
+        if (handle_incoming(inputs_state->stream, &inputs_state->in_handler)) {
             inputs_relase_keys();
             if (inputs_state->channel) {
                 inputs_state->channel->data = NULL;
                 reds->inputs_state = NULL;
             }
-            reds_stream_free(inputs_state->peer);
+            reds_stream_free(inputs_state->stream);
             free(inputs_state);
         }
     }
     if (event & SPICE_WATCH_EVENT_WRITE) {
-        if (handle_outgoing(inputs_state->peer, &inputs_state->out_handler)) {
+        if (handle_outgoing(inputs_state->stream, &inputs_state->out_handler)) {
             reds_disconnect();
         }
     }
@@ -2368,7 +2367,7 @@ static void inputs_shutdown(Channel *channel)
     InputsState *state = (InputsState *)channel->data;
     if (state) {
         state->in_handler.shut = TRUE;
-        shutdown(state->peer->socket, SHUT_RDWR);
+        shutdown(state->stream->socket, SHUT_RDWR);
         channel->data = NULL;
         state->channel = NULL;
         reds->inputs_state = NULL;
@@ -2402,7 +2401,7 @@ static void inputs_select(void *opaque, int select)
     if (select) {
         eventmask |= SPICE_WATCH_EVENT_WRITE;
     }
-    core->watch_update_mask(inputs_state->peer->watch, eventmask);
+    core->watch_update_mask(inputs_state->stream->watch, eventmask);
 }
 
 static void inputs_may_write(void *opaque)
@@ -2410,7 +2409,7 @@ static void inputs_may_write(void *opaque)
     red_printf("");
 }
 
-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)
 {
@@ -2424,16 +2423,16 @@ static void inputs_link(Channel *channel, RedsStream *peer, int migration,
     inputs_state = spice_new0(InputsState, 1);
 
     delay_val = 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 ((flags = fcntl(peer->socket, F_GETFL)) == -1 ||
-                                            fcntl(peer->socket, F_SETFL, flags | O_ASYNC) == -1) {
+    if ((flags = fcntl(stream->socket, F_GETFL)) == -1 ||
+                                            fcntl(stream->socket, F_SETFL, flags | O_ASYNC) == -1) {
         red_printf("fcntl failed, %s", strerror(errno));
     }
 
-    inputs_state->peer = peer;
+    inputs_state->stream = stream;
     inputs_state->channel = channel;
     inputs_state->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_INPUTS, NULL);
     inputs_state->in_handler.opaque = inputs_state;
@@ -2445,7 +2444,7 @@ static void inputs_link(Channel *channel, RedsStream *peer, int migration,
     inputs_state->pending_mouse_event = FALSE;
     channel->data = inputs_state;
     reds->inputs_state = inputs_state;
-    peer->watch = core->watch_add(peer->socket, SPICE_WATCH_EVENT_READ,
+    stream->watch = core->watch_add(stream->socket, SPICE_WATCH_EVENT_READ,
                                   inputs_event, inputs_state);
 
     SpiceMarshaller *m;
@@ -2470,7 +2469,7 @@ static void reds_send_keyboard_modifiers(uint8_t modifiers)
     if (!channel || !(state = (InputsState *)channel->data)) {
         return;
     }
-    ASSERT(state->peer);
+    ASSERT(state->stream);
 
     m = marshaller_new_for_outgoing(state, SPICE_MSG_INPUTS_KEY_MODIFIERS);
 
@@ -2516,7 +2515,7 @@ static void inputs_init()
 static void reds_handle_other_links(RedLinkInfo *link)
 {
     Channel *channel;
-    RedsStream *peer;
+    RedsStream *stream;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
 
@@ -2537,7 +2536,7 @@ 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) {
         RedsOutItem *item;
         SpiceMsgNotify notify;
         char *mess = "keyboard channel is insecure";
@@ -2556,13 +2555,13 @@ static void reds_handle_other_links(RedLinkInfo *link)
 
         reds_push_pipe_item(item);
     }
-    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);
@@ -2607,10 +2606,10 @@ 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)
@@ -2621,15 +2620,15 @@ 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,
-                                                           SPICE_WATCH_EVENT_READ,
-                                                           async_read_handler, obj);
+                    if (!obj->stream->watch) {
+                        obj->stream->watch = core->watch_add(obj->stream->socket,
+                                                             SPICE_WATCH_EVENT_READ,
+                                                             async_read_handler, obj);
                     }
                     return;
                 case EINTR:
@@ -2659,8 +2658,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)
@@ -2679,7 +2678,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 {
@@ -2758,7 +2757,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;
@@ -2771,28 +2770,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;
@@ -2817,16 +2816,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_channel_event(stream, SPICE_CHANNEL_EVENT_CONNECTED);
 
     openssl_init(link);
 
@@ -2841,15 +2840,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;
 }
@@ -2867,47 +2866,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);
 }
@@ -3150,8 +3149,8 @@ static void reds_init_ssl()
 
 static void reds_exit()
 {
-    if (reds->peer) {
-        close(reds->peer->socket);
+    if (reds->stream) {
+        close(reds->stream->socket);
     }
 #ifdef RED_STATISTICS
     shm_unlink(reds->stat_shm_name);
@@ -3194,7 +3193,7 @@ enum {
 
 static inline void on_activating_ticketing()
 {
-    if (!ticketing_enabled && reds->peer) {
+    if (!ticketing_enabled && reds->stream) {
         red_printf("disconnecting");
         reds_disconnect();
     }
@@ -3297,8 +3296,8 @@ static void reds_mig_started(void)
         core->watch_update_mask(reds->secure_listen_watch, 0);
     }
 
-    if (reds->peer == NULL) {
-        red_printf("not connected to peer");
+    if (reds->stream == NULL) {
+        red_printf("not connected to stream");
         goto error;
     }
 
@@ -3329,8 +3328,8 @@ static void reds_mig_finished(int completed)
         core->watch_update_mask(reds->secure_listen_watch, SPICE_WATCH_EVENT_READ);
     }
 
-    if (reds->peer == NULL) {
-        red_printf("no peer connected");
+    if (reds->stream == NULL) {
+        red_printf("no stream connected");
         return;
     }
     reds->mig_inprogress = TRUE;
@@ -3420,7 +3419,7 @@ void reds_enable_mm_timer()
     RedsOutItem *item;
 
     core->timer_start(reds->mm_timer, MM_TIMER_GRANULARITY_MS);
-    if (!reds->peer) {
+    if (!reds->stream) {
         return;
     }
 
@@ -3448,7 +3447,7 @@ static void attach_to_red_agent(SpiceCharDeviceInstance *sin)
 
     vdagent = sin;
     reds_update_mouse_mode();
-    if (!reds->peer) {
+    if (!reds->stream) {
         return;
     }
     sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
@@ -3756,7 +3755,7 @@ static int do_spice_init(SpiceCoreInterface *core_interface)
     core = core_interface;
     reds->listen_socket = -1;
     reds->secure_listen_socket = -1;
-    reds->peer = NULL;
+    reds->stream = NULL;
     reds->in_handler.parser = spice_get_client_channel_parser(SPICE_CHANNEL_MAIN, NULL);
     reds->in_handler.handle_message = reds_main_handle_message;
     ring_init(&reds->outgoing.pipe);
@@ -3915,7 +3914,7 @@ __visible__ int spice_server_set_ticket(SpiceServer *s,
 {
     ASSERT(reds == s);
 
-    if (reds->peer) {
+    if (reds->stream) {
         if (fail_if_connected) {
             return -1;
         }
@@ -4053,10 +4052,10 @@ __visible__ int spice_server_set_channel_security(SpiceServer *s, const char *ch
 __visible__ int spice_server_get_sock_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
 {
     ASSERT(reds == s);
-    if (!reds->peer) {
+    if (!reds->stream) {
         return -1;
     }
-    if (getsockname(reds->peer->socket, sa, salen) < 0) {
+    if (getsockname(reds->stream->socket, sa, salen) < 0) {
         return -1;
     }
     return 0;
@@ -4065,10 +4064,10 @@ __visible__ int spice_server_get_sock_info(SpiceServer *s, struct sockaddr *sa,
 __visible__ int spice_server_get_peer_info(SpiceServer *s, struct sockaddr *sa, socklen_t *salen)
 {
     ASSERT(reds == s);
-    if (!reds->peer) {
+    if (!reds->stream) {
         return -1;
     }
-    if (getpeername(reds->peer->socket, sa, salen) < 0) {
+    if (getpeername(reds->stream->socket, sa, salen) < 0) {
         return -1;
     }
     return 0;
@@ -4171,7 +4170,7 @@ __visible__ int spice_server_migrate_client_state(SpiceServer *s)
 {
     ASSERT(reds == s);
 
-    if (!reds->peer) {
+    if (!reds->stream) {
         return SPICE_MIGRATE_CLIENT_NONE;
     } else if (reds->mig_wait_connect) {
         return SPICE_MIGRATE_CLIENT_WAITING;
diff --git a/server/smartcard.c b/server/smartcard.c
index ba28336..852110b 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -465,7 +465,7 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
     return TRUE;
 }
 
-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)
@@ -475,7 +475,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 5f27f8f522121556c515e4c37227f3853c3c7472
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 beda0e3..bdf5d85 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2847,7 +2847,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;
@@ -2882,7 +2881,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 8913e83..4cd2833 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -27,8 +27,6 @@
 typedef struct RedsStream RedsStream;
 
 struct RedsStream {
-    void *ctx;
-
     int socket;
     SpiceWatch *watch;
 
commit 36ab16d6c512f4cca8426fe788f333e05911d18b
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 f064054..60eb443 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -42,7 +42,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;
             }
@@ -140,7 +141,8 @@ static struct iovec *__iovec_skip(struct iovec vec[], int skip, int *vec_size)
 
 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);
@@ -149,8 +151,10 @@ static void red_peer_handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
         }
         handler->prepare(handler->opaque, handler->vec, &handler->vec_size);
     }
+
     for (;;) {
-        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 84697b3..a1c18b6 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -7316,9 +7316,9 @@ static void inline channel_release_res(RedChannel *channel)
 static void red_send_data(RedChannel *channel, void *item)
 {
     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;
@@ -7331,7 +7331,8 @@ static void red_send_data(RedChannel *channel, void *item)
         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;
@@ -9239,7 +9240,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 19da2ae..beda0e3 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -391,73 +391,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 {
@@ -786,7 +773,7 @@ static int handle_incoming(RedsStream *peer, IncomingHandler *handler)
         uint8_t *end = buf + pos;
         SpiceDataHeader *header;
         int n;
-        n = peer->cb_read(peer->ctx, buf + pos, RECIVE_BUF_SIZE - pos);
+        n = reds_stream_read(peer, buf + pos, RECIVE_BUF_SIZE - pos);
         if (n <= 0) {
             if (n == 0) {
                 return -1;
@@ -840,7 +827,8 @@ static int handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
     while (handler->length) {
         int n;
 
-        n = peer->cb_write(peer->ctx, handler->now, handler->length);
+        n = reds_stream_write(peer, handler->now, handler->length);
+
         if (n <= 0) {
             if (n == 0) {
                 return -1;
@@ -880,7 +868,7 @@ static int outgoing_write(RedsStream *peer, OutgoingHandler *handler, void *in_d
     }
 
     while (length) {
-        int n = peer->cb_write(peer->ctx, data, length);
+        int n = reds_stream_write(peer, data, length);
         if (n < 0) {
             switch (errno) {
             case EAGAIN:
@@ -1831,7 +1819,7 @@ static int reds_send_data()
 
     ASSERT(outgoing->vec_size);
     for (;;) {
-        if ((n = reds->peer->cb_writev(reds->peer->ctx, outgoing->vec, outgoing->vec_size)) == -1) {
+        if ((n = reds_stream_writev(reds->peer, outgoing->vec, outgoing->vec_size)) == -1) {
             switch (errno) {
             case EAGAIN:
                 core->watch_update_mask(reds->peer->watch,
@@ -1905,7 +1893,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;
@@ -2633,7 +2621,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:
@@ -2859,9 +2848,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;
 }
@@ -2894,9 +2883,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 2a9a0de..8913e83 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -39,11 +39,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 584cc5a3d139de92d1a22fb80703a33106967297
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 acbce57..19da2ae 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -413,14 +413,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;
@@ -479,15 +471,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) {
@@ -2879,7 +2862,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;
 }
@@ -2915,7 +2897,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 3ed097c..2a9a0de 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -43,7 +43,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 a5946a54dd54b4a3a72c9683f43b710f3f0b3f11
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 a7620f7..f064054 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -304,8 +304,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);
     free(channel);
 }
 
diff --git a/server/reds.c b/server/reds.c
index 991660e..acbce57 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -515,28 +515,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);
-}
-
 static struct iovec *reds_iovec_skip(struct iovec vec[], int skip, int *vec_size)
 {
     struct iovec *now = vec;
@@ -791,8 +769,7 @@ static void reds_disconnect()
     }
 
     reds_shatdown_channels();
-    reds_stream_remove_watch(reds->peer);
-    reds->peer->cb_free(reds->peer);
+    reds_stream_free(reds->peer);
     reds->peer = NULL;
     reds->in_handler.shut = TRUE;
     reds->link_id = 0;
@@ -2078,7 +2055,7 @@ static void reds_handle_main_link(RedLinkInfo *link)
     } else {
         if (link->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);
@@ -2094,7 +2071,10 @@ static void reds_handle_main_link(RedLinkInfo *link)
     reds->in_handler.shut = FALSE;
 
     reds_show_new_channel(link, connection_id);
-    __reds_release_link(link);
+    reds_stream_remove_watch(link->peer);
+    link->peer = NULL;
+    link->link_mess = NULL;
+    reds_link_free(link);
     if (vdagent) {
         SpiceCharDeviceInterface *sif;
         sif = SPICE_CONTAINEROF(vdagent->base.sif, SpiceCharDeviceInterface, base);
@@ -2396,12 +2376,11 @@ static void inputs_event(int fd, int event, void *data)
     if (event & SPICE_WATCH_EVENT_READ) {
         if (handle_incoming(inputs_state->peer, &inputs_state->in_handler)) {
             inputs_relase_keys();
-            reds_stream_remove_watch(inputs_state->peer);
             if (inputs_state->channel) {
                 inputs_state->channel->data = NULL;
                 reds->inputs_state = NULL;
             }
-            inputs_state->peer->cb_free(inputs_state->peer);
+            reds_stream_free(inputs_state->peer);
             free(inputs_state);
         }
     }
@@ -2574,14 +2553,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;
     }
 
@@ -2607,8 +2586,10 @@ static void reds_handle_other_links(RedLinkInfo *link)
         reds_push_pipe_item(item);
     }
     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,
@@ -2636,13 +2617,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;
         }
     }
@@ -2721,7 +2702,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;
     }
 
@@ -2733,12 +2714,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;
     }
 
@@ -2759,7 +2740,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)
@@ -2770,7 +2751,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;
     }
 
@@ -2780,7 +2761,7 @@ static void reds_handle_read_header_done(void *opaque)
         }
 
         red_printf("version mismatch");
-        reds_release_link(link);
+        reds_link_free(link);
         return;
     }
 
@@ -2789,7 +2770,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;
     }
 
@@ -2822,7 +2803,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 6d8cbc23491ae53933662b169138c048cc6d54a6
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 fa197f6..991660e 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -791,8 +791,7 @@ static void reds_disconnect()
     }
 
     reds_shatdown_channels();
-    core->watch_remove(reds->peer->watch);
-    reds->peer->watch = NULL;
+    reds_stream_remove_watch(reds->peer);
     reds->peer->cb_free(reds->peer);
     reds->peer = NULL;
     reds->in_handler.shut = TRUE;
@@ -2397,8 +2396,7 @@ static void inputs_event(int fd, int event, void *data)
     if (event & SPICE_WATCH_EVENT_READ) {
         if (handle_incoming(inputs_state->peer, &inputs_state->in_handler)) {
             inputs_relase_keys();
-            core->watch_remove(inputs_state->peer->watch);
-            inputs_state->peer->watch = NULL;
+            reds_stream_remove_watch(inputs_state->peer);
             if (inputs_state->channel) {
                 inputs_state->channel->data = NULL;
                 reds->inputs_state = NULL;
@@ -2660,8 +2658,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)
@@ -2835,8 +2832,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 eeb95c5b84e81a2ba6745fbeb1689d0ef5dc49d0
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 a3dbaa2..a7620f7 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -293,7 +293,7 @@ RedChannel *red_channel_create(int size, RedsStream *peer,
 
 error:
     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 467b4a8..84697b3 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -8512,9 +8512,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;
@@ -9371,7 +9369,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 63fd08f..fa197f6 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -479,7 +479,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);
@@ -488,6 +488,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);
@@ -4223,3 +4250,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 2c97729..3ed097c 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -24,7 +24,9 @@
 
 #define __visible__ __attribute__ ((visibility ("default")))
 
-typedef struct RedsStream {
+typedef struct RedsStream RedsStream;
+
+struct RedsStream {
     void *ctx;
 
     int socket;
@@ -42,7 +44,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;
@@ -81,6 +88,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 881971fbcab7c1eaf47a9edcf517aeaa09945dae
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/red_channel.c b/server/red_channel.c
index 81a9162..a3dbaa2 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -34,7 +34,7 @@ static void red_channel_pipe_clear(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) {
@@ -65,7 +65,7 @@ static int red_peer_receive(RedsStreamContext *peer, uint8_t *buf, uint32_t size
     return pos - buf;
 }
 
-static void red_peer_handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
+static void red_peer_handle_incoming(RedsStream *peer, IncomingHandler *handler)
 {
     int bytes_read;
 
@@ -138,7 +138,7 @@ static struct iovec *__iovec_skip(struct iovec vec[], int skip, int *vec_size)
     return now;
 }
 
-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) {
@@ -233,7 +233,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,
diff --git a/server/red_channel.h b/server/red_channel.h
index 509da77..dfbc60f 100644
--- a/server/red_channel.h
+++ b/server/red_channel.h
@@ -100,7 +100,7 @@ typedef void (*channel_release_pipe_item_proc)(RedChannel *channel,
                                                PipeItem *item, int item_pushed);
 
 struct RedChannel {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SpiceCoreInterface *core;
     int migrate;
     int handle_acks;
@@ -141,7 +141,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,
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 6092a76..267de4a 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);
@@ -3420,7 +3420,7 @@ static void on_new_tunnel_channel(TunnelChannel *channel)
     }
 }
 
-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 f163a71..467b4a8 100644
--- a/server/red_worker.c
+++ b/server/red_worker.c
@@ -356,7 +356,7 @@ struct RedChannel {
     uint32_t id;
     spice_parse_channel_func_t parser;
     struct RedWorker *worker;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     int migrate;
 
     Ring pipe;
@@ -9307,7 +9307,7 @@ static void red_receive(RedChannel *channel)
 }
 
 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,
                                  disconnect_channel_proc disconnect,
                                  hold_item_proc hold_item,
@@ -9433,7 +9433,7 @@ static void display_channel_release_item(RedChannel *channel, void *item)
     }
 }
 
-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;
@@ -9556,7 +9556,7 @@ static void cursor_channel_release_item(RedChannel *channel, void *item)
     red_release_cursor(channel->worker, item);
 }
 
-static void red_connect_cursor(RedWorker *worker, RedsStreamContext *peer, int migrate)
+static void red_connect_cursor(RedWorker *worker, RedsStream *peer, int migrate)
 {
     CursorChannel *channel;
 
@@ -9992,11 +9992,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;
@@ -10040,11 +10040,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 a92eb88..63fd08f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -209,7 +209,7 @@ typedef struct VDIPortState {
 
 typedef struct InputsState {
     Channel *channel;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     IncomingHandler in_handler;
     OutgoingHandler out_handler;
     VDAgentMouseState mouse_state;
@@ -255,7 +255,7 @@ typedef struct RedsState {
     int secure_listen_socket;
     SpiceWatch *listen_watch;
     SpiceWatch *secure_listen_watch;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     int disconnecting;
     uint32_t link_id;
     uint64_t serial; //migrate me
@@ -304,7 +304,7 @@ static uint64_t latency = 0;
 static RedsState *reds = NULL;
 
 typedef struct AsyncRead {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     void *opaque;
     uint8_t *now;
     uint8_t *end;
@@ -313,7 +313,7 @@ typedef struct AsyncRead {
 } AsyncRead;
 
 typedef struct RedLinkInfo {
-    RedsStreamContext *peer;
+    RedsStream *peer;
     AsyncRead asyc_read;
     SpiceLinkHeader link_header;
     SpiceLinkMess *link_mess;
@@ -384,7 +384,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;
@@ -413,7 +413,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);
@@ -479,7 +479,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);
@@ -505,7 +505,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);
 }
@@ -792,7 +792,7 @@ static void reds_mig_disconnect()
     }
 }
 
-static int handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
+static int handle_incoming(RedsStream *peer, IncomingHandler *handler)
 {
     for (;;) {
         uint8_t *buf = handler->buf;
@@ -845,7 +845,7 @@ static int handle_incoming(RedsStreamContext *peer, IncomingHandler *handler)
     }
 }
 
-static int handle_outgoing(RedsStreamContext *peer, OutgoingHandler *handler)
+static int handle_outgoing(RedsStream *peer, OutgoingHandler *handler)
 {
     if (!handler->length) {
         return 0;
@@ -884,7 +884,7 @@ static int handle_outgoing(RedsStreamContext *peer, OutgoingHandler *handler)
 #define OUTGOING_FAILED -1
 #define OUTGOING_BLOCKED 1
 
-static int outgoing_write(RedsStreamContext *peer, OutgoingHandler *handler, void *in_data,
+static int outgoing_write(RedsStream *peer, OutgoingHandler *handler, void *in_data,
                           int length)
 {
     uint8_t *data = in_data;
@@ -1915,7 +1915,7 @@ static void reds_main_event(int fd, int event, void *data)
     }
 }
 
-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) {
@@ -2435,7 +2435,7 @@ static void inputs_may_write(void *opaque)
     red_printf("");
 }
 
-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)
 {
@@ -2541,7 +2541,7 @@ static void inputs_init()
 static void reds_handle_other_links(RedLinkInfo *link)
 {
     Channel *channel;
-    RedsStreamContext *peer;
+    RedsStream *peer;
     SpiceLinkMess *link_mess;
     uint32_t *caps;
 
@@ -2816,7 +2816,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;
@@ -2841,7 +2841,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;
 
@@ -2865,7 +2865,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;
@@ -2875,7 +2875,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;
 }
@@ -2911,7 +2911,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 4b23d64..2c97729 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -24,7 +24,7 @@
 
 #define __visible__ __attribute__ ((visibility ("default")))
 
-typedef struct RedsStreamContext {
+typedef struct RedsStream {
     void *ctx;
 
     int socket;
@@ -41,8 +41,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;
@@ -52,7 +52,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 9d72a7e..ba28336 100644
--- a/server/smartcard.c
+++ b/server/smartcard.c
@@ -465,7 +465,7 @@ static int smartcard_channel_handle_message(RedChannel *channel, SpiceDataHeader
     return TRUE;
 }
 
-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 a1ef838d34944e335324feb2f4949c14be40d4e8
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 6c7df09..a92eb88 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2874,7 +2874,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;
 
@@ -2911,7 +2910,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 e95aea5..4b23d64 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -40,7 +40,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 e1cfe664c436096201b504af59e4c7e2e5299fc1
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 f3146d8..b4aa4a8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -420,6 +420,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 49cb5d9..8e6e007 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 =				\
commit 4bdacb2c14fbd0daa559d0ebdc766fcb121302f9
Author: Arnon Gilboa <agilboa at redhat.com>
Date:   Sun Feb 13 12:23:47 2011 +0200

    client/windows: use SPICE_PROTOCOL_DIR in project include dirs
    
    instead of ..\..\..\spice-protocol. Relative path to another git tree is a bit
    ugly, since it requires spice-protocol to be in a specific location.
    
    SPICE_PROTOCOL_DIR should also be used in windows qxl and vdagent instead of
    SPICE_COMMON_DIR, which is an old and confusing name, due to the common
    directory in spice git repo.

diff --git a/client/windows/redc.vcproj b/client/windows/redc.vcproj
index 0958004..a937001 100644
--- a/client/windows/redc.vcproj
+++ b/client/windows/redc.vcproj
@@ -49,7 +49,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories=".;..;..\..\common;&quot;..\..\..\spice-protocol&quot;;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
+				AdditionalIncludeDirectories=".;..;$(SPICE_PROTOCOL_DIR);..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SW_CANVAS_CACHE;RED_DEBUG;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;USE_GUI;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				MinimalRebuild="false"
 				BasicRuntimeChecks="3"
@@ -137,7 +137,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories=".;..;..\..\common;&quot;..\..\..\spice-protocol&quot;;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
+				AdditionalIncludeDirectories=".;..;$(SPICE_PROTOCOL_DIR);..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;SW_CANVAS_CACHE;RED_DEBUG;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;USE_GUI;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				MinimalRebuild="false"
 				BasicRuntimeChecks="3"
@@ -220,7 +220,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories=".;..;&quot;..\..\..\spice-protocol&quot;;..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
+				AdditionalIncludeDirectories=".;..;$(SPICE_PROTOCOL_DIR);..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
 				PreprocessorDefinitions="WIN32;_WINDOWS;SW_CANVAS_CACHE;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;USE_GUI;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
@@ -303,7 +303,7 @@
 			/>
 			<Tool
 				Name="VCCLCompilerTool"
-				AdditionalIncludeDirectories=".;..;&quot;..\..\..\spice-protocol&quot;;..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
+				AdditionalIncludeDirectories=".;..;$(SPICE_PROTOCOL_DIR);..\..\common;..\..\common\win;&quot;..\..\common\win\my_getopt-1.5&quot;;&quot;$(SPICE_LIBS)\include&quot;;&quot;$(SPICE_LIBS)\include\pixman-1&quot;;&quot;$(SPICE_LIBS)\include\CEGUI-0.6.2&quot;;&quot;$(SPICE_LIBS)\include\CxImage&quot;"
 				PreprocessorDefinitions="WIN32;_WINDOWS;SW_CANVAS_CACHE;SW_CANVAS_NO_CHUNKS;_WIN32_WINNT=0x0500;USE_GUI;USE_GLZ;PTW32_STATIC_LIB;CEGUI_STATIC"
 				RuntimeLibrary="0"
 				UsePrecompiledHeader="0"
commit fcd4a8e44631e80c85ab7baf70489c32f0b4f5d7
Author: Alon Levy <alevy at redhat.com>
Date:   Sat Jan 15 20:53:44 2011 +0200

    server/red_channel: fix segfault on red_channel_destroy if peer already removed

diff --git a/server/red_channel.c b/server/red_channel.c
index 3941338..81a9162 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -312,7 +312,7 @@ void red_channel_destroy(RedChannel *channel)
 void red_channel_shutdown(RedChannel *channel)
 {
     red_printf("");
-    if (!channel->peer->shutdown) {
+    if (channel->peer && !channel->peer->shutdown) {
         channel->core->watch_update_mask(channel->peer->watch,
                                          SPICE_WATCH_EVENT_READ);
         red_channel_pipe_clear(channel);
commit b6445d35f7cc15c512de969b9b932d27616ac08b
Author: Thomas Tyminski <thomast at cs.tu-berlin.de>
Date:   Wed Dec 22 14:08:09 2010 +0100

    Fixes compilation error of Spice Client (Linux/X11) with OpenGL enabled modified: client/x11/red_window.cpp

diff --git a/client/x11/red_window.cpp b/client/x11/red_window.cpp
index d7b19f9..d53a92f 100644
--- a/client/x11/red_window.cpp
+++ b/client/x11/red_window.cpp
@@ -2075,13 +2075,13 @@ bool RedWindow::get_mouse_anchor_point(SpicePoint& pt)
 #ifdef USE_OGL
 RedGlContext RedWindow::create_context_gl()
 {
-    RedGlContext *context = NULL;
     if (XPlatform::get_fbconfig()[_screen]) {
         XLockDisplay(x_display);
-        context = glXCreateContext(x_display, XPlatform::get_vinfo()[_screen], NULL, GL_TRUE);
+        RedGlContext context = glXCreateContext(x_display, XPlatform::get_vinfo()[_screen], NULL, GL_TRUE);
         XUnlockDisplay(x_display);
+        return context;
     }
-    return context;
+    return NULL;
 }
 
 RedPbuffer RedWindow::create_pbuff(int width, int height)
commit 8c0f2787abfa64dd839b2dea5fa5acf6f1464cb1
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jul 8 11:40:53 2010 +0200

    build: s/HUGE/INFINITY/
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/client/red_client.cpp b/client/red_client.cpp
index 5291ded..4e3b2dd 100644
--- a/client/red_client.cpp
+++ b/client/red_client.cpp
@@ -641,7 +641,7 @@ void RedClient::send_agent_monitors_config()
         THROW(" monitors query failed");
     }
 
-    double min_distance = HUGE;
+    double min_distance = INFINITY;
     int dx = 0;
     int dy = 0;
     int i;
commit 205193f25523f8dc61aa69b067f4e60e2c4495f4
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Sun Dec 5 20:43:57 2010 +0200

    build: only check for x11 extensions when
    building for x11 platform.

diff --git a/configure.ac b/configure.ac
index 117915e..f3146d8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -238,24 +238,32 @@ AC_SUBST(GL_CFLAGS)
 AC_SUBST(GL_LIBS)
 SPICE_NONPKGCONFIG_LIBS+=" $GL_LIBS"
 
-PKG_CHECK_MODULES(XRANDR, xrandr)
-PKG_CHECK_MODULES(XFIXES, xfixes)
-AC_SUBST(XRANDR_CFLAGS)
-AC_SUBST(XRANDR_LIBS)
-
-PKG_CHECK_MODULES(XRANDR12,
-        xrandr >= 1.2,
-        have_xrandr12=yes,
-        have_xrandr12=no)
+if test "$red_target" = "x11"; then
+	PKG_CHECK_MODULES(XRANDR, xrandr)
+	PKG_CHECK_MODULES(XFIXES, xfixes)
+	AC_SUBST(XRANDR_CFLAGS)
+	AC_SUBST(XRANDR_LIBS)
+	SPICE_REQUIRES+=" xrandr xfixes"
+
+	PKG_CHECK_MODULES(XRANDR12,
+	        xrandr >= 1.2,
+	        have_xrandr12=yes,
+	        have_xrandr12=no)
+else
+	have_xrandr12=no
+fi
 
 AM_CONDITIONAL([HAVE_XRANDR12], [test "x$have_xrandr12" = "xyes"])
 if test "x$have_xrandr12" = "xyes" ; then
   AC_DEFINE([HAVE_XRANDR12], [], [Define if we have XRANDR 12])
 fi
 
-PKG_CHECK_MODULES(MISC_X, x11 xext xrender)
-AC_SUBST(MISC_X_CFLAGS)
-AC_SUBST(MISC_X_LIBS)
+if test "$red_target" = "x11"; then
+	PKG_CHECK_MODULES(MISC_X, x11 xext xrender)
+	AC_SUBST(MISC_X_CFLAGS)
+	AC_SUBST(MISC_X_LIBS)
+	SPICE_REQUIRES+=" x11 xext xrender"
+fi
 
 # Add parameter for (partial) static linkage of spice client.
 # this is used to achive single binary package for all (?) distros.
commit 4492f4854ec888ef2dc428f47f3e5115e295d46a
Author: Gerd Hoffmann <kraxel at redhat.com>
Date:   Thu Jul 8 11:40:49 2010 +0200

    build: alsa is needed on linux only.
    
    Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>

diff --git a/configure.ac b/configure.ac
index dffc975..117915e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -205,9 +205,12 @@ AC_SUBST(CELT051_LIBS)
 AC_SUBST(CELT051_LIBDIR)
 SPICE_REQUIRES+=" celt051 >= 0.5.1.1"
 
-PKG_CHECK_MODULES(ALSA, alsa)
-AC_SUBST(ALSA_CFLAGS)
-AC_SUBST(ALSA_LIBS)
+if test "$os_linux" = yes; then
+	PKG_CHECK_MODULES(ALSA, alsa)
+	AC_SUBST(ALSA_CFLAGS)
+	AC_SUBST(ALSA_LIBS)
+	SPICE_REQUIRES+=" alsa"
+fi
 
 PKG_CHECK_MODULES(SSL, openssl)
 AC_SUBST(SSL_CFLAGS)
commit 58f79a98b696ab36e869d5c1377a9bf0891f28ca
Author: Alon Levy <alevy at redhat.com>
Date:   Mon Dec 6 18:02:52 2010 +0200

    server/tests: Makefile.am: use AM_LDFLAGS instead of LDFLAGS

diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 11cc5f2..ddac420 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -7,24 +7,24 @@ INCLUDES =                          \
 	$(SPICE_NONPKGCONFIG_CFLAGS)    \
 	$(NULL)
 
-LDFLAGS = -L../.libs -lspice-server
+AM_LDFLAGS = -L../.libs -lspice-server
 
 noinst_PROGRAMS = test_just_sockets_no_ssl test_empty_success test_fail_on_null_core_interface test_display_no_ssl
 
 test_display_no_ssl_SOURCES = test_display_no_ssl.c basic_event_loop.c basic_event_loop.h test_util.h
 
-test_display_no_ssl_LDFLAGS = $(LDFLAGS)
+test_display_no_ssl_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS)
 
 test_just_sockets_no_ssl_SOURCES = test_just_sockets_no_ssl.c basic_event_loop.c basic_event_loop.h test_util.h
 
-test_just_sockets_no_ssl_LDFLAGS = $(LDFLAGS)
+test_just_sockets_no_ssl_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS)
 
 test_empty_success_SOURCES = test_empty_success.c
 
-test_empty_success_LDFLAGS = $(LDFLAGS)
+test_empty_success_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS)
 
 test_fail_on_null_core_interface_SOURCES = test_fail_on_null_core_interface.c
 
-test_fail_on_null_core_interface_LDFLAGS = $(LDFLAGS)
+test_fail_on_null_core_interface_LDFLAGS = $(AM_LDFLAGS) $(LDFLAGS)
 
 
commit ae7659fea94717741b7cccdd5718b1fff2804a9d
Author: Alon Levy <alevy at redhat.com>
Date:   Tue Dec 7 12:57:06 2010 +0200

    server/red_channel: error channel if alloc_msg_buf fails (returns NULL)

diff --git a/server/red_channel.c b/server/red_channel.c
index f547f5a..3941338 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -89,6 +89,11 @@ static void red_peer_handle_incoming(RedsStreamContext *peer, IncomingHandler *h
         if (handler->msg_pos < handler->header.size) {
             if (!handler->msg) {
                 handler->msg = handler->alloc_msg_buf(handler->opaque, &handler->header);
+                if (handler->msg == NULL) {
+                    red_printf("ERROR: channel refused to allocate buffer.");
+                    handler->on_error(handler->opaque);
+                    return;
+                }
             }
 
             bytes_read = red_peer_receive(peer,


More information about the Spice-commits mailing list