[Spice-devel,1/2] vdagent: Allow disabling the server-side udscs support

Submitted by Francois Gouget on Nov. 5, 2015, 6:21 p.m.

Details

Message ID alpine.DEB.2.20.1511051921080.5152@amboise
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Spice

Not browsing as part of any series.

Commit Message

Francois Gouget Nov. 5, 2015, 6:21 p.m.
To do so define UDSCS_NO_SERVER.
This simplifies reuse in client-only scenarios that don't need peer
credential support for instance.
The patch also reorders the client and server code so the
implementation is not peppered with #ifdefs.

Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
---
 src/udscs.c | 486 ++++++++++++++++++++++++++++++------------------------------
 src/udscs.h | 128 +++++++++-------
 2 files changed, 321 insertions(+), 293 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/udscs.c b/src/udscs.c
index 288aca2..334d54a 100644
--- a/src/udscs.c
+++ b/src/udscs.c
@@ -46,8 +46,10 @@  struct udscs_connection {
     const char * const *type_to_string;
     int no_types;
     int debug;
-    struct ucred peer_cred;
     void *user_data;
+#ifndef UDSCS_NO_SERVER
+    struct ucred peer_cred;
+#endif
 
     /* Read stuff, single buffer, separate header and data buffer */
     int header_read;
@@ -66,86 +68,6 @@  struct udscs_connection {
     struct udscs_connection *prev;
 };
 
-struct udscs_server {
-    int fd;
-    const char * const *type_to_string;
-    int no_types;
-    int debug;
-    struct udscs_connection connections_head;
-    udscs_connect_callback connect_callback;
-    udscs_read_callback read_callback;
-    udscs_disconnect_callback disconnect_callback;
-};
-
-static void udscs_do_write(struct udscs_connection **connp);
-static void udscs_do_read(struct udscs_connection **connp);
-
-
-struct udscs_server *udscs_create_server(const char *socketname,
-    udscs_connect_callback connect_callback,
-    udscs_read_callback read_callback,
-    udscs_disconnect_callback disconnect_callback,
-    const char * const type_to_string[], int no_types, int debug)
-{
-    int c;
-    struct sockaddr_un address;
-    struct udscs_server *server;
-
-    server = calloc(1, sizeof(*server));
-    if (!server)
-        return NULL;
-
-    server->type_to_string = type_to_string;
-    server->no_types = no_types;
-    server->debug = debug;
-
-    server->fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (server->fd == -1) {
-        syslog(LOG_ERR, "creating unix domain socket: %m");
-        free(server);
-        return NULL;
-    }
-
-    address.sun_family = AF_UNIX;
-    snprintf(address.sun_path, sizeof(address.sun_path), "%s", socketname);
-    c = bind(server->fd, (struct sockaddr *)&address, sizeof(address));
-    if (c != 0) {
-        syslog(LOG_ERR, "bind %s: %m", socketname);
-        free(server);
-        return NULL;
-    }
-
-    c = listen(server->fd, 5);
-    if (c != 0) {
-        syslog(LOG_ERR, "listen: %m");
-        free(server);
-        return NULL;
-    }
-
-    server->connect_callback = connect_callback;
-    server->read_callback = read_callback;
-    server->disconnect_callback = disconnect_callback;
-
-    return server;
-}
-
-void udscs_destroy_server(struct udscs_server *server)
-{
-    struct udscs_connection *conn, *next_conn;
-
-    if (!server)
-        return;
-
-    conn = server->connections_head.next;
-    while (conn) {
-        next_conn = conn->next;
-        udscs_destroy_connection(&conn);
-        conn = next_conn;
-    }
-    close(server->fd);
-    free(server);
-}
-
 struct udscs_connection *udscs_connect(const char *socketname,
     udscs_read_callback read_callback,
     udscs_disconnect_callback disconnect_callback,
@@ -225,131 +147,17 @@  void udscs_destroy_connection(struct udscs_connection **connp)
     *connp = NULL;
 }
 
-struct ucred udscs_get_peer_cred(struct udscs_connection *conn)
-{
-    return conn->peer_cred;
-}
-
-int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
-        fd_set *writefds)
+void udscs_set_user_data(struct udscs_connection *conn, void *data)
 {
-    struct udscs_connection *conn;
-    int nfds = server->fd + 1;
-
-    if (!server)
-        return -1;
-
-    FD_SET(server->fd, readfds);
-
-    conn = server->connections_head.next;
-    while (conn) {
-        int conn_nfds = udscs_client_fill_fds(conn, readfds, writefds);
-        if (conn_nfds > nfds)
-            nfds = conn_nfds;
-
-        conn = conn->next;
-    }
-
-    return nfds;
+    conn->user_data = data;
 }
 
-int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
-        fd_set *writefds)
+void *udscs_get_user_data(struct udscs_connection *conn)
 {
     if (!conn)
-        return -1;
-
-    FD_SET(conn->fd, readfds);
-    if (conn->write_buf)
-        FD_SET(conn->fd, writefds);
-
-    return conn->fd + 1;
-}
-
-static void udscs_server_accept(struct udscs_server *server) {
-    struct udscs_connection *new_conn, *conn;
-    struct sockaddr_un address;
-    socklen_t length = sizeof(address);
-    int r, fd;
-
-    fd = accept(server->fd, (struct sockaddr *)&address, &length);
-    if (fd == -1) {
-        if (errno == EINTR)
-            return;
-        syslog(LOG_ERR, "accept: %m");
-        return;
-    }
-
-    new_conn = calloc(1, sizeof(*conn));
-    if (!new_conn) {
-        syslog(LOG_ERR, "out of memory, disconnecting new client");
-        close(fd);
-        return;
-    }
-
-    new_conn->fd = fd;
-    new_conn->type_to_string = server->type_to_string;
-    new_conn->no_types = server->no_types;
-    new_conn->debug = server->debug;
-    new_conn->read_callback = server->read_callback;
-    new_conn->disconnect_callback = server->disconnect_callback;
-
-    length = sizeof(new_conn->peer_cred);
-    r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &new_conn->peer_cred, &length);
-    if (r != 0) {
-        syslog(LOG_ERR, "Could not get peercred, disconnecting new client");
-        close(fd);
-        free(new_conn);
-        return;
-    }
-
-    conn = &server->connections_head;
-    while (conn->next)
-        conn = conn->next;
-
-    new_conn->prev = conn;
-    conn->next = new_conn;
-
-    if (server->debug)
-        syslog(LOG_DEBUG, "new client accepted: %p, pid: %d",
-               new_conn, (int)new_conn->peer_cred.pid);
-
-    if (server->connect_callback)
-        server->connect_callback(new_conn);
-}
-
-void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
-        fd_set *writefds)
-{
-    struct udscs_connection *conn, *next_conn;
-
-    if (!server)
-        return;
-
-    if (FD_ISSET(server->fd, readfds))
-        udscs_server_accept(server);
-
-    conn = server->connections_head.next;
-    while (conn) {
-        /* conn maybe destroyed by udscs_client_handle_fds (when disconnected),
-           so get the next connection first. */
-        next_conn = conn->next;
-        udscs_client_handle_fds(&conn, readfds, writefds);
-        conn = next_conn;
-    }
-}
-
-void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
-        fd_set *writefds)
-{
-    if (!*connp)
-        return;
-
-    if (FD_ISSET((*connp)->fd, readfds))
-        udscs_do_read(connp);
+        return NULL;
 
-    if (*connp && FD_ISSET((*connp)->fd, writefds))
-        udscs_do_write(connp);
+    return conn->user_data;
 }
 
 int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
@@ -404,41 +212,7 @@  int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
     return 0;
 }
 
-int udscs_server_write_all(struct udscs_server *server,
-        uint32_t type, uint32_t arg1, uint32_t arg2,
-        const uint8_t *data, uint32_t size)
-{
-    struct udscs_connection *conn;
-
-    conn = server->connections_head.next;
-    while (conn) {
-        if (udscs_write(conn, type, arg1, arg2, data, size))
-            return -1;
-        conn = conn->next;
-    }
-
-    return 0;
-}
-
-int udscs_server_for_all_clients(struct udscs_server *server,
-    udscs_for_all_clients_callback func, void *priv)
-{
-    int r = 0;
-    struct udscs_connection *conn, *next_conn;
-
-    if (!server)
-        return 0;
-
-    conn = server->connections_head.next;
-    while (conn) {
-        /* Get next conn as func may destroy the current conn */
-        next_conn = conn->next;
-        r += func(&conn, priv);
-        conn = next_conn;
-    }
-    return r;
-}
-
+/* A helper for udscs_do_read() */
 static void udscs_read_complete(struct udscs_connection **connp)
 {
     struct udscs_connection *conn = *connp;
@@ -466,6 +240,7 @@  static void udscs_read_complete(struct udscs_connection **connp)
     memset(&conn->data, 0, sizeof(conn->data));
 }
 
+/* A helper for udscs_client_handle_fds() */
 static void udscs_do_read(struct udscs_connection **connp)
 {
     ssize_t n;
@@ -516,6 +291,7 @@  static void udscs_do_read(struct udscs_connection **connp)
     }
 }
 
+/* A helper for udscs_client_handle_fds() */
 static void udscs_do_write(struct udscs_connection **connp)
 {
     ssize_t n;
@@ -549,15 +325,247 @@  static void udscs_do_write(struct udscs_connection **connp)
     }
 }
 
-void udscs_set_user_data(struct udscs_connection *conn, void *data)
+void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
+        fd_set *writefds)
 {
-    conn->user_data = data;
+    if (!*connp)
+        return;
+
+    if (FD_ISSET((*connp)->fd, readfds))
+        udscs_do_read(connp);
+
+    if (*connp && FD_ISSET((*connp)->fd, writefds))
+        udscs_do_write(connp);
 }
 
-void *udscs_get_user_data(struct udscs_connection *conn)
+int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
+        fd_set *writefds)
 {
     if (!conn)
+        return -1;
+
+    FD_SET(conn->fd, readfds);
+    if (conn->write_buf)
+        FD_SET(conn->fd, writefds);
+
+    return conn->fd + 1;
+}
+
+
+#ifndef UDSCS_NO_SERVER
+
+/* ---------- Server-side implementation ---------- */
+
+struct udscs_server {
+    int fd;
+    const char * const *type_to_string;
+    int no_types;
+    int debug;
+    struct udscs_connection connections_head;
+    udscs_connect_callback connect_callback;
+    udscs_read_callback read_callback;
+    udscs_disconnect_callback disconnect_callback;
+};
+
+struct udscs_server *udscs_create_server(const char *socketname,
+    udscs_connect_callback connect_callback,
+    udscs_read_callback read_callback,
+    udscs_disconnect_callback disconnect_callback,
+    const char * const type_to_string[], int no_types, int debug)
+{
+    int c;
+    struct sockaddr_un address;
+    struct udscs_server *server;
+
+    server = calloc(1, sizeof(*server));
+    if (!server)
         return NULL;
 
-    return conn->user_data;
+    server->type_to_string = type_to_string;
+    server->no_types = no_types;
+    server->debug = debug;
+
+    server->fd = socket(PF_UNIX, SOCK_STREAM, 0);
+    if (server->fd == -1) {
+        syslog(LOG_ERR, "creating unix domain socket: %m");
+        free(server);
+        return NULL;
+    }
+
+    address.sun_family = AF_UNIX;
+    snprintf(address.sun_path, sizeof(address.sun_path), "%s", socketname);
+    c = bind(server->fd, (struct sockaddr *)&address, sizeof(address));
+    if (c != 0) {
+        syslog(LOG_ERR, "bind %s: %m", socketname);
+        free(server);
+        return NULL;
+    }
+
+    c = listen(server->fd, 5);
+    if (c != 0) {
+        syslog(LOG_ERR, "listen: %m");
+        free(server);
+        return NULL;
+    }
+
+    server->connect_callback = connect_callback;
+    server->read_callback = read_callback;
+    server->disconnect_callback = disconnect_callback;
+
+    return server;
+}
+
+void udscs_destroy_server(struct udscs_server *server)
+{
+    struct udscs_connection *conn, *next_conn;
+
+    if (!server)
+        return;
+
+    conn = server->connections_head.next;
+    while (conn) {
+        next_conn = conn->next;
+        udscs_destroy_connection(&conn);
+        conn = next_conn;
+    }
+    close(server->fd);
+    free(server);
+}
+
+struct ucred udscs_get_peer_cred(struct udscs_connection *conn)
+{
+    return conn->peer_cred;
 }
