summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancois Gouget <fgouget@codeweavers.com>2015-11-13 16:26:16 +0100
committerVictor Toso <victortoso@redhat.com>2015-11-13 17:57:25 +0100
commit69c88c633f4ae59468d161e6b157afc58f5102af (patch)
tree2b29cfad66e1c6f6871aceaf4939d0a9d18d8b22
parent02370e444514a15c58f166d86f91b4eeddb3cb11 (diff)
vdagent: Group the client and server functions together
This will simplify selectively disabling the server-side code. Signed-off-by: Francois Gouget <fgouget@codeweavers.com>
-rw-r--r--src/udscs.c478
-rw-r--r--src/udscs.h128
2 files changed, 314 insertions, 292 deletions
diff --git a/src/udscs.c b/src/udscs.c
index 288aca2..732db33 100644
--- a/src/udscs.c
+++ b/src/udscs.c
@@ -66,86 +66,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 +145,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 +210,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 +238,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 +289,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 +323,243 @@ 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;
+}
+
+
+/* ---------- 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;
}
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