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@xxxxxxxxxxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/spice-devel _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel