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

Francois Gouget fgouget at codeweavers.com
Thu Nov 5 10:21:38 PST 2015


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 at 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



More information about the Spice-devel mailing list