+
+static void udscs_server_accept(struct udscs_server *server) {
+    struct udscs_connection *new_conn, *conn;
+    struct sockaddr_un address;
+    socklen_t length = sizeof(address);
+    int r, fd;
+
+    fd = accept(server->fd, (struct sockaddr *)&address, &length);
+    if (fd == -1) {
+        if (errno == EINTR)
+            return;
+        syslog(LOG_ERR, "accept: %m");
+        return;
+    }
+
+    new_conn = calloc(1, sizeof(*conn));
+    if (!new_conn) {
+        syslog(LOG_ERR, "out of memory, disconnecting new client");
+        close(fd);
+        return;
+    }
+
+    new_conn->fd = fd;
+    new_conn->type_to_string = server->type_to_string;
+    new_conn->no_types = server->no_types;
+    new_conn->debug = server->debug;
+    new_conn->read_callback = server->read_callback;
+    new_conn->disconnect_callback = server->disconnect_callback;
+
+    length = sizeof(new_conn->peer_cred);
+    r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &new_conn->peer_cred, &length);
+    if (r != 0) {
+        syslog(LOG_ERR, "Could not get peercred, disconnecting new client");
+        close(fd);
+        free(new_conn);
+        return;
+    }
+
+    conn = &server->connections_head;
+    while (conn->next)
+        conn = conn->next;
+
+    new_conn->prev = conn;
+    conn->next = new_conn;
+
+    if (server->debug)
+        syslog(LOG_DEBUG, "new client accepted: %p, pid: %d",
+               new_conn, (int)new_conn->peer_cred.pid);
+
+    if (server->connect_callback)
+        server->connect_callback(new_conn);
+}
+
+int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
+        fd_set *writefds)
+{
+    struct udscs_connection *conn;
+    int nfds = server->fd + 1;
+
+    if (!server)
+        return -1;
+
+    FD_SET(server->fd, readfds);
+
+    conn = server->connections_head.next;
+    while (conn) {
+        int conn_nfds = udscs_client_fill_fds(conn, readfds, writefds);
+        if (conn_nfds > nfds)
+            nfds = conn_nfds;
+
+        conn = conn->next;
+    }
+
+    return nfds;
+}
+
+void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
+        fd_set *writefds)
+{
+    struct udscs_connection *conn, *next_conn;
+
+    if (!server)
+        return;
+
+    if (FD_ISSET(server->fd, readfds))
+        udscs_server_accept(server);
+
+    conn = server->connections_head.next;
+    while (conn) {
+        /* conn maybe destroyed by udscs_client_handle_fds (when disconnected),
+           so get the next connection first. */
+        next_conn = conn->next;
+        udscs_client_handle_fds(&conn, readfds, writefds);
+        conn = next_conn;
+    }
+}
+
+int udscs_server_write_all(struct udscs_server *server,
+        uint32_t type, uint32_t arg1, uint32_t arg2,
+        const uint8_t *data, uint32_t size)
+{
+    struct udscs_connection *conn;
+
+    conn = server->connections_head.next;
+    while (conn) {
+        if (udscs_write(conn, type, arg1, arg2, data, size))
+            return -1;
+        conn = conn->next;
+    }
+
+    return 0;
+}
+
+int udscs_server_for_all_clients(struct udscs_server *server,
+    udscs_for_all_clients_callback func, void *priv)
+{
+    int r = 0;
+    struct udscs_connection *conn, *next_conn;
+
+    if (!server)
+        return 0;
+
+    conn = server->connections_head.next;
+    while (conn) {
+        /* Get next conn as func may destroy the current conn */
+        next_conn = conn->next;
+        r += func(&conn, priv);
+        conn = next_conn;
+    }
+    return r;
+}
+
+#endif
diff --git a/src/udscs.h b/src/udscs.h
index 89ab617..8b0b14e 100644
--- a/src/udscs.h
+++ b/src/udscs.h
@@ -27,8 +27,10 @@ 
 #include <sys/select.h>
 #include <sys/socket.h>
 
+
+/* ---------- Generic bits and client-side API ---------- */
+
 struct udscs_connection;
-struct udscs_server;
 struct udscs_message_header {
     uint32_t type;
     uint32_t arg1;
@@ -36,89 +38,107 @@  struct udscs_message_header {
     uint32_t size;  
 };
 
-/* Callbacks with this type will be called when a new connection to a
-   server is accepted. */
-typedef void (*udscs_connect_callback)(struct udscs_connection *conn);
 /* Callbacks with this type will be called when a complete message has been
-   received. The callback may call udscs_destroy_connection, in which case
-   *connp must be made NULL (which udscs_destroy_connection takes care of) */
+ * received. The callback may call udscs_destroy_connection, in which case
+ * *connp must be made NULL (which udscs_destroy_connection takes care of).
+ */
 typedef void (*udscs_read_callback)(struct udscs_connection **connp,
     struct udscs_message_header *header, uint8_t *data);
-/* Callback type for udscs_server_for_all_clients. Clients can be disconnected
-   from this callback just like with a read callback. */
-typedef int (*udscs_for_all_clients_callback)(struct udscs_connection **connp,
-    void *priv);
+
 /* Callbacks with this type will be called when the connection is disconnected.
-   Note:
-   1) udscs will destroy the connection in question itself after
-      this callback has completed!
-   2) This callback is always called, even if the disconnect is initiated
-      by the udscs user through returning -1 from a read callback, or
-      by explictly calling udscs_destroy_connection */
+ * Note:
+ * 1) udscs will destroy the connection in question itself after
+ *    this callback has completed!
+ * 2) This callback is always called, even if the disconnect is initiated
+ *    by the udscs user through returning -1 from a read callback, or
+ *    by explictly calling udscs_destroy_connection.
+ */
 typedef void (*udscs_disconnect_callback)(struct udscs_connection *conn);
 
-/* Create a unix domain socket named name and start listening on it. */
-struct udscs_server *udscs_create_server(const char *socketname,
-    udscs_connect_callback connect_callback,
-    udscs_read_callback read_callback,
-    udscs_disconnect_callback disconnect_callback,
-    const char * const type_to_string[], int no_types, int debug);
-
-void udscs_destroy_server(struct udscs_server *server);
-
 /* Connect to a unix domain socket named name. */
 struct udscs_connection *udscs_connect(const char *socketname,
     udscs_read_callback read_callback,
     udscs_disconnect_callback disconnect_callback,
     const char * const type_to_string[], int no_types, int debug);
 
-/* The contents of connp will be made NULL */
+/* The contents of connp will be made NULL. */
 void udscs_destroy_connection(struct udscs_connection **connp);
 
-
-/* Given an udscs server or client fill the fd_sets pointed to by readfds and
-   writefds for select() usage.
-
-   Return value: value of the highest fd + 1 */
-int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
-        fd_set *writefds);
-
 int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
-        fd_set *writefds);
-
-/* Handle any events flagged by select for the given udscs server or client. */
-void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
-        fd_set *writefds);
+    fd_set *writefds);
 
 /* Note the connection may be destroyed (when disconnected) by this call
-   in this case the disconnect calllback will get called before the
-   destruction and the contents of connp will be made NULL */
+ * in this case the disconnect calllback will get called before the
+ * destruction and the contents of connp will be made NULL.
+ */
 void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
-        fd_set *writefds);
-
+    fd_set *writefds);
 
 /* Queue a message for delivery to the client connected through conn.
-
-   Returns 0 on success -1 on error (only happens when malloc fails) */
+ * Returns 0 on success -1 on error (only happens when malloc fails).
+ */
 int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
         uint32_t arg2, const uint8_t *data, uint32_t size);
 
+/* To associate per connection data with a connection. */
+void udscs_set_user_data(struct udscs_connection *conn, void *data);
+void *udscs_get_user_data(struct udscs_connection *conn);
+
+
+#ifndef UDSCS_NO_SERVER
+
+/* ---------- Server-side API ---------- */
+
+struct udscs_server;
+
+/* Callbacks with this type will be called when a new connection to a
+ * server is accepted.
+ */
+typedef void (*udscs_connect_callback)(struct udscs_connection *conn);
+
+/* Create a unix domain socket named name and start listening on it. */
+struct udscs_server *udscs_create_server(const char *socketname,
+    udscs_connect_callback connect_callback,
+    udscs_read_callback read_callback,
+    udscs_disconnect_callback disconnect_callback,
+    const char * const type_to_string[], int no_types, int debug);
+
+void udscs_destroy_server(struct udscs_server *server);
+
 /* Like udscs_write, but then send the message to all clients connected to
-   the server */
+ * the server.
+ */
 int udscs_server_write_all(struct udscs_server *server,
-        uint32_t type, uint32_t arg1, uint32_t arg2,
-        const uint8_t *data, uint32_t size);
+    uint32_t type, uint32_t arg1, uint32_t arg2,
+    const uint8_t *data, uint32_t size);
+
+/* Callback type for udscs_server_for_all_clients. Clients can be disconnected
+ * from this callback just like with a read callback.
+ */
+typedef int (*udscs_for_all_clients_callback)(struct udscs_connection **connp,
+    void *priv);
+
 /* Call func for all clients connected to the server, passing through
-   priv to all func calls. Returns the total of the return values from all
-   calls to func */
+ * priv to all func calls. Returns the total of the return values from all
+ * calls to func.
+ */
 int udscs_server_for_all_clients(struct udscs_server *server,
-        udscs_for_all_clients_callback func, void *priv);
+    udscs_for_all_clients_callback func, void *priv);
 
+/* Given an udscs server or client fill the fd_sets pointed to by readfds and
+ * writefds for select() usage.
+ * Return value: value of the highest fd + 1
+ */
+int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
+    fd_set *writefds);
+
+/* Handle any events flagged by select for the given udscs server or client. */
+void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
+    fd_set *writefds);
 
+/* Returns the peer's user credentials. */
 struct ucred udscs_get_peer_cred(struct udscs_connection *conn);
 
-/* For server use, to associate per connection data with a connection */
-void udscs_set_user_data(struct udscs_connection *conn, void *data);
-void *udscs_get_user_data(struct udscs_connection *conn);
+#endif
 
 #endif

Comments

Hi,

On Thu, Nov 05, 2015 at 07:21:38PM +0100, Francois Gouget wrote:
> To do so define UDSCS_NO_SERVER.
> This simplifies reuse in client-only scenarios that don't need peer
> credential support for instance.
> The patch also reorders the client and server code so the
> implementation is not peppered with #ifdefs.

The problem with reordering the code is that it can affect git blame
(which I like using) when understanding code. Now, udscs.c has only 4
commits so I don't think it is a big issue in this case.

Would you mind doing the reordering in one patch and using and defining
UDSCS_NO_SERVER in other patch?

Also, did you send this with git-send-email? It does not seem proper
threaded in patchwork.freedesktop.org/project/Spice neither in mailman.

Best,
  Victor Toso

>
> Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
> ---
>  src/udscs.c | 486 ++++++++++++++++++++++++++++++------------------------------
>  src/udscs.h | 128 +++++++++-------
>  2 files changed, 321 insertions(+), 293 deletions(-)
> 
> diff --git a/src/udscs.c b/src/udscs.c
> index 288aca2..334d54a 100644
> --- a/src/udscs.c
> +++ b/src/udscs.c
> @@ -46,8 +46,10 @@ struct udscs_connection {
>      const char * const *type_to_string;
>      int no_types;
>      int debug;
> -    struct ucred peer_cred;
>      void *user_data;
> +#ifndef UDSCS_NO_SERVER
> +    struct ucred peer_cred;
> +#endif
>  
>      /* Read stuff, single buffer, separate header and data buffer */
>      int header_read;
> @@ -66,86 +68,6 @@ struct udscs_connection {
>      struct udscs_connection *prev;
>  };
>  
> -struct udscs_server {
> -    int fd;
> -    const char * const *type_to_string;
> -    int no_types;
> -    int debug;
> -    struct udscs_connection connections_head;
> -    udscs_connect_callback connect_callback;
> -    udscs_read_callback read_callback;
> -    udscs_disconnect_callback disconnect_callback;
> -};
> -
> -static void udscs_do_write(struct udscs_connection **connp);
> -static void udscs_do_read(struct udscs_connection **connp);
> -
> -
> -struct udscs_server *udscs_create_server(const char *socketname,
> -    udscs_connect_callback connect_callback,
> -    udscs_read_callback read_callback,
> -    udscs_disconnect_callback disconnect_callback,
> -    const char * const type_to_string[], int no_types, int debug)
> -{
> -    int c;
> -    struct sockaddr_un address;
> -    struct udscs_server *server;
> -
> -    server = calloc(1, sizeof(*server));
> -    if (!server)
> -        return NULL;
> -
> -    server->type_to_string = type_to_string;
> -    server->no_types = no_types;
> -    server->debug = debug;
> -
> -    server->fd = socket(PF_UNIX, SOCK_STREAM, 0);
> -    if (server->fd == -1) {
> -        syslog(LOG_ERR, "creating unix domain socket: %m");
> -        free(server);
> -        return NULL;
> -    }
> -
> -    address.sun_family = AF_UNIX;
> -    snprintf(address.sun_path, sizeof(address.sun_path), "%s", socketname);
> -    c = bind(server->fd, (struct sockaddr *)&address, sizeof(address));
> -    if (c != 0) {
> -        syslog(LOG_ERR, "bind %s: %m", socketname);
> -        free(server);
> -        return NULL;
> -    }
> -
> -    c = listen(server->fd, 5);
> -    if (c != 0) {
> -        syslog(LOG_ERR, "listen: %m");
> -        free(server);
> -        return NULL;
> -    }
> -
> -    server->connect_callback = connect_callback;
> -    server->read_callback = read_callback;
> -    server->disconnect_callback = disconnect_callback;
> -
> -    return server;
> -}
> -
> -void udscs_destroy_server(struct udscs_server *server)
> -{
> -    struct udscs_connection *conn, *next_conn;
> -
> -    if (!server)
> -        return;
> -
> -    conn = server->connections_head.next;
> -    while (conn) {
> -        next_conn = conn->next;
> -        udscs_destroy_connection(&conn);
> -        conn = next_conn;
> -    }
> -    close(server->fd);
> -    free(server);
> -}
> -
>  struct udscs_connection *udscs_connect(const char *socketname,
>      udscs_read_callback read_callback,
>      udscs_disconnect_callback disconnect_callback,
> @@ -225,131 +147,17 @@ void udscs_destroy_connection(struct udscs_connection **connp)
>      *connp = NULL;
>  }
>  
> -struct ucred udscs_get_peer_cred(struct udscs_connection *conn)
> -{
> -    return conn->peer_cred;
> -}
> -
> -int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
> -        fd_set *writefds)
> +void udscs_set_user_data(struct udscs_connection *conn, void *data)
>  {
> -    struct udscs_connection *conn;
> -    int nfds = server->fd + 1;
> -
> -    if (!server)
> -        return -1;
> -
> -    FD_SET(server->fd, readfds);
> -
> -    conn = server->connections_head.next;
> -    while (conn) {
> -        int conn_nfds = udscs_client_fill_fds(conn, readfds, writefds);
> -        if (conn_nfds > nfds)
> -            nfds = conn_nfds;
> -
> -        conn = conn->next;
> -    }
> -
> -    return nfds;
> +    conn->user_data = data;
>  }
>  
> -int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
> -        fd_set *writefds)
> +void *udscs_get_user_data(struct udscs_connection *conn)
>  {
>      if (!conn)
> -        return -1;
> -
> -    FD_SET(conn->fd, readfds);
> -    if (conn->write_buf)
> -        FD_SET(conn->fd, writefds);
> -
> -    return conn->fd + 1;
> -}
> -
> -static void udscs_server_accept(struct udscs_server *server) {
> -    struct udscs_connection *new_conn, *conn;
> -    struct sockaddr_un address;
> -    socklen_t length = sizeof(address);
> -    int r, fd;
> -
> -    fd = accept(server->fd, (struct sockaddr *)&address, &length);
> -    if (fd == -1) {
> -        if (errno == EINTR)
> -            return;
> -        syslog(LOG_ERR, "accept: %m");
> -        return;
> -    }
> -
> -    new_conn = calloc(1, sizeof(*conn));
> -    if (!new_conn) {
> -        syslog(LOG_ERR, "out of memory, disconnecting new client");
> -        close(fd);
> -        return;
> -    }
> -
> -    new_conn->fd = fd;
> -    new_conn->type_to_string = server->type_to_string;
> -    new_conn->no_types = server->no_types;
> -    new_conn->debug = server->debug;
> -    new_conn->read_callback = server->read_callback;
> -    new_conn->disconnect_callback = server->disconnect_callback;
> -
> -    length = sizeof(new_conn->peer_cred);
> -    r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &new_conn->peer_cred, &length);
> -    if (r != 0) {
> -        syslog(LOG_ERR, "Could not get peercred, disconnecting new client");
> -        close(fd);
> -        free(new_conn);
> -        return;
> -    }
> -
> -    conn = &server->connections_head;
> -    while (conn->next)
> -        conn = conn->next;
> -
> -    new_conn->prev = conn;
> -    conn->next = new_conn;
> -
> -    if (server->debug)
> -        syslog(LOG_DEBUG, "new client accepted: %p, pid: %d",
> -               new_conn, (int)new_conn->peer_cred.pid);
> -
> -    if (server->connect_callback)
> -        server->connect_callback(new_conn);
> -}
> -
> -void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
> -        fd_set *writefds)
> -{
> -    struct udscs_connection *conn, *next_conn;
> -
> -    if (!server)
> -        return;
> -
> -    if (FD_ISSET(server->fd, readfds))
> -        udscs_server_accept(server);
> -
> -    conn = server->connections_head.next;
> -    while (conn) {
> -        /* conn maybe destroyed by udscs_client_handle_fds (when disconnected),
> -           so get the next connection first. */
> -        next_conn = conn->next;
> -        udscs_client_handle_fds(&conn, readfds, writefds);
> -        conn = next_conn;
> -    }
> -}
> -
> -void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
> -        fd_set *writefds)
> -{
> -    if (!*connp)
> -        return;
> -
> -    if (FD_ISSET((*connp)->fd, readfds))
> -        udscs_do_read(connp);
> +        return NULL;
>  
> -    if (*connp && FD_ISSET((*connp)->fd, writefds))
> -        udscs_do_write(connp);
> +    return conn->user_data;
>  }
>  
>  int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
> @@ -404,41 +212,7 @@ int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
>      return 0;
>  }
>  
> -int udscs_server_write_all(struct udscs_server *server,
> -        uint32_t type, uint32_t arg1, uint32_t arg2,
> -        const uint8_t *data, uint32_t size)
> -{
> -    struct udscs_connection *conn;
> -
> -    conn = server->connections_head.next;
> -    while (conn) {
> -        if (udscs_write(conn, type, arg1, arg2, data, size))
> -            return -1;
> -        conn = conn->next;
> -    }
> -
> -    return 0;
> -}
> -
> -int udscs_server_for_all_clients(struct udscs_server *server,
> -    udscs_for_all_clients_callback func, void *priv)
> -{
> -    int r = 0;
> -    struct udscs_connection *conn, *next_conn;
> -
> -    if (!server)
> -        return 0;
> -
> -    conn = server->connections_head.next;
> -    while (conn) {
> -        /* Get next conn as func may destroy the current conn */
> -        next_conn = conn->next;
> -        r += func(&conn, priv);
> -        conn = next_conn;
> -    }
> -    return r;
> -}
> -
> +/* A helper for udscs_do_read() */
>  static void udscs_read_complete(struct udscs_connection **connp)
>  {
>      struct udscs_connection *conn = *connp;
> @@ -466,6 +240,7 @@ static void udscs_read_complete(struct udscs_connection **connp)
>      memset(&conn->data, 0, sizeof(conn->data));
>  }
>  
> +/* A helper for udscs_client_handle_fds() */
>  static void udscs_do_read(struct udscs_connection **connp)
>  {
>      ssize_t n;
> @@ -516,6 +291,7 @@ static void udscs_do_read(struct udscs_connection **connp)
>      }
>  }
>  
> +/* A helper for udscs_client_handle_fds() */
>  static void udscs_do_write(struct udscs_connection **connp)
>  {
>      ssize_t n;
> @@ -549,15 +325,247 @@ static void udscs_do_write(struct udscs_connection **connp)
>      }
>  }
>  
> -void udscs_set_user_data(struct udscs_connection *conn, void *data)
> +void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
> +        fd_set *writefds)
>  {
> -    conn->user_data = data;
> +    if (!*connp)
> +        return;
> +
> +    if (FD_ISSET((*connp)->fd, readfds))
> +        udscs_do_read(connp);
> +
> +    if (*connp && FD_ISSET((*connp)->fd, writefds))
> +        udscs_do_write(connp);
>  }
>  
> -void *udscs_get_user_data(struct udscs_connection *conn)
> +int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
> +        fd_set *writefds)
>  {
>      if (!conn)
> +        return -1;
> +
> +    FD_SET(conn->fd, readfds);
> +    if (conn->write_buf)
> +        FD_SET(conn->fd, writefds);
> +
> +    return conn->fd + 1;
> +}
> +
> +
> +#ifndef UDSCS_NO_SERVER
> +
> +/* ---------- Server-side implementation ---------- */
> +
> +struct udscs_server {
> +    int fd;
> +    const char * const *type_to_string;
> +    int no_types;
> +    int debug;
> +    struct udscs_connection connections_head;
> +    udscs_connect_callback connect_callback;
> +    udscs_read_callback read_callback;
> +    udscs_disconnect_callback disconnect_callback;
> +};
> +
> +struct udscs_server *udscs_create_server(const char *socketname,
> +    udscs_connect_callback connect_callback,
> +    udscs_read_callback read_callback,
> +    udscs_disconnect_callback disconnect_callback,
> +    const char * const type_to_string[], int no_types, int debug)
> +{
> +    int c;
> +    struct sockaddr_un address;
> +    struct udscs_server *server;
> +
> +    server = calloc(1, sizeof(*server));
> +    if (!server)
>          return NULL;
>  
> -    return conn->user_data;
> +    server->type_to_string = type_to_string;
> +    server->no_types = no_types;
> +    server->debug = debug;
> +
> +    server->fd = socket(PF_UNIX, SOCK_STREAM, 0);
> +    if (server->fd == -1) {
> +        syslog(LOG_ERR, "creating unix domain socket: %m");
> +        free(server);
> +        return NULL;
> +    }
> +
> +    address.sun_family = AF_UNIX;
> +    snprintf(address.sun_path, sizeof(address.sun_path), "%s", socketname);
> +    c = bind(server->fd, (struct sockaddr *)&address, sizeof(address));
> +    if (c != 0) {
> +        syslog(LOG_ERR, "bind %s: %m", socketname);
> +        free(server);
> +        return NULL;
> +    }
> +
> +    c = listen(server->fd, 5);
> +    if (c != 0) {
> +        syslog(LOG_ERR, "listen: %m");
> +        free(server);
> +        return NULL;
> +    }
> +
> +    server->connect_callback = connect_callback;
> +    server->read_callback = read_callback;
> +    server->disconnect_callback = disconnect_callback;
> +
> +    return server;
> +}
> +
> +void udscs_destroy_server(struct udscs_server *server)
> +{
> +    struct udscs_connection *conn, *next_conn;
> +
> +    if (!server)
> +        return;
> +
> +    conn = server->connections_head.next;
> +    while (conn) {
> +        next_conn = conn->next;
> +        udscs_destroy_connection(&conn);
> +        conn = next_conn;
> +    }
> +    close(server->fd);
> +    free(server);
> +}
> +
> +struct ucred udscs_get_peer_cred(struct udscs_connection *conn)
> +{
> +    return conn->peer_cred;
>  }
> +
> +static void udscs_server_accept(struct udscs_server *server) {
> +    struct udscs_connection *new_conn, *conn;
> +    struct sockaddr_un address;
> +    socklen_t length = sizeof(address);
> +    int r, fd;
> +
> +    fd = accept(server->fd, (struct sockaddr *)&address, &length);
> +    if (fd == -1) {
> +        if (errno == EINTR)
> +            return;
> +        syslog(LOG_ERR, "accept: %m");
> +        return;
> +    }
> +
> +    new_conn = calloc(1, sizeof(*conn));
> +    if (!new_conn) {
> +        syslog(LOG_ERR, "out of memory, disconnecting new client");
> +        close(fd);
> +        return;
> +    }
> +
> +    new_conn->fd = fd;
> +    new_conn->type_to_string = server->type_to_string;
> +    new_conn->no_types = server->no_types;
> +    new_conn->debug = server->debug;
> +    new_conn->read_callback = server->read_callback;
> +    new_conn->disconnect_callback = server->disconnect_callback;
> +
> +    length = sizeof(new_conn->peer_cred);
> +    r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &new_conn->peer_cred, &length);
> +    if (r != 0) {
> +        syslog(LOG_ERR, "Could not get peercred, disconnecting new client");
> +        close(fd);
> +        free(new_conn);
> +        return;
> +    }
> +
> +    conn = &server->connections_head;
> +    while (conn->next)
> +        conn = conn->next;
> +
> +    new_conn->prev = conn;
> +    conn->next = new_conn;
> +
> +    if (server->debug)
> +        syslog(LOG_DEBUG, "new client accepted: %p, pid: %d",
> +               new_conn, (int)new_conn->peer_cred.pid);
> +
> +    if (server->connect_callback)
> +        server->connect_callback(new_conn);
> +}
> +
> +int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
> +        fd_set *writefds)
> +{
> +    struct udscs_connection *conn;
> +    int nfds = server->fd + 1;
> +
> +    if (!server)
> +        return -1;
> +
> +    FD_SET(server->fd, readfds);
> +
> +    conn = server->connections_head.next;
> +    while (conn) {
> +        int conn_nfds = udscs_client_fill_fds(conn, readfds, writefds);
> +        if (conn_nfds > nfds)
> +            nfds = conn_nfds;
> +
> +        conn = conn->next;
> +    }
> +
> +    return nfds;
> +}
> +
> +void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
> +        fd_set *writefds)
> +{
> +    struct udscs_connection *conn, *next_conn;
> +
> +    if (!server)
> +        return;
> +
> +    if (FD_ISSET(server->fd, readfds))
> +        udscs_server_accept(server);
> +
> +    conn = server->connections_head.next;
> +    while (conn) {
> +        /* conn maybe destroyed by udscs_client_handle_fds (when disconnected),
> +           so get the next connection first. */
> +        next_conn = conn->next;
> +        udscs_client_handle_fds(&conn, readfds, writefds);
> +        conn = next_conn;
> +    }
> +}
> +
> +int udscs_server_write_all(struct udscs_server *server,
> +        uint32_t type, uint32_t arg1, uint32_t arg2,
> +        const uint8_t *data, uint32_t size)
> +{
> +    struct udscs_connection *conn;
> +
> +    conn = server->connections_head.next;
> +    while (conn) {
> +        if (udscs_write(conn, type, arg1, arg2, data, size))
> +            return -1;
> +        conn = conn->next;
> +    }
> +
> +    return 0;
> +}
> +
> +int udscs_server_for_all_clients(struct udscs_server *server,
> +    udscs_for_all_clients_callback func, void *priv)
> +{
> +    int r = 0;
> +    struct udscs_connection *conn, *next_conn;
> +
> +    if (!server)
> +        return 0;
> +
> +    conn = server->connections_head.next;
> +    while (conn) {
> +        /* Get next conn as func may destroy the current conn */
> +        next_conn = conn->next;
> +        r += func(&conn, priv);
> +        conn = next_conn;
> +    }
> +    return r;
> +}
> +
> +#endif
> diff --git a/src/udscs.h b/src/udscs.h
> index 89ab617..8b0b14e 100644
> --- a/src/udscs.h
> +++ b/src/udscs.h
> @@ -27,8 +27,10 @@
>  #include <sys/select.h>
>  #include <sys/socket.h>
>  
> +
> +/* ---------- Generic bits and client-side API ---------- */
> +
>  struct udscs_connection;
> -struct udscs_server;
>  struct udscs_message_header {
>      uint32_t type;
>      uint32_t arg1;
> @@ -36,89 +38,107 @@ struct udscs_message_header {
>      uint32_t size;  
>  };
>  
> -/* Callbacks with this type will be called when a new connection to a
> -   server is accepted. */
> -typedef void (*udscs_connect_callback)(struct udscs_connection *conn);
>  /* Callbacks with this type will be called when a complete message has been
> -   received. The callback may call udscs_destroy_connection, in which case
> -   *connp must be made NULL (which udscs_destroy_connection takes care of) */
> + * received. The callback may call udscs_destroy_connection, in which case
> + * *connp must be made NULL (which udscs_destroy_connection takes care of).
> + */
>  typedef void (*udscs_read_callback)(struct udscs_connection **connp,
>      struct udscs_message_header *header, uint8_t *data);
> -/* Callback type for udscs_server_for_all_clients. Clients can be disconnected
> -   from this callback just like with a read callback. */
> -typedef int (*udscs_for_all_clients_callback)(struct udscs_connection **connp,
> -    void *priv);
> +
>  /* Callbacks with this type will be called when the connection is disconnected.
> -   Note:
> -   1) udscs will destroy the connection in question itself after
> -      this callback has completed!
> -   2) This callback is always called, even if the disconnect is initiated
> -      by the udscs user through returning -1 from a read callback, or
> -      by explictly calling udscs_destroy_connection */
> + * Note:
> + * 1) udscs will destroy the connection in question itself after
> + *    this callback has completed!
> + * 2) This callback is always called, even if the disconnect is initiated
> + *    by the udscs user through returning -1 from a read callback, or
> + *    by explictly calling udscs_destroy_connection.
> + */
>  typedef void (*udscs_disconnect_callback)(struct udscs_connection *conn);
>  
> -/* Create a unix domain socket named name and start listening on it. */
> -struct udscs_server *udscs_create_server(const char *socketname,
> -    udscs_connect_callback connect_callback,
> -    udscs_read_callback read_callback,
> -    udscs_disconnect_callback disconnect_callback,
> -    const char * const type_to_string[], int no_types, int debug);
> -
> -void udscs_destroy_server(struct udscs_server *server);
> -
>  /* Connect to a unix domain socket named name. */
>  struct udscs_connection *udscs_connect(const char *socketname,
>      udscs_read_callback read_callback,
>      udscs_disconnect_callback disconnect_callback,
>      const char * const type_to_string[], int no_types, int debug);
>  
> -/* The contents of connp will be made NULL */
> +/* The contents of connp will be made NULL. */
>  void udscs_destroy_connection(struct udscs_connection **connp);
>  
> -
> -/* Given an udscs server or client fill the fd_sets pointed to by readfds and
> -   writefds for select() usage.
> -
> -   Return value: value of the highest fd + 1 */
> -int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
> -        fd_set *writefds);
> -
>  int udscs_client_fill_fds(struct udscs_connection *conn, fd_set *readfds,
> -        fd_set *writefds);
> -
> -/* Handle any events flagged by select for the given udscs server or client. */
> -void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
> -        fd_set *writefds);
> +    fd_set *writefds);
>  
>  /* Note the connection may be destroyed (when disconnected) by this call
> -   in this case the disconnect calllback will get called before the
> -   destruction and the contents of connp will be made NULL */
> + * in this case the disconnect calllback will get called before the
> + * destruction and the contents of connp will be made NULL.
> + */
>  void udscs_client_handle_fds(struct udscs_connection **connp, fd_set *readfds,
> -        fd_set *writefds);
> -
> +    fd_set *writefds);
>  
>  /* Queue a message for delivery to the client connected through conn.
> -
> -   Returns 0 on success -1 on error (only happens when malloc fails) */
> + * Returns 0 on success -1 on error (only happens when malloc fails).
> + */
>  int udscs_write(struct udscs_connection *conn, uint32_t type, uint32_t arg1,
>          uint32_t arg2, const uint8_t *data, uint32_t size);
>  
> +/* To associate per connection data with a connection. */
> +void udscs_set_user_data(struct udscs_connection *conn, void *data);
> +void *udscs_get_user_data(struct udscs_connection *conn);
> +
> +
> +#ifndef UDSCS_NO_SERVER
> +
> +/* ---------- Server-side API ---------- */
> +
> +struct udscs_server;
> +
> +/* Callbacks with this type will be called when a new connection to a
> + * server is accepted.
> + */
> +typedef void (*udscs_connect_callback)(struct udscs_connection *conn);
> +
> +/* Create a unix domain socket named name and start listening on it. */
> +struct udscs_server *udscs_create_server(const char *socketname,
> +    udscs_connect_callback connect_callback,
> +    udscs_read_callback read_callback,
> +    udscs_disconnect_callback disconnect_callback,
> +    const char * const type_to_string[], int no_types, int debug);
> +
> +void udscs_destroy_server(struct udscs_server *server);
> +
>  /* Like udscs_write, but then send the message to all clients connected to
> -   the server */
> + * the server.
> + */
>  int udscs_server_write_all(struct udscs_server *server,
> -        uint32_t type, uint32_t arg1, uint32_t arg2,
> -        const uint8_t *data, uint32_t size);
> +    uint32_t type, uint32_t arg1, uint32_t arg2,
> +    const uint8_t *data, uint32_t size);
> +
> +/* Callback type for udscs_server_for_all_clients. Clients can be disconnected
> + * from this callback just like with a read callback.
> + */
> +typedef int (*udscs_for_all_clients_callback)(struct udscs_connection **connp,
> +    void *priv);
> +
>  /* Call func for all clients connected to the server, passing through
> -   priv to all func calls. Returns the total of the return values from all
> -   calls to func */
> + * priv to all func calls. Returns the total of the return values from all
> + * calls to func.
> + */
>  int udscs_server_for_all_clients(struct udscs_server *server,
> -        udscs_for_all_clients_callback func, void *priv);
> +    udscs_for_all_clients_callback func, void *priv);
>  
> +/* Given an udscs server or client fill the fd_sets pointed to by readfds and
> + * writefds for select() usage.
> + * Return value: value of the highest fd + 1
> + */
> +int udscs_server_fill_fds(struct udscs_server *server, fd_set *readfds,
> +    fd_set *writefds);
> +
> +/* Handle any events flagged by select for the given udscs server or client. */
> +void udscs_server_handle_fds(struct udscs_server *server, fd_set *readfds,
> +    fd_set *writefds);
>  
> +/* Returns the peer's user credentials. */
>  struct ucred udscs_get_peer_cred(struct udscs_connection *conn);
>  
> -/* For server use, to associate per connection data with a connection */
> -void udscs_set_user_data(struct udscs_connection *conn, void *data);
> -void *udscs_get_user_data(struct udscs_connection *conn);
> +#endif
>  
>  #endif
> -- 
> 2.6.1
> 
> _______________________________________________
> Spice-devel mailing list
> Spice-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel