[Spice-commits] 19 commits - configure.ac .gitlab-ci.yml meson.build README.Windows.md server/dispatcher.c server/Makefile.am server/meson.build server/net-utils.c server/red-channel-client.c server/red-common.h server/red-qxl.c server/red-record-qxl.c server/reds.c server/red-stream.c server/red-stream.h server/red-worker.c server/sound.c server/stat-file.c server/sys-socket.c server/sys-socket.h server/tests tools/Makefile.am tools/meson.build

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue May 7 09:15:21 UTC 2019


 .gitlab-ci.yml                    |   18 ++
 README.Windows.md                 |   31 ++++
 configure.ac                      |   20 ++
 meson.build                       |   15 +-
 server/Makefile.am                |    2 
 server/dispatcher.c               |   28 +++
 server/meson.build                |    2 
 server/net-utils.c                |   11 +
 server/red-channel-client.c       |    2 
 server/red-common.h               |    1 
 server/red-qxl.c                  |   52 +++---
 server/red-record-qxl.c           |    7 
 server/red-stream.c               |   48 +++++-
 server/red-stream.h               |    2 
 server/red-worker.c               |    6 
 server/reds.c                     |  115 ++++++++-------
 server/sound.c                    |    5 
 server/stat-file.c                |    2 
 server/sys-socket.c               |  285 ++++++++++++++++++++++++++++++++++++++
 server/sys-socket.h               |  142 ++++++++++++++++++
 server/tests/Makefile.am          |   11 +
 server/tests/basic-event-loop.c   |    2 
 server/tests/meson.build          |   16 +-
 server/tests/replay.c             |    2 
 server/tests/test-channel.c       |    9 -
 server/tests/test-leaks.c         |    5 
 server/tests/test-loop.c          |    1 
 server/tests/test-record.c        |    7 
 server/tests/test-stream-device.c |    1 
 server/tests/win-alarm.c          |   65 ++++++++
 server/tests/win-alarm.h          |   26 +++
 tools/Makefile.am                 |    2 
 tools/meson.build                 |   10 -
 33 files changed, 834 insertions(+), 117 deletions(-)

New commits:
commit d5041a50399097a1d80a81907e15e322e70aa9b8
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Tue Apr 30 11:59:14 2019 +0100

    ci: Add test for Windows using MingW
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2c1f46ad..91ee47ed 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -93,3 +93,21 @@ makecheck-centos:
     ./autogen.sh --enable-celt051
   - make
   - make -C server check || (cat server/tests/test-suite.log && exit 1)
+
+# Same as makecheck job but use Windows build
+makecheck-windows:
+  script:
+  - >
+    dnf install -y
+    wine-core.x86_64 mingw64-gcc-c++
+    mingw64-openssl mingw64-glib2 mingw64-glib-networking mingw64-libjpeg-turbo
+    mingw64-pixman mingw64-opus mingw64-winpthreads mingw64-zlib
+    mingw64-gstreamer1-plugins-base mingw64-gstreamer1-plugins-good mingw64-orc
+  - cd spice-protocol
+  - mingw64-configure
+  - mingw64-make install
+  - cd ..
+  - NOCONFIGURE=yes ./autogen.sh
+  - mingw64-configure --disable-celt051
+  - mingw64-make
+  - mingw64-make LOG_COMPILE=wine -C server check || (cat server/tests/test-suite.log && exit 1)
commit 80fb39eedd1d8466348e33f758d070a042d6a8c2
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Fri Dec 21 11:41:04 2018 +0000

    Add some notes for the Windows port
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/README.Windows.md b/README.Windows.md
new file mode 100644
index 00000000..98add5fd
--- /dev/null
+++ b/README.Windows.md
@@ -0,0 +1,31 @@
+SPICE server Windows support
+============================
+
+SPICE server was ported from Unix/Linux to Windows.
+
+Most features are present, with some exceptions:
+
+ - Unix sockets;
+ - signal handling;
+ - CLOEXEC flag (completely different handling on Windows);
+ - IPTOS_LOWDELAY flag (Linux specific);
+ - TCP_CORK (Linux/*BSD specific).
+
+Some features could be ported but currently are not:
+
+ - statistics exported through mapped files. Disabled by default and mainly
+   used for development;
+ - filtering while recording (SPICE_WORKER_RECORD_FILTER environment).
+   Recording is used for debugging or development work;
+ - TCP_KEEPIDLE setting. Default is used.
+
+To compile and use with Qemu you can follow the guide at
+https://wiki.qemu.org/Hosts/W32, just pass `--enable-spice` during
+configuration.
+
+To test using a Linux cross compiler you can install Wine and run test
+with
+
+```
+make LOG_COMPILE=wine check
+```
commit d417a0bdfd26a8fb08892cadfc115e7175e61321
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Thu Nov 8 07:50:37 2018 +0000

    Disable recording filtering for Windows
    
    Although this feature can be ported to Windows doing so would
    require the usage of g_spawn_async_with_fds, which is only available
    in GLib 2.58 or some specific Win32 code.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-record-qxl.c b/server/red-record-qxl.c
index f6a627fd..6ae5f213 100644
--- a/server/red-record-qxl.c
+++ b/server/red-record-qxl.c
@@ -815,6 +815,7 @@ void red_record_qxl_command(RedRecord *record, RedMemSlotInfo *slots,
     pthread_mutex_unlock(&record->lock);
 }
 
+#ifndef _WIN32
 /**
  * Redirects child output to the file specified
  */
@@ -827,6 +828,7 @@ static void child_output_setup(gpointer user_data)
     }
     close(fd);
 }
+#endif
 
 RedRecord *red_record_new(const char *filename)
 {
@@ -843,6 +845,7 @@ RedRecord *red_record_new(const char *filename)
 
     filter = getenv("SPICE_WORKER_RECORD_FILTER");
     if (filter) {
+#ifndef _WIN32
         gint argc;
         gchar **argv = NULL;
         GError *error = NULL;
@@ -868,6 +871,10 @@ RedRecord *red_record_new(const char *filename)
         }
         close(fd_in);
         g_spawn_close_pid(child_pid);
+#else
+        // TODO
+        spice_warning("recorder filter not supported under Windows");
+#endif
     }
 
     if (fwrite(header, sizeof(header)-1, 1, f) != 1) {
diff --git a/server/tests/test-record.c b/server/tests/test-record.c
index de3c6f5b..8ee36ceb 100644
--- a/server/tests/test-record.c
+++ b/server/tests/test-record.c
@@ -35,9 +35,9 @@ test_record(bool compress)
     RedRecord *rec;
     const char *fn = OUTPUT_FILENAME;
 
-    unsetenv("SPICE_WORKER_RECORD_FILTER");
+    g_unsetenv("SPICE_WORKER_RECORD_FILTER");
     if (compress) {
-        setenv("SPICE_WORKER_RECORD_FILTER", "gzip", 1);
+        g_setenv("SPICE_WORKER_RECORD_FILTER", "gzip", 1);
     }
 
     // delete possible stale test output
@@ -95,6 +95,9 @@ int
 main(void)
 {
     test_record(false);
+    // TODO implement on Windows
+#ifndef _WIN32
     test_record(true);
+#endif
     return 0;
 }
commit 9a07eb65824121fcf58419b7587a4df870b63da0
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sat Dec 15 18:53:24 2018 +0000

    red-stream: Fix SSL connection for Windows
    
    Set correctly errno to make callers handle correctly encrypted
    traffic.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-stream.c b/server/red-stream.c
index 4706acae..3057d8bb 100644
--- a/server/red-stream.c
+++ b/server/red-stream.c
@@ -156,15 +156,37 @@ static ssize_t stream_read_cb(RedStream *s, void *buf, size_t size)
     return socket_read(s->socket, buf, size);
 }
 
+static ssize_t stream_ssl_error(RedStream *s, int return_code)
+{
+    SPICE_GNUC_UNUSED int ssl_error;
+
+    ssl_error = SSL_get_error(s->priv->ssl, return_code);
+
+    // OpenSSL can to return SSL_ERROR_WANT_READ if we attempt to read
+    // data and the socket did not receive all SSL packet.
+    // Under Windows errno is not set so potentially caller can detect
+    // the wrong error so we need to set errno.
+#ifdef _WIN32
+    if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
+        errno = EAGAIN;
+    } else {
+        errno = EPIPE;
+    }
+#endif
+
+    // red_peer_receive is expected to receive -1 on errors while
+    // OpenSSL documentation just state a <0 value
+    return -1;
+}
+
 static ssize_t stream_ssl_write_cb(RedStream *s, const void *buf, size_t size)
 {
     int return_code;
-    SPICE_GNUC_UNUSED int ssl_error;
 
     return_code = SSL_write(s->priv->ssl, buf, size);
 
     if (return_code < 0) {
-        ssl_error = SSL_get_error(s->priv->ssl, return_code);
+        return stream_ssl_error(s, return_code);
     }
 
     return return_code;
@@ -173,12 +195,11 @@ static ssize_t stream_ssl_write_cb(RedStream *s, const void *buf, size_t size)
 static ssize_t stream_ssl_read_cb(RedStream *s, void *buf, size_t size)
 {
     int return_code;
-    SPICE_GNUC_UNUSED int ssl_error;
 
     return_code = SSL_read(s->priv->ssl, buf, size);
 
     if (return_code < 0) {
-        ssl_error = SSL_get_error(s->priv->ssl, return_code);
+        return stream_ssl_error(s, return_code);
     }
 
     return return_code;
commit fd90a9d0840f41939ec716b6656e38057b18842a
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 21:42:39 2018 +0100

    tests: Exclude tests that cannot work on Windows
    
    test-stream test is passing file descriptor using Unix socket.
    test-stat-file needs some porting work of mmap feature.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index 7668739f..c50826e6 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -53,11 +53,9 @@ check_PROGRAMS =				\
 	test-codecs-parsing			\
 	test-options				\
 	test-stat				\
-	test-stream				\
 	test-agent-msg-filter			\
 	test-loop				\
 	test-qxl-parsing			\
-	test-stat-file				\
 	test-leaks				\
 	test-vdagent				\
 	test-fail-on-null-core-interface	\
@@ -68,6 +66,13 @@ check_PROGRAMS =				\
 	test-record				\
 	$(NULL)
 
+if !OS_WIN32
+check_PROGRAMS +=				\
+	test-stream				\
+	test-stat-file				\
+	$(NULL)
+endif
+
 noinst_PROGRAMS =				\
 	test-display-no-ssl			\
 	test-display-streaming			\
diff --git a/server/tests/meson.build b/server/tests/meson.build
index 31febc6a..b4269c58 100644
--- a/server/tests/meson.build
+++ b/server/tests/meson.build
@@ -40,11 +40,9 @@ tests = [
   ['test-codecs-parsing', true],
   ['test-options', true],
   ['test-stat', true],
-  ['test-stream', true],
   ['test-agent-msg-filter', true],
   ['test-loop', true],
   ['test-qxl-parsing', true],
-  ['test-stat-file', true],
   ['test-leaks', true],
   ['test-vdagent', true],
   ['test-fail-on-null-core-interface', true],
@@ -65,6 +63,13 @@ if spice_server_has_sasl
   tests += [['test-sasl', true]]
 endif
 
+if host_machine.system() != 'windows'
+  tests += [
+    ['test-stream', true],
+    ['test-stat-file', true],
+  ]
+endif
+
 if spice_server_has_gstreamer
   tests += [['test-gst', false]]
   if get_option('extra-checks')
commit d0ae7f157d8fc8780df05840f1c2fe4018fd4fb2
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 19:29:20 2018 +0100

    dispatcher: Port to Windows
    
    Replace poll call with select.
    As socket is set to non-blocking we must support it so if
    we detect an EAGAIN error wait for data.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/dispatcher.c b/server/dispatcher.c
index a1fb705c..602f30a8 100644
--- a/server/dispatcher.c
+++ b/server/dispatcher.c
@@ -199,6 +199,7 @@ static int read_safe(int fd, uint8_t *buf, size_t size, int block)
     }
 
     if (!block) {
+#ifndef _WIN32
         struct pollfd pollfd = {.fd = fd, .events = POLLIN, .revents = 0};
         while ((ret = poll(&pollfd, 1, 0)) == -1) {
             if (errno == EINTR) {
@@ -211,6 +212,15 @@ static int read_safe(int fd, uint8_t *buf, size_t size, int block)
         if (!(pollfd.revents & POLLIN)) {
             return 0;
         }
+#else
+        struct timeval tv = { 0, 0 };
+        fd_set fds;
+        FD_ZERO(&fds);
+        FD_SET(fd, &fds);
+        if (select(1, &fds, NULL, NULL, &tv) < 1) {
+            return 0;
+        }
+#endif
     }
     while (read_size < size) {
         ret = socket_read(fd, buf + read_size, size - read_size);
@@ -219,6 +229,16 @@ static int read_safe(int fd, uint8_t *buf, size_t size, int block)
                 spice_debug("EINTR in read");
                 continue;
             }
+#ifdef _WIN32
+            // Windows turns this socket not-blocking
+            if (errno == EAGAIN) {
+                fd_set fds;
+                FD_ZERO(&fds);
+                FD_SET(fd, &fds);
+                select(1, &fds, NULL, NULL, NULL);
+                continue;
+            }
+#endif
             return -1;
         }
         if (ret == 0) {
commit 524acca643713711cb557e2850ef6317e4f21e69
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Feb 6 12:32:35 2019 +0000

    windows: Disable code not working on Windows
    
    - global signals;
    - CLOEXEC flag;
    - mmap and statistics;
    - IPTOS_LOWDELAY flag;
    - Unix sockets;
    - sharing file descriptors through Unix sockets;
    - TCP_CORK flag.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-channel-client.c b/server/red-channel-client.c
index ce4f4194..4978f356 100644
--- a/server/red-channel-client.c
+++ b/server/red-channel-client.c
@@ -622,6 +622,7 @@ static void red_channel_client_restore_main_sender(RedChannelClient *rcc)
 
 static void red_channel_client_msg_sent(RedChannelClient *rcc)
 {
+#ifndef _WIN32
     int fd;
 
     if (spice_marshaller_get_fd(rcc->priv->send_data.marshaller, &fd)) {
@@ -635,6 +636,7 @@ static void red_channel_client_msg_sent(RedChannelClient *rcc)
         if (fd != -1)
             close(fd);
     }
+#endif
 
     red_channel_client_clear_sent_item(rcc);
 
diff --git a/server/red-stream.c b/server/red-stream.c
index af7036e5..4706acae 100644
--- a/server/red-stream.c
+++ b/server/red-stream.c
@@ -39,7 +39,7 @@
 #include "reds.h"
 
 // compatibility for *BSD systems
-#ifndef TCP_CORK
+#if !defined(TCP_CORK) && !defined(_WIN32)
 #define TCP_CORK TCP_NOPUSH
 #endif
 
@@ -100,6 +100,7 @@ struct RedStreamPrivate {
     SpiceCoreInterfaceInternal *core;
 };
 
+#ifndef _WIN32
 /**
  * Set TCP_CORK on socket
  */
@@ -109,6 +110,12 @@ static int socket_set_cork(int socket, int enabled)
     SPICE_VERIFY(sizeof(enabled) == sizeof(int));
     return setsockopt(socket, IPPROTO_TCP, TCP_CORK, &enabled, sizeof(enabled));
 }
+#else
+static inline int socket_set_cork(int socket, int enabled)
+{
+    return -1;
+}
+#endif
 
 static ssize_t stream_write_cb(RedStream *s, const void *buf, size_t size)
 {
@@ -316,6 +323,7 @@ int red_stream_get_no_delay(RedStream *stream)
     return red_socket_get_no_delay(stream->socket);
 }
 
+#ifndef _WIN32
 int red_stream_send_msgfd(RedStream *stream, int fd)
 {
     struct msghdr msgh = { 0, };
@@ -358,6 +366,7 @@ int red_stream_send_msgfd(RedStream *stream, int fd)
 
     return r;
 }
+#endif
 
 ssize_t red_stream_writev(RedStream *s, const struct iovec *iov, int iovcnt)
 {
diff --git a/server/red-stream.h b/server/red-stream.h
index 9a7cc617..ca6dc71a 100644
--- a/server/red-stream.h
+++ b/server/red-stream.h
@@ -67,7 +67,9 @@ int red_stream_get_family(const RedStream *stream);
 bool red_stream_is_plain_unix(const RedStream *stream);
 bool red_stream_set_no_delay(RedStream *stream, bool no_delay);
 int red_stream_get_no_delay(RedStream *stream);
+#ifndef _WIN32
 int red_stream_send_msgfd(RedStream *stream, int fd);
+#endif
 
 /**
  * Set auto flush flag.
diff --git a/server/red-worker.c b/server/red-worker.c
index 7436df81..d64c26e8 100644
--- a/server/red-worker.c
+++ b/server/red-worker.c
@@ -1143,22 +1143,28 @@ static void *red_worker_main(void *arg)
 
 bool red_worker_run(RedWorker *worker)
 {
+#ifndef _WIN32
     sigset_t thread_sig_mask;
     sigset_t curr_sig_mask;
+#endif
     int r;
 
     spice_return_val_if_fail(worker, FALSE);
     spice_return_val_if_fail(!worker->thread, FALSE);
 
+#ifndef _WIN32
     sigfillset(&thread_sig_mask);
     sigdelset(&thread_sig_mask, SIGILL);
     sigdelset(&thread_sig_mask, SIGFPE);
     sigdelset(&thread_sig_mask, SIGSEGV);
     pthread_sigmask(SIG_SETMASK, &thread_sig_mask, &curr_sig_mask);
+#endif
     if ((r = pthread_create(&worker->thread, NULL, red_worker_main, worker))) {
         spice_error("create thread failed %d", r);
     }
+#ifndef _WIN32
     pthread_sigmask(SIG_SETMASK, &curr_sig_mask, NULL);
+#endif
     pthread_setname_np(worker->thread, "SPICE Worker");
 
     return r == 0;
diff --git a/server/reds.c b/server/reds.c
index b17dc208..d658103e 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -2644,9 +2644,11 @@ static int reds_init_socket(const char *addr, int portnr, int family)
     static const int on=1, off=0;
     struct addrinfo ai,*res,*e;
     char port[33];
-    int slisten, rc, len;
+    int slisten, rc;
 
     if (family == AF_UNIX) {
+#ifndef _WIN32
+        int len;
         struct sockaddr_un local = { 0, };
 
         if ((slisten = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
@@ -2665,6 +2667,9 @@ static int reds_init_socket(const char *addr, int portnr, int family)
         }
 
         goto listen;
+#else
+        return -1;
+#endif
     }
 
     memset(&ai,0, sizeof(ai));
diff --git a/server/sound.c b/server/sound.c
index 9888a9f0..c952ffc5 100644
--- a/server/sound.c
+++ b/server/sound.c
@@ -773,7 +773,6 @@ static void record_channel_send_item(RedChannelClient *rcc, G_GNUC_UNUSED RedPip
 
 static bool snd_channel_client_config_socket(RedChannelClient *rcc)
 {
-    int tos;
     RedStream *stream = red_channel_client_get_stream(rcc);
     RedClient *red_client = red_channel_client_get_client(rcc);
     MainChannelClient *mcc = red_client_get_main(red_client);
@@ -789,7 +788,8 @@ static bool snd_channel_client_config_socket(RedChannelClient *rcc)
     }
 #endif
 
-    tos = IPTOS_LOWDELAY;
+#ifdef IPTOS_LOWDELAY
+    int tos = IPTOS_LOWDELAY;
     if (setsockopt(stream->socket, IPPROTO_IP, IP_TOS, (void*)&tos, sizeof(tos)) == -1) {
         if (errno != ENOTSUP) {
             red_channel_warning(red_channel_client_get_channel(rcc),
@@ -797,6 +797,7 @@ static bool snd_channel_client_config_socket(RedChannelClient *rcc)
                                 strerror(errno));
         }
     }
+#endif
 
     red_stream_set_no_delay(stream, !main_channel_client_is_low_bandwidth(mcc));
 
diff --git a/server/stat-file.c b/server/stat-file.c
index 211cddfa..4228be31 100644
--- a/server/stat-file.c
+++ b/server/stat-file.c
@@ -17,6 +17,7 @@
 */
 #include <config.h>
 
+#ifndef _WIN32
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -234,3 +235,4 @@ void stat_file_remove_counter(RedStatFile *stat_file, uint64_t *counter)
 {
     stat_file_remove(stat_file, (SpiceStatNode *)(counter - SPICE_OFFSETOF(SpiceStatNode, value)));
 }
+#endif
diff --git a/server/tests/basic-event-loop.c b/server/tests/basic-event-loop.c
index 607a5a5e..e331e852 100644
--- a/server/tests/basic-event-loop.c
+++ b/server/tests/basic-event-loop.c
@@ -68,12 +68,14 @@ void basic_event_loop_quit(void)
 
 static void ignore_sigpipe(void)
 {
+#ifndef _WIN32
     struct sigaction act;
 
     memset(&act, 0, sizeof(act));
     sigfillset(&act.sa_mask);
     act.sa_handler = SIG_IGN;
     sigaction(SIGPIPE, &act, NULL);
+#endif
 }
 
 static SpiceTimer* base_timer_add(SpiceTimerFunc func, void *opaque)
diff --git a/server/tests/replay.c b/server/tests/replay.c
index 0da5f997..e3ef7bf1 100644
--- a/server/tests/replay.c
+++ b/server/tests/replay.c
@@ -409,10 +409,12 @@ int main(int argc, char **argv)
     }
     g_strfreev(file);
     file = NULL;
+#ifndef _WIN32
     if (fcntl(fileno(fd), FD_CLOEXEC) < 0) {
         perror("fcntl failed");
         exit(1);
     }
+#endif
     fseek(fd, 0L, SEEK_END);
     total_size = ftell(fd);
     fseek(fd, 0L, SEEK_SET);
diff --git a/tools/Makefile.am b/tools/Makefile.am
index cfb0a213..702fcdd1 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -10,6 +10,7 @@ AM_LDFLAGS = \
 	$(LIBRT) \
 	$(NULL)
 
+if !OS_WIN32
 noinst_PROGRAMS = \
 	reds_stat \
 	$(NULL)
@@ -17,6 +18,7 @@ noinst_PROGRAMS = \
 reds_stat_SOURCES = \
 	reds_stat.c \
 	$(NULL)
+endif
 
 EXTRA_DIST = \
 	meson.build \
diff --git a/tools/meson.build b/tools/meson.build
index 1d78340b..8ec2cc91 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -1,4 +1,6 @@
-executable('reds_stat', 'reds_stat.c',
-           install : false,
-           include_directories : spice_server_include,
-           dependencies : spice_server_deps)
+if host_machine.system() != 'windows'
+  executable('reds_stat', 'reds_stat.c',
+             install : false,
+             include_directories : spice_server_include,
+             dependencies : spice_server_deps)
+endif
commit c8ab3c2c984732d4f210b85c3f23139fef06da9d
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 19:50:59 2018 +0100

    test-channel: Use socket compatibility layer
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/tests/test-channel.c b/server/tests/test-channel.c
index fcea98aa..372c8d79 100644
--- a/server/tests/test-channel.c
+++ b/server/tests/test-channel.c
@@ -183,7 +183,7 @@ static void send_ack_sync(int socket, uint32_t generation)
     msg.len = GUINT32_TO_LE(sizeof(generation));
     msg.generation = GUINT32_TO_LE(generation);
 
-    g_assert_cmpint(write(socket, &msg.type, 10), ==, 10);
+    g_assert_cmpint(socket_write(socket, &msg.type, 10), ==, 10);
 }
 
 static SpiceTimer *waked_up_timer;
@@ -198,7 +198,7 @@ static void timer_wakeup(void *opaque)
     ssize_t len;
     alarm(1);
     char buffer[256];
-    while ((len=recv(client_socket, buffer, sizeof(buffer), 0)) > 0)
+    while ((len=socket_read(client_socket, buffer, sizeof(buffer))) > 0)
         got_data += len;
     alarm(0);
 
@@ -218,7 +218,7 @@ static void timeout_watch_count(void *opaque)
     // get all pending data
     alarm(1);
     char buffer[256];
-    while (recv(client_socket, buffer, sizeof(buffer), 0) > 0)
+    while (socket_read(client_socket, buffer, sizeof(buffer)) > 0)
         continue;
     alarm(0);
 
@@ -226,7 +226,7 @@ static void timeout_watch_count(void *opaque)
     watch_called_countdown = 20;
 
     // send ack reply, this should unblock data from RedChannelClient
-    g_assert_cmpint(write(client_socket, "\2\0\0\0\0\0", 6), ==, 6);
+    g_assert_cmpint(socket_write(client_socket, "\2\0\0\0\0\0", 6), ==, 6);
 
     // expect data soon
     waked_up_timer = core->timer_add(timer_wakeup, core);
commit 5ab0667eff88eb43c8dca8500fad3b087778fe0d
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 21:40:20 2018 +0100

    test-leaks: Use socket compatibility layer
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/tests/test-leaks.c b/server/tests/test-leaks.c
index 64130c22..be9fe2d2 100644
--- a/server/tests/test-leaks.c
+++ b/server/tests/test-leaks.c
@@ -35,6 +35,7 @@
 #include "test-glib-compat.h"
 #include "basic-event-loop.h"
 #include "test-display-base.h"
+#include "sys-socket.h"
 
 #define PKI_DIR SPICE_TOP_SRCDIR "/server/tests/pki/"
 
@@ -70,11 +71,11 @@ static void server_leaks(void)
     g_test_expect_message(G_LOG_DOMAIN, G_LOG_LEVEL_WARNING,
                           "*SSL_accept failed*");
     g_assert_cmpint(socketpair(AF_LOCAL, SOCK_STREAM, 0, sv), ==, 0);
-    close(sv[1]);
+    socket_close(sv[1]);
     result = spice_server_add_ssl_client(server, sv[0], 1);
     g_assert_cmpint(result, ==, -1);
     /* if the function fails, it should not close the socket */
-    g_assert_cmpint(close(sv[0]), ==, 0);
+    g_assert_cmpint(socket_close(sv[0]), ==, 0);
 
     spice_server_destroy(server);
     basic_event_loop_destroy();
commit 3a95e77af2864002fefecb56da3d600bbca52a62
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 19:10:44 2018 +0100

    dispatcher: Use socket compatibility layer
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/dispatcher.c b/server/dispatcher.c
index 5204ddee..a1fb705c 100644
--- a/server/dispatcher.c
+++ b/server/dispatcher.c
@@ -113,8 +113,8 @@ dispatcher_finalize(GObject *object)
 {
     Dispatcher *self = DISPATCHER(object);
     g_free(self->priv->messages);
-    close(self->priv->send_fd);
-    close(self->priv->recv_fd);
+    socket_close(self->priv->send_fd);
+    socket_close(self->priv->recv_fd);
     pthread_mutex_destroy(&self->priv->lock);
     g_free(self->priv->payload);
     G_OBJECT_CLASS(dispatcher_parent_class)->finalize(object);
@@ -213,7 +213,7 @@ static int read_safe(int fd, uint8_t *buf, size_t size, int block)
         }
     }
     while (read_size < size) {
-        ret = read(fd, buf + read_size, size - read_size);
+        ret = socket_read(fd, buf + read_size, size - read_size);
         if (ret == -1) {
             if (errno == EINTR) {
                 spice_debug("EINTR in read");
@@ -240,7 +240,7 @@ static int write_safe(int fd, uint8_t *buf, size_t size)
     int ret;
 
     while (written_size < size) {
-        ret = write(fd, buf + written_size, size - written_size);
+        ret = socket_write(fd, buf + written_size, size - written_size);
         if (ret == -1) {
             if (errno != EINTR) {
                 return -1;
commit 5c651076631dbf6015177d4a2c2ee567751dc630
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Jun 20 14:23:44 2018 +0100

    red-stream: Use socket compatibility layer
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-stream.c b/server/red-stream.c
index 323af58c..af7036e5 100644
--- a/server/red-stream.c
+++ b/server/red-stream.c
@@ -112,7 +112,7 @@ static int socket_set_cork(int socket, int enabled)
 
 static ssize_t stream_write_cb(RedStream *s, const void *buf, size_t size)
 {
-    return write(s->socket, buf, size);
+    return socket_write(s->socket, buf, size);
 }
 
 static ssize_t stream_writev_cb(RedStream *s, const struct iovec *iov, int iovcnt)
@@ -130,7 +130,7 @@ static ssize_t stream_writev_cb(RedStream *s, const struct iovec *iov, int iovcn
         for (i = 0; i < tosend; i++) {
             expected += iov[i].iov_len;
         }
-        n = writev(s->socket, iov, tosend);
+        n = socket_writev(s->socket, iov, tosend);
         if (n <= expected) {
             if (n > 0)
                 ret += n;
@@ -146,7 +146,7 @@ static ssize_t stream_writev_cb(RedStream *s, const struct iovec *iov, int iovcn
 
 static ssize_t stream_read_cb(RedStream *s, void *buf, size_t size)
 {
-    return read(s->socket, buf, size);
+    return socket_read(s->socket, buf, size);
 }
 
 static ssize_t stream_ssl_write_cb(RedStream *s, const void *buf, size_t size)
@@ -402,7 +402,7 @@ void red_stream_free(RedStream *s)
     }
 
     red_stream_remove_watch(s);
-    close(s->socket);
+    socket_close(s->socket);
 
     g_free(s);
 }
commit 14d4cdebc3c9c0fd18262d8eeb1ac620a9b93ce4
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 19:04:07 2018 +0100

    reds: Use socket compatibility layer (close -> socket_close)
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-common.h b/server/red-common.h
index 181ed283..6b5d0b2e 100644
--- a/server/red-common.h
+++ b/server/red-common.h
@@ -35,6 +35,7 @@
 
 #include "spice.h"
 #include "utils.h"
+#include "sys-socket.h"
 
 #define SPICE_UPCAST(type, ptr) \
     (verify_expr(SPICE_OFFSETOF(type, base) == 0,SPICE_CONTAINEROF(ptr, type, base)))
diff --git a/server/reds.c b/server/reds.c
index 3f1a4a05..b17dc208 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -106,6 +106,7 @@ static void adapter_timer_remove(const SpiceCoreInterfaceInternal *iface, SpiceT
 static SpiceWatch *adapter_watch_add(const SpiceCoreInterfaceInternal *iface,
                                      int fd, int event_mask, SpiceWatchFunc func, void *opaque)
 {
+    // note: Qemu API is fine having a SOCKET on Windows
     return iface->public_interface->watch_add(fd, event_mask, func, opaque);
 }
 
@@ -2659,7 +2660,7 @@ static int reds_init_socket(const char *addr, int portnr, int family)
         len = SUN_LEN(&local);
         if (bind(slisten, (struct sockaddr *)&local, len) == -1) {
             perror("bind");
-            close(slisten);
+            socket_close(slisten);
             return -1;
         }
 
@@ -2707,7 +2708,7 @@ static int reds_init_socket(const char *addr, int portnr, int family)
             freeaddrinfo(res);
             goto listen;
         }
-        close(slisten);
+        socket_close(slisten);
     }
     spice_warning("binding socket to %s:%d failed", addr, portnr);
     freeaddrinfo(res);
@@ -2716,7 +2717,7 @@ static int reds_init_socket(const char *addr, int portnr, int family)
 listen:
     if (listen(slisten, SOMAXCONN) != 0) {
         spice_warning("listen: %s", strerror(errno));
-        close(slisten);
+        socket_close(slisten);
         return -1;
     }
     return slisten;
@@ -2754,14 +2755,14 @@ static void reds_cleanup_net(SpiceServer *reds)
     if (reds->listen_socket != -1) {
        reds_core_watch_remove(reds, reds->listen_watch);
        if (reds->config->spice_listen_socket_fd != reds->listen_socket) {
-          close(reds->listen_socket);
+          socket_close(reds->listen_socket);
        }
        reds->listen_watch = NULL;
        reds->listen_socket = -1;
     }
     if (reds->secure_listen_socket != -1) {
        reds_core_watch_remove(reds, reds->secure_listen_watch);
-       close(reds->secure_listen_socket);
+       socket_close(reds->secure_listen_socket);
        reds->secure_listen_watch = NULL;
        reds->secure_listen_socket = -1;
     }
commit 026fab1825fac30770d96cf0c45f15df0d29b329
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Jun 20 14:23:44 2018 +0100

    net-utils: Port to Windows
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/net-utils.c b/server/net-utils.c
index 71912728..144bfd8f 100644
--- a/server/net-utils.c
+++ b/server/net-utils.c
@@ -33,6 +33,7 @@
 #include <common/log.h>
 
 #include "net-utils.h"
+#include "sys-socket.h"
 
 /**
  * red_socket_set_keepalive:
@@ -99,6 +100,15 @@ bool red_socket_set_no_delay(int fd, bool no_delay)
  */
 bool red_socket_set_non_blocking(int fd, bool non_blocking)
 {
+#ifdef _WIN32
+    u_long ioctl_nonblocking = 1;
+
+    if (ioctlsocket(fd, FIONBIO, &ioctl_nonblocking) != 0) {
+        spice_warning("ioctlsocket(FIONBIO) failed, %d", WSAGetLastError());
+        return false;
+    }
+    return true;
+#else
     int flags;
 
     if ((flags = fcntl(fd, F_GETFL)) == -1) {
@@ -118,6 +128,7 @@ bool red_socket_set_non_blocking(int fd, bool non_blocking)
     }
 
     return true;
+#endif
 }
 
 /**
commit 0c59394b241c392d2eb75379c1bb8fae2489f8a1
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Feb 6 11:39:25 2019 +0000

    sys-socket: Add socket_newpair utility
    
    Allows to easier port socketpair.
    Windows does not have this function, we need to create a pair
    using 2 internet sockets and connecting one to the other.
    The SPICE core interface implementation provided by Qemu under
    Windows requires, under Windows, to provide SOCKET handles
    so pipes or other Windows handles won't work.
    Windows does not provide a socketpair function so use this
    replacement.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/sys-socket.c b/server/sys-socket.c
index 5ac627b4..b97335c7 100644
--- a/server/sys-socket.c
+++ b/server/sys-socket.c
@@ -207,4 +207,79 @@ SPICE_CONSTRUCTOR_FUNC(socket_win32_init)
     WSADATA wsaData;
     WSAStartup(MAKEWORD(2, 2), &wsaData);
 }
+
+int socket_newpair(int type, int protocol, int sv[2])
+{
+    struct sockaddr_in sa, sa2;
+    socklen_t addrlen;
+    SOCKET s, pairs[2];
+
+    if (!sv) {
+        return -1;
+    }
+
+    /* create a listener */
+    s = socket(AF_INET, type, 0);
+    if (s == INVALID_SOCKET) {
+        return -1;
+    }
+
+    pairs[1] = INVALID_SOCKET;
+
+    pairs[0] = socket(AF_INET, type, 0);
+    if (pairs[0] == INVALID_SOCKET) {
+        goto cleanup;
+    }
+
+    /* bind to a random port */
+    sa.sin_family = AF_INET;
+    sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    sa.sin_port = 0;
+    if (bind(s, (struct sockaddr*) &sa, sizeof(sa)) < 0) {
+        goto cleanup;
+    }
+    if (listen(s, 1) < 0) {
+        goto cleanup;
+    }
+
+    /* connect to kernel choosen port */
+    addrlen = sizeof(sa);
+    if (getsockname(s, (struct sockaddr*) &sa, &addrlen) < 0) {
+        goto cleanup;
+    }
+    if (connect(pairs[0], (struct sockaddr*) &sa, sizeof(sa)) < 0) {
+        goto cleanup;
+    }
+    addrlen = sizeof(sa2);
+    pairs[1] = accept(s, (struct sockaddr*) &sa2, &addrlen);
+    if (pairs[1] == INVALID_SOCKET) {
+        goto cleanup;
+    }
+
+    /* check proper connection */
+    addrlen = sizeof(sa);
+    if (getsockname(pairs[0], (struct sockaddr*) &sa, &addrlen) < 0) {
+        goto cleanup;
+    }
+    addrlen = sizeof(sa2);
+    if (getpeername(pairs[1], (struct sockaddr*) &sa2, &addrlen) < 0) {
+        goto cleanup;
+    }
+    if (sa.sin_family != sa2.sin_family || sa.sin_port != sa2.sin_port
+        || sa.sin_addr.s_addr != sa2.sin_addr.s_addr) {
+        goto cleanup;
+    }
+
+    closesocket(s);
+    sv[0] = pairs[0];
+    sv[1] = pairs[1];
+    return 0;
+
+cleanup:
+    socket_win32_set_errno();
+    closesocket(s);
+    closesocket(pairs[0]);
+    closesocket(pairs[1]);
+    return -1;
+}
 #endif
diff --git a/server/sys-socket.h b/server/sys-socket.h
index 65062571..3a3b7878 100644
--- a/server/sys-socket.h
+++ b/server/sys-socket.h
@@ -134,6 +134,9 @@ socket_accept(int sock, struct sockaddr *addr, int *addrlen)
 }
 #undef accept
 #define accept socket_accept
+
+int socket_newpair(int type, int protocol, int sv[2]);
+#define socketpair(family, type, protocol, sv) socket_newpair(type, protocol, sv)
 #endif
 
 #endif // RED_SYS_SOCKET_H_
commit 55dd7410b0a993e4bcdb85fef461d8f72cd2ff42
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Jun 20 14:23:44 2018 +0100

    sys-socket: Introduce some utility to make sockets more portable
    
    Between Unix and Windows socket are quite different:
    - on Windows sockets have a different namespace from C file
      descriptors so you can't use read/write/close or similar functions;
    - errors are not stored in errno but you must be read/write the
      errors with specific function;
    - sometimes sockets are put in non-blocking mode automatically
      calling some functions;
    - SOCKET type is 64 bit on Windows 64 which does not fit technically
      in an int. Is however safe to assume them to fit in an int.
    
    So encapsulate the socket APIs in some definition to make easier
    and more safe to deal with them.
    Where the portability to Windows would make to code more offuscated a Unix
    style was preferred. For instance if errors are detected errno is set from
    Windows socket error instead of changing all code handling.
    Fortunately on Windows Qemu core interface accepts socket (but not
    other types like C file descriptors!).
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Reviewed-by: Marc-André Lureau <marcandre.lureau at redhat.com>

diff --git a/server/Makefile.am b/server/Makefile.am
index 34ec22ad..7f260612 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -166,6 +166,8 @@ libserver_la_SOURCES =				\
 	stat.h					\
 	stream-channel.c			\
 	stream-channel.h			\
+	sys-socket.h				\
+	sys-socket.c				\
 	red-stream-device.c			\
 	red-stream-device.h			\
 	sw-canvas.c				\
diff --git a/server/meson.build b/server/meson.build
index 63191d79..34d8eef1 100644
--- a/server/meson.build
+++ b/server/meson.build
@@ -133,6 +133,8 @@ spice_server_sources = [
   'stat.h',
   'stream-channel.c',
   'stream-channel.h',
+  'sys-socket.c',
+  'sys-socket.h',
   'red-stream-device.c',
   'red-stream-device.h',
   'sw-canvas.c',
diff --git a/server/sys-socket.c b/server/sys-socket.c
new file mode 100644
index 00000000..5ac627b4
--- /dev/null
+++ b/server/sys-socket.c
@@ -0,0 +1,210 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2018 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 <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/tcp.h>
+#include <sys/socket.h>
+#endif
+
+#include <common/log.h>
+
+#include "sys-socket.h"
+
+#ifdef _WIN32
+// Map Windows socket errors to standard C ones
+// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms740668(v=vs.85).aspx
+void socket_win32_set_errno(void)
+{
+    int err = EPIPE; // default
+    switch (WSAGetLastError()) {
+    case WSAEWOULDBLOCK:
+    case WSAEINPROGRESS:
+        err = EAGAIN;
+        break;
+    case WSAEINTR:
+        err = EINTR;
+        break;
+    case WSAEBADF:
+        err = EBADF;
+        break;
+    case WSA_INVALID_HANDLE:
+    case WSA_INVALID_PARAMETER:
+    case WSAEINVAL:
+        err = EINVAL;
+        break;
+    case WSAENOTSOCK:
+        err = ENOTSOCK;
+        break;
+    case WSA_NOT_ENOUGH_MEMORY:
+        err = ENOMEM;
+        break;
+    case WSAEPROTONOSUPPORT:
+    case WSAESOCKTNOSUPPORT:
+    case WSAEOPNOTSUPP:
+    case WSAEPFNOSUPPORT:
+    case WSAEAFNOSUPPORT:
+    case WSAVERNOTSUPPORTED:
+        err = ENOTSUP;
+        break;
+    case WSAEFAULT:
+        err = EFAULT;
+        break;
+    case WSAEACCES:
+        err = EACCES;
+        break;
+    case WSAEMFILE:
+        err = EMFILE;
+        break;
+    case WSAENAMETOOLONG:
+        err = ENAMETOOLONG;
+        break;
+    case WSAENOTEMPTY:
+        err = ENOTEMPTY;
+        break;
+    case WSA_OPERATION_ABORTED:
+    case WSAECANCELLED:
+    case WSA_E_CANCELLED:
+        err = ECANCELED;
+        break;
+    case WSAEADDRINUSE:
+        err = EADDRINUSE;
+        break;
+    case WSAENETDOWN:
+        err = ENETDOWN;
+        break;
+    case WSAENETUNREACH:
+        err = ENETUNREACH;
+        break;
+    case WSAENETRESET:
+        err = ENETRESET;
+        break;
+    case WSAECONNABORTED:
+        err = ECONNABORTED;
+        break;
+    case WSAECONNRESET:
+        err = ECONNRESET;
+        break;
+    case WSAEISCONN:
+        err = EISCONN;
+        break;
+    case WSAENOTCONN:
+        err = ENOTCONN;
+        break;
+    case WSAETIMEDOUT:
+        err = ETIMEDOUT;
+        break;
+    case WSAECONNREFUSED:
+        err = ECONNREFUSED;
+        break;
+    case WSAEHOSTUNREACH:
+        err = EHOSTUNREACH;
+        break;
+    case WSAEDESTADDRREQ:
+        err = EDESTADDRREQ;
+        break;
+    case WSAEMSGSIZE:
+        err = EMSGSIZE;
+        break;
+    case WSAEPROTOTYPE:
+        err = EPROTOTYPE;
+        break;
+    case WSAENOPROTOOPT:
+        err = ENOPROTOOPT;
+        break;
+    case WSAEADDRNOTAVAIL:
+        err = EADDRNOTAVAIL;
+        break;
+    case WSAENOBUFS:
+        err = ENOBUFS;
+        break;
+    // TODO
+    case WSAESTALE:
+    case WSAEDISCON:
+    case WSA_IO_INCOMPLETE:
+    case WSA_IO_PENDING:
+    case WSAEALREADY:
+    case WSAESHUTDOWN:
+    case WSAETOOMANYREFS:
+    case WSAELOOP:
+    case WSAEHOSTDOWN:
+    case WSAEPROCLIM:
+    case WSAEUSERS:
+    case WSAEDQUOT:
+    case WSAEREMOTE:
+    case WSASYSNOTREADY:
+    case WSANOTINITIALISED:
+    case WSAENOMORE:
+    case WSAEINVALIDPROCTABLE:
+    case WSAEINVALIDPROVIDER:
+    case WSAEPROVIDERFAILEDINIT:
+    case WSASYSCALLFAILURE:
+    case WSASERVICE_NOT_FOUND:
+    case WSATYPE_NOT_FOUND:
+    case WSA_E_NO_MORE:
+    case WSAEREFUSED:
+    case WSAHOST_NOT_FOUND:
+    case WSATRY_AGAIN:
+    case WSANO_RECOVERY:
+    case WSANO_DATA:
+    case WSA_QOS_RECEIVERS:
+    case WSA_QOS_SENDERS:
+    case WSA_QOS_NO_SENDERS:
+    case WSA_QOS_NO_RECEIVERS:
+    case WSA_QOS_REQUEST_CONFIRMED:
+    case WSA_QOS_ADMISSION_FAILURE:
+    case WSA_QOS_POLICY_FAILURE:
+    case WSA_QOS_BAD_STYLE:
+    case WSA_QOS_BAD_OBJECT:
+    case WSA_QOS_TRAFFIC_CTRL_ERROR:
+    case WSA_QOS_GENERIC_ERROR:
+    case WSA_QOS_ESERVICETYPE:
+    case WSA_QOS_EFLOWSPEC:
+    case WSA_QOS_EPROVSPECBUF:
+    case WSA_QOS_EFILTERSTYLE:
+    case WSA_QOS_EFILTERTYPE:
+    case WSA_QOS_EFILTERCOUNT:
+    case WSA_QOS_EOBJLENGTH:
+    case WSA_QOS_EFLOWCOUNT:
+    case WSA_QOS_EUNKOWNPSOBJ:
+    case WSA_QOS_EPOLICYOBJ:
+    case WSA_QOS_EFLOWDESC:
+    case WSA_QOS_EPSFLOWSPEC:
+    case WSA_QOS_EPSFILTERSPEC:
+    case WSA_QOS_ESDMODEOBJ:
+    case WSA_QOS_ESHAPERATEOBJ:
+    case WSA_QOS_RESERVED_PETYPE:
+        break;
+    }
+    errno = err;
+}
+
+SPICE_CONSTRUCTOR_FUNC(socket_win32_init)
+{
+    WSADATA wsaData;
+    WSAStartup(MAKEWORD(2, 2), &wsaData);
+}
+#endif
diff --git a/server/sys-socket.h b/server/sys-socket.h
new file mode 100644
index 00000000..65062571
--- /dev/null
+++ b/server/sys-socket.h
@@ -0,0 +1,139 @@
+/*
+   Copyright (C) 2018 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/>.
+*/
+
+/* Small compatibility layer for sockets, mostly to make easier portability
+ * for Windows but without loosing performances under Unix, the most supported
+ * system */
+#ifndef RED_SYS_SOCKET_H_
+#define RED_SYS_SOCKET_H_
+
+#ifndef _WIN32
+#  include <sys/socket.h>
+
+#define socket_read(sock, buf, len) read(sock, buf, len)
+#define socket_write(sock, buf, len) write(sock, buf, len)
+#define socket_writev(sock, iov, n) writev(sock, iov, n)
+#define socket_close(sock) close(sock)
+
+#else
+#  include <winsock2.h>
+#  include <windows.h>
+typedef int socklen_t;
+
+// this definition is ABI compatible with WSABUF
+struct iovec {
+    u_long iov_len;
+    void FAR *iov_base;
+};
+
+void socket_win32_set_errno(void);
+
+static inline ssize_t socket_read(int sock, void *buf, size_t count)
+{
+    ssize_t res = recv(sock, buf, count, 0);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+
+static inline ssize_t socket_write(int sock, const void *buf, size_t count)
+{
+    ssize_t res = send(sock, buf, count, 0);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+
+static inline ssize_t socket_writev(int sock, const struct iovec *iov, int n_iov)
+{
+    DWORD sent;
+    int res = WSASend(sock, (LPWSABUF) iov, n_iov, &sent, 0, NULL, NULL);
+    if (res) {
+        socket_win32_set_errno();
+        return -1;
+    }
+    return sent;
+}
+
+#define socket_close(sock) closesocket(sock)
+
+#define SHUT_RDWR SD_BOTH
+
+static inline int
+socket_getsockopt(int sock, int lvl, int type, void *value, socklen_t *len)
+{
+    int res = getsockopt(sock, lvl, type, value, len);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+#undef getsockopt
+#define getsockopt socket_getsockopt
+
+static inline int
+socket_setsockopt(int sock, int lvl, int type, const void *value, socklen_t len)
+{
+    int res = setsockopt(sock, lvl, type, value, len);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+#undef setsockopt
+#define setsockopt socket_setsockopt
+
+static inline int
+socket_listen(int sock, int backlog)
+{
+    int res = listen(sock, backlog);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+#undef listen
+#define listen socket_listen
+
+static inline int
+socket_bind(int sock, const struct sockaddr *addr, int addrlen)
+{
+    int res = bind(sock, addr, addrlen);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+#undef bind
+#define bind socket_bind
+
+static inline int
+socket_accept(int sock, struct sockaddr *addr, int *addrlen)
+{
+    int res = accept(sock, addr, addrlen);
+    if (res < 0) {
+        socket_win32_set_errno();
+    }
+    return res;
+}
+#undef accept
+#define accept socket_accept
+#endif
+
+#endif // RED_SYS_SOCKET_H_
commit 8031558ee37cdf406caae23fa6fcded6b398fb2a
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 21:28:02 2018 +0100

    tests: Provide alarm replacement for Windows
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/tests/Makefile.am b/server/tests/Makefile.am
index d7f7af9b..7668739f 100644
--- a/server/tests/Makefile.am
+++ b/server/tests/Makefile.am
@@ -35,6 +35,8 @@ libtest_a_SOURCES =				\
 	test-display-base.h			\
 	test-glib-compat.c			\
 	test-glib-compat.h			\
+	win-alarm.c				\
+	win-alarm.h				\
 	$(NULL)
 
 LDADD =								\
diff --git a/server/tests/meson.build b/server/tests/meson.build
index 20548213..31febc6a 100644
--- a/server/tests/meson.build
+++ b/server/tests/meson.build
@@ -11,6 +11,8 @@ test_lib_sources = [
   'test-display-base.h',
   'test-glib-compat.c',
   'test-glib-compat.h',
+  'win-alarm.c',
+  'win-alarm.h',
 ]
 
 test_libs = []
diff --git a/server/tests/test-channel.c b/server/tests/test-channel.c
index 9700e31c..fcea98aa 100644
--- a/server/tests/test-channel.c
+++ b/server/tests/test-channel.c
@@ -28,6 +28,7 @@
 #include "red-client.h"
 #include "cursor-channel.h"
 #include "net-utils.h"
+#include "win-alarm.h"
 
 /*
  * Declare a RedTestChannel to be used for the test
diff --git a/server/tests/test-loop.c b/server/tests/test-loop.c
index 1e3b39e5..82af80ab 100644
--- a/server/tests/test-loop.c
+++ b/server/tests/test-loop.c
@@ -31,6 +31,7 @@
 #include <spice/macros.h>
 #include <common/log.h>
 #include "basic-event-loop.h"
+#include "win-alarm.h"
 
 static SpiceCoreInterface *core = NULL;
 static GMainLoop *loop = NULL;
diff --git a/server/tests/test-stream-device.c b/server/tests/test-stream-device.c
index ce37822f..f5698c7d 100644
--- a/server/tests/test-stream-device.c
+++ b/server/tests/test-stream-device.c
@@ -33,6 +33,7 @@
 #include "test-glib-compat.h"
 #include "stream-channel.h"
 #include "reds.h"
+#include "win-alarm.h"
 
 static SpiceCharDeviceInstance vmc_instance;
 
diff --git a/server/tests/win-alarm.c b/server/tests/win-alarm.c
new file mode 100644
index 00000000..225d0709
--- /dev/null
+++ b/server/tests/win-alarm.c
@@ -0,0 +1,65 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2018 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 <config.h>
+#include <glib.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include "win-alarm.h"
+
+static HANDLE alarm_cond = NULL;
+
+static DWORD WINAPI alarm_thread_proc(LPVOID arg)
+{
+    unsigned int timeout = (uintptr_t) arg;
+    switch (WaitForSingleObject(alarm_cond, timeout * 1000)) {
+    case WAIT_OBJECT_0:
+        return 0;
+    }
+    abort();
+    return 0;
+}
+
+void alarm(unsigned int timeout)
+{
+    static HANDLE thread = NULL;
+
+    // create an event to stop the alarm thread
+    if (alarm_cond == NULL) {
+        alarm_cond = CreateEvent(NULL, TRUE, FALSE, NULL);
+        g_assert(alarm_cond != NULL);
+    }
+
+    // stop old alarm
+    if (thread) {
+        SetEvent(alarm_cond);
+        g_assert(WaitForSingleObject(thread, INFINITE) == WAIT_OBJECT_0);
+        CloseHandle(thread);
+        thread = NULL;
+    }
+
+    if (timeout) {
+        ResetEvent(alarm_cond);
+
+        // start alarm thread
+        thread = CreateThread(NULL, 0, alarm_thread_proc, (LPVOID) (uintptr_t) timeout, 0, NULL);
+        g_assert(thread);
+    }
+}
+#endif
diff --git a/server/tests/win-alarm.h b/server/tests/win-alarm.h
new file mode 100644
index 00000000..a7233a8f
--- /dev/null
+++ b/server/tests/win-alarm.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2018 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 TEST_WIN_ALARM_H
+#define TEST_WIN_ALARM_H
+
+#ifdef _WIN32
+void test_alarm(unsigned int timeout);
+#define alarm test_alarm
+#endif
+
+#endif // TEST_WIN_ALARM_H
commit 50be664da2e084d3fc32bb45a5acc642652428dc
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Sun Jun 24 19:22:16 2018 +0100

    windows: Do not use conflicting preprocessor macros
    
    "interface" and "MAX_MONITORS" are defined in some Windows system
    headers causing garbage code to be fed to the compiler.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/red-qxl.c b/server/red-qxl.c
index 5fa974fc..d40d3970 100644
--- a/server/red-qxl.c
+++ b/server/red-qxl.c
@@ -966,95 +966,95 @@ RedsState* red_qxl_get_server(QXLState *qxl_state)
 
 void red_qxl_attach_worker(QXLInstance *qxl)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
-    interface->attache_worker(qxl, &qxl->st->qxl_worker);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
+    qxl_interface->attache_worker(qxl, &qxl->st->qxl_worker);
 }
 
 void red_qxl_set_compression_level(QXLInstance *qxl, int level)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
-    interface->set_compression_level(qxl, level);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
+    qxl_interface->set_compression_level(qxl, level);
 }
 
 void red_qxl_get_init_info(QXLInstance *qxl, QXLDevInitInfo *info)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    interface->get_init_info(qxl, info);
+    qxl_interface->get_init_info(qxl, info);
 }
 
 int red_qxl_get_command(QXLInstance *qxl, struct QXLCommandExt *cmd)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    return interface->get_command(qxl, cmd);
+    return qxl_interface->get_command(qxl, cmd);
 }
 
 int red_qxl_req_cmd_notification(QXLInstance *qxl)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    return interface->req_cmd_notification(qxl);
+    return qxl_interface->req_cmd_notification(qxl);
 }
 
 void red_qxl_release_resource(QXLInstance *qxl, struct QXLReleaseInfoExt release_info)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    interface->release_resource(qxl, release_info);
+    qxl_interface->release_resource(qxl, release_info);
 }
 
 int red_qxl_get_cursor_command(QXLInstance *qxl, struct QXLCommandExt *cmd)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    return interface->get_cursor_command(qxl, cmd);
+    return qxl_interface->get_cursor_command(qxl, cmd);
 }
 
 int red_qxl_req_cursor_notification(QXLInstance *qxl)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    return interface->req_cursor_notification(qxl);
+    return qxl_interface->req_cursor_notification(qxl);
 }
 
 void red_qxl_notify_update(QXLInstance *qxl, uint32_t update_id)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    interface->notify_update(qxl, update_id);
+    qxl_interface->notify_update(qxl, update_id);
 }
 
 int red_qxl_flush_resources(QXLInstance *qxl)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    return interface->flush_resources(qxl);
+    return qxl_interface->flush_resources(qxl);
 }
 
 void red_qxl_update_area_complete(QXLInstance *qxl, uint32_t surface_id,
                                   struct QXLRect *updated_rects,
                                   uint32_t num_updated_rects)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    interface->update_area_complete(qxl, surface_id, updated_rects, num_updated_rects);
+    qxl_interface->update_area_complete(qxl, surface_id, updated_rects, num_updated_rects);
 }
 
 void red_qxl_set_client_capabilities(QXLInstance *qxl,
                                      uint8_t client_present,
                                      uint8_t caps[SPICE_CAPABILITIES_SIZE])
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
     if (qxl->st->running) {
-        interface->set_client_capabilities(qxl, client_present, caps);
+        qxl_interface->set_client_capabilities(qxl, client_present, caps);
     }
 }
 
 void red_qxl_async_complete(QXLInstance *qxl, uint64_t cookie)
 {
-    QXLInterface *interface = qxl_get_interface(qxl);
+    QXLInterface *qxl_interface = qxl_get_interface(qxl);
 
-    interface->async_complete(qxl, cookie);
+    qxl_interface->async_complete(qxl, cookie);
 }
diff --git a/server/reds.c b/server/reds.c
index 4e990351..3f1a4a05 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1260,9 +1260,9 @@ void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf)
 static void reds_on_main_agent_monitors_config(RedsState *reds,
         MainChannelClient *mcc, const void *message, size_t size)
 {
-    const unsigned int MAX_MONITORS = 256;
+    const unsigned int MAX_NUM_MONITORS = 256;
     const unsigned int MAX_MONITOR_CONFIG_SIZE =
-       sizeof(VDAgentMonitorsConfig) + MAX_MONITORS * sizeof(VDAgentMonConfig);
+       sizeof(VDAgentMonitorsConfig) + MAX_NUM_MONITORS * sizeof(VDAgentMonConfig);
 
     VDAgentMessage *msg_header;
     VDAgentMonitorsConfig *monitors_config;
@@ -3385,12 +3385,12 @@ static int spice_server_char_device_remove_interface(RedsState *reds, SpiceBaseI
 SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
                                                   SpiceBaseInstance *sin)
 {
-    const SpiceBaseInterface *interface = sin->sif;
+    const SpiceBaseInterface *base_interface = sin->sif;
 
-    if (strcmp(interface->type, SPICE_INTERFACE_KEYBOARD) == 0) {
+    if (strcmp(base_interface->type, SPICE_INTERFACE_KEYBOARD) == 0) {
         spice_debug("SPICE_INTERFACE_KEYBOARD");
-        if (interface->major_version != SPICE_INTERFACE_KEYBOARD_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_KEYBOARD_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_KEYBOARD_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_KEYBOARD_MINOR) {
             spice_warning("unsupported keyboard interface");
             return -1;
         }
@@ -3398,10 +3398,10 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
                                         SPICE_UPCAST(SpiceKbdInstance, sin)) != 0) {
             return -1;
         }
-    } else if (strcmp(interface->type, SPICE_INTERFACE_MOUSE) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_MOUSE) == 0) {
         spice_debug("SPICE_INTERFACE_MOUSE");
-        if (interface->major_version != SPICE_INTERFACE_MOUSE_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_MOUSE_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_MOUSE_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_MOUSE_MINOR) {
             spice_warning("unsupported mouse interface");
             return -1;
         }
@@ -3409,12 +3409,12 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
                                      SPICE_UPCAST(SpiceMouseInstance, sin)) != 0) {
             return -1;
         }
-    } else if (strcmp(interface->type, SPICE_INTERFACE_QXL) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_QXL) == 0) {
         QXLInstance *qxl;
 
         spice_debug("SPICE_INTERFACE_QXL");
-        if (interface->major_version != SPICE_INTERFACE_QXL_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_QXL_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_QXL_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_QXL_MINOR) {
             spice_warning("unsupported qxl interface");
             return -1;
         }
@@ -3438,11 +3438,11 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
          * be called. */
         red_qxl_attach_worker(qxl);
         red_qxl_set_compression_level(qxl, calc_compression_level(reds));
-    } else if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_TABLET) == 0) {
         SpiceTabletInstance *tablet = SPICE_UPCAST(SpiceTabletInstance, sin);
         spice_debug("SPICE_INTERFACE_TABLET");
-        if (interface->major_version != SPICE_INTERFACE_TABLET_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_TABLET_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_TABLET_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_TABLET_MINOR) {
             spice_warning("unsupported tablet interface");
             return -1;
         }
@@ -3454,41 +3454,41 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
             inputs_channel_set_tablet_logical_size(reds->inputs_channel, reds->monitor_mode.x_res, reds->monitor_mode.y_res);
         }
 
-    } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
         spice_debug("SPICE_INTERFACE_PLAYBACK");
-        if (interface->major_version != SPICE_INTERFACE_PLAYBACK_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_PLAYBACK_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_PLAYBACK_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_PLAYBACK_MINOR) {
             spice_warning("unsupported playback interface");
             return -1;
         }
         snd_attach_playback(reds, SPICE_UPCAST(SpicePlaybackInstance, sin));
 
-    } else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_RECORD) == 0) {
         spice_debug("SPICE_INTERFACE_RECORD");
-        if (interface->major_version != SPICE_INTERFACE_RECORD_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_RECORD_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_RECORD_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_RECORD_MINOR) {
             spice_warning("unsupported record interface");
             return -1;
         }
         snd_attach_record(reds, SPICE_UPCAST(SpiceRecordInstance, sin));
 
-    } 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) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
+        if (base_interface->major_version != SPICE_INTERFACE_CHAR_DEVICE_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_CHAR_DEVICE_MINOR) {
             spice_warning("unsupported char device interface");
             return -1;
         }
         spice_server_char_device_add_interface(reds, sin);
 
-    } else if (strcmp(interface->type, SPICE_INTERFACE_MIGRATION) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_MIGRATION) == 0) {
         spice_debug("SPICE_INTERFACE_MIGRATION");
         if (reds->migration_interface) {
             spice_warning("already have migration");
             return -1;
         }
 
-        if (interface->major_version != SPICE_INTERFACE_MIGRATION_MAJOR ||
-            interface->minor_version > SPICE_INTERFACE_MIGRATION_MINOR) {
+        if (base_interface->major_version != SPICE_INTERFACE_MIGRATION_MAJOR ||
+            base_interface->minor_version > SPICE_INTERFACE_MIGRATION_MINOR) {
             spice_warning("unsupported migration interface");
             return -1;
         }
@@ -3502,30 +3502,30 @@ SPICE_GNUC_VISIBLE int spice_server_add_interface(SpiceServer *reds,
 SPICE_GNUC_VISIBLE int spice_server_remove_interface(SpiceBaseInstance *sin)
 {
     RedsState *reds;
-    const SpiceBaseInterface *interface;
+    const SpiceBaseInterface *base_interface;
 
     g_return_val_if_fail(sin != NULL, -1);
 
-    interface = sin->sif;
-    if (strcmp(interface->type, SPICE_INTERFACE_TABLET) == 0) {
+    base_interface = sin->sif;
+    if (strcmp(base_interface->type, SPICE_INTERFACE_TABLET) == 0) {
         SpiceTabletInstance *tablet = SPICE_UPCAST(SpiceTabletInstance, sin);
         g_return_val_if_fail(tablet->st != NULL, -1);
         reds = spice_tablet_state_get_server(tablet->st);
         spice_debug("remove SPICE_INTERFACE_TABLET");
         inputs_channel_detach_tablet(reds->inputs_channel, tablet);
         reds_update_mouse_mode(reds);
-    } else if (strcmp(interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_PLAYBACK) == 0) {
         spice_debug("remove SPICE_INTERFACE_PLAYBACK");
         snd_detach_playback(SPICE_UPCAST(SpicePlaybackInstance, sin));
-    } else if (strcmp(interface->type, SPICE_INTERFACE_RECORD) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_RECORD) == 0) {
         spice_debug("remove SPICE_INTERFACE_RECORD");
         snd_detach_record(SPICE_UPCAST(SpiceRecordInstance, sin));
-    } else if (strcmp(interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_CHAR_DEVICE) == 0) {
         SpiceCharDeviceInstance *char_device = SPICE_UPCAST(SpiceCharDeviceInstance, sin);
         g_return_val_if_fail(char_device->st != NULL, -1);
         reds = red_char_device_get_server(char_device->st);
         return spice_server_char_device_remove_interface(reds, sin);
-    } else if (strcmp(interface->type, SPICE_INTERFACE_QXL) == 0) {
+    } else if (strcmp(base_interface->type, SPICE_INTERFACE_QXL) == 0) {
         QXLInstance *qxl;
 
         qxl = SPICE_UPCAST(QXLInstance, sin);
commit 992226d6f2295573435295d902a5f8bedf8a47d8
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Jun 20 14:23:44 2018 +0100

    Avoids %m in formatting for Windows
    
    Not supported, %m is a GNU extension of sscanf.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/server/reds.c b/server/reds.c
index 5a553878..4e990351 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -3739,8 +3739,7 @@ static const int video_codec_caps[] = {
  * @codec: a location to return the parsed codec
  * @return the position of the next codec in the string
  */
-static const char* parse_next_video_codec(const char *codecs, char **encoder,
-                                          char **codec)
+static char* parse_next_video_codec(char *codecs, char **encoder, char **codec)
 {
     if (!codecs) {
         return NULL;
@@ -3749,14 +3748,15 @@ static const char* parse_next_video_codec(const char *codecs, char **encoder,
     if (!*codecs) {
         return NULL;
     }
-    int n;
+    int end_encoder, end_codec = -1;
     *encoder = *codec = NULL;
-    if (sscanf(codecs, "%m[0-9a-zA-Z_]:%m[0-9a-zA-Z_]%n", encoder, codec, &n) == 2) {
-        // this avoids accepting "encoder:codec" followed by garbage like "$%*"
-        if (codecs[n] != ';' && codecs[n] != '\0') {
-            free(*codec);
-            *codec = NULL;
-        }
+    if (sscanf(codecs, "%*[0-9a-zA-Z_]:%n%*[0-9a-zA-Z_];%n", &end_encoder, &end_codec) == 0
+        && end_codec > 0) {
+        codecs[end_encoder - 1] = '\0';
+        codecs[end_codec - 1] = '\0';
+        *encoder = codecs;
+        *codec = codecs + end_encoder;
+        return codecs + end_codec;
     }
     return codecs + strcspn(codecs, ";");
 }
@@ -3773,7 +3773,8 @@ static void reds_set_video_codecs_from_string(RedsState *reds, const char *codec
     }
 
     video_codecs = g_array_new(FALSE, FALSE, sizeof(RedVideoCodec));
-    const char *c = codecs;
+    char *codecs_copy = g_strdup_printf("%s;", codecs);
+    char *c = codecs_copy;
     while ( (c = parse_next_video_codec(c, &encoder_name, &codec_name)) ) {
         uint32_t encoder_index, codec_index;
         if (!encoder_name || !codec_name) {
@@ -3796,19 +3797,17 @@ static void reds_set_video_codecs_from_string(RedsState *reds, const char *codec
             g_array_append_val(video_codecs, new_codec);
         }
 
-        /* these are allocated by sscanf, do not use g_free */
-        free(encoder_name);
-        free(codec_name);
         codecs = c;
     }
 
     if (video_codecs->len == 0) {
         spice_warning("Failed to set video codecs, input string: '%s'", codecs);
         g_array_unref(video_codecs);
-        return;
+    } else {
+        reds_set_video_codecs(reds, video_codecs);
     }
 
-    reds_set_video_codecs(reds, video_codecs);
+    g_free(codecs_copy);
 }
 
 SPICE_GNUC_VISIBLE int spice_server_init(SpiceServer *reds, SpiceCoreInterface *core)
commit 0643d6755720755d7a8471cae9d73ec840c6da88
Author: Frediano Ziglio <fziglio at redhat.com>
Date:   Wed Jun 20 14:23:44 2018 +0100

    build: Detect Windows build and change some definitions
    
    Windows needs some specific setting to use network.
    
    Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
    Acked-by: Victor Toso <victortoso at redhat.com>

diff --git a/configure.ac b/configure.ac
index 1ce81f91..8bcb22ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,6 +68,20 @@ case $host_cpu in
         SPICE_WARNING([spice-server on non-x86_64 architectures has not been extensively tested])
 esac
 
+AC_MSG_CHECKING([for native Win32])
+case "$host_os" in
+     *mingw*|*cygwin*)
+        os_win32=yes
+        dnl AI_ADDRCONFIG and possibly some other code require at least Vista
+        AC_DEFINE([_WIN32_WINNT], [0x600], [Minimal Win32 version])
+        ;;
+     *)
+        os_win32=no
+        ;;
+esac
+AC_MSG_RESULT([$os_win32])
+AM_CONDITIONAL([OS_WIN32],[test "$os_win32" = "yes"])
+
 dnl =========================================================================
 dnl Check optional features
 SPICE_CHECK_SMARTCARD
@@ -154,6 +168,9 @@ AC_CHECK_LIB(rt, clock_gettime, LIBRT="-lrt")
 AC_SUBST(LIBRT)
 
 AS_VAR_APPEND([SPICE_NONPKGCONFIG_LIBS], [" -pthread $LIBM $LIBRT"])
+AS_IF([test "x$os_win32" = "xyes"], [
+    AS_VAR_APPEND([SPICE_NONPKGCONFIG_LIBS], [" -lws2_32"])
+])
 
 SPICE_REQUIRES=""
 
@@ -176,7 +193,8 @@ PKG_CHECK_MODULES([GOBJECT2], [gobject-2.0 >= $GLIB2_REQUIRED])
 AS_VAR_APPEND([SPICE_REQUIRES], [" gobject-2.0 >= $GLIB2_REQUIRED"])
 
 #used only by tests
-PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0 >= $GLIB2_REQUIRED])
+AS_IF([test "x$os_win32" != "xyes"],
+      PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0 >= $GLIB2_REQUIRED]))
 
 PIXMAN_REQUIRED=0.17.7
 PKG_CHECK_MODULES(PIXMAN, pixman-1 >= $PIXMAN_REQUIRED)
diff --git a/meson.build b/meson.build
index 93fbdfff..8b8ae8bb 100644
--- a/meson.build
+++ b/meson.build
@@ -102,9 +102,13 @@ foreach dep : ['libjpeg', 'zlib']
   spice_server_deps += dependency(dep)
 endforeach
 
-foreach dep : ['librt', 'libm']
-  spice_server_deps += compiler.find_library(dep)
-endforeach
+if host_machine.system() != 'windows'
+  foreach dep : ['librt', 'libm']
+    spice_server_deps += compiler.find_library(dep)
+  endforeach
+else
+  spice_server_deps += compiler.find_library('ws2_32')
+endif
 
 #
 # Non-mandatory/optional dependencies
@@ -201,6 +205,11 @@ if get_option('statistics')
   spice_server_config_data.set('RED_STATISTICS', '1')
 endif
 
+# Minimal Win32 version
+if host_machine.system() == 'windows'
+  spice_server_config_data.set('_WIN32_WINNT', '0x600')
+endif
+
 configure_file(output : 'config.h',
                install : false,
                configuration : spice_server_config_data)
diff --git a/server/tests/meson.build b/server/tests/meson.build
index b79b1108..20548213 100644
--- a/server/tests/meson.build
+++ b/server/tests/meson.build
@@ -1,5 +1,8 @@
 test_lib_include = [spice_server_include, include_directories('.')]
-test_lib_deps = [spice_server_deps, dependency('gio-unix-2.0')]
+test_lib_deps = [spice_server_deps]
+if host_machine.system() != 'windows'
+  test_lib_deps += [dependency('gio-unix-2.0')]
+endif
 
 test_lib_sources = [
   'basic-event-loop.c',


More information about the Spice-commits mailing list