diff options
Diffstat (limited to 'cras/src/server/cras_server.c')
-rw-r--r-- | cras/src/server/cras_server.c | 267 |
1 files changed, 95 insertions, 172 deletions
diff --git a/cras/src/server/cras_server.c b/cras/src/server/cras_server.c index 97c83dfd..51f35079 100644 --- a/cras/src/server/cras_server.c +++ b/cras/src/server/cras_server.c @@ -49,7 +49,6 @@ #include "cras_server_metrics.h" #include "cras_system_state.h" #include "cras_tm.h" -#include "cras_types.h" #include "cras_udev.h" #include "cras_util.h" #include "cras_mix.h" @@ -99,13 +98,6 @@ struct system_task { struct system_task *next, *prev; }; -/* A structure wraps data related to server socket. */ -struct server_socket { - struct sockaddr_un addr; - int fd; - enum CRAS_CONNECTION_TYPE type; -}; - /* Local server data. */ struct server_data { struct attached_client *clients_head; @@ -114,19 +106,8 @@ struct server_data { struct system_task *system_tasks; size_t num_client_callbacks; size_t next_client_id; - struct server_socket server_sockets[CRAS_NUM_CONN_TYPE]; } server_instance; -/* Cleanup a given server_socket */ -static void server_socket_cleanup(struct server_socket *socket) -{ - if (socket && socket->fd >= 0) { - close(socket->fd); - socket->fd = -1; - unlink(socket->addr.sun_path); - } -} - /* Remove a client from the list and destroy it. Calling rclient_destroy will * also free all the streams owned by the client */ static void remove_client(struct attached_client *client) @@ -145,21 +126,19 @@ static void handle_message_from_client(struct attached_client *client) { uint8_t buf[CRAS_SERV_MAX_MSG_SIZE]; int nread; - unsigned int num_fds = 2; - int fds[num_fds]; + int fd; + unsigned int num_fds = 1; - nread = cras_recv_with_fds(client->fd, buf, sizeof(buf), fds, &num_fds); - if (nread < 0) - goto read_error; - if (cras_rclient_buffer_from_client(client->client, buf, nread, fds, - num_fds) < 0) + nread = cras_recv_with_fds(client->fd, buf, sizeof(buf), &fd, &num_fds); + if (nread < 0) + goto read_error; + if (cras_rclient_buffer_from_client(client->client, buf, nread, fd) < 0) goto read_error; return; read_error: - for (int i = 0; i < num_fds; i++) - if (fds[i] >= 0) - close(fds[i]); + if (fd != -1) + close(fd); switch (nread) { case 0: break; @@ -177,8 +156,8 @@ static void fill_client_info(struct attached_client *client) { socklen_t ucred_length = sizeof(client->ucred); - if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, &client->ucred, - &ucred_length)) + if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, + &client->ucred, &ucred_length)) syslog(LOG_INFO, "Failed to get client socket info\n"); } @@ -199,7 +178,7 @@ static void send_client_list_to_clients(struct server_data *serv) info = state->client_info; i = 0; - DL_FOREACH (serv->clients_head, c) { + DL_FOREACH(serv->clients_head, c) { info->id = c->id; info->pid = c->ucred.pid; info->uid = c->ucred.uid; @@ -214,7 +193,7 @@ static void send_client_list_to_clients(struct server_data *serv) /* Handles requests from a client to attach to the server. Create a local * structure to track the client, assign it a unique id and let it attach */ -static void handle_new_connection(struct server_socket *server_socket) +static void handle_new_connection(struct sockaddr_un *address, int fd) { int connection_fd; struct attached_client *poll_client; @@ -227,8 +206,7 @@ static void handle_new_connection(struct server_socket *server_socket) } memset(&address_length, 0, sizeof(address_length)); - connection_fd = accept(server_socket->fd, - (struct sockaddr *)&server_socket->addr, + connection_fd = accept(fd, (struct sockaddr *) address, &address_length); if (connection_fd < 0) { syslog(LOG_ERR, "connecting"); @@ -254,12 +232,13 @@ static void handle_new_connection(struct server_socket *server_socket) poll_client->next = NULL; poll_client->pollfd = NULL; fill_client_info(poll_client); - - poll_client->client = cras_rclient_create( - connection_fd, poll_client->id, server_socket->type); + poll_client->client = cras_rclient_create(connection_fd, + poll_client->id); if (poll_client->client == NULL) { syslog(LOG_ERR, "failed to create client"); - goto error; + close(connection_fd); + free(poll_client); + return; } DL_APPEND(server_instance.clients_head, poll_client); @@ -267,18 +246,13 @@ static void handle_new_connection(struct server_socket *server_socket) /* Send a current list of available inputs and outputs. */ cras_iodev_list_update_device_list(); send_client_list_to_clients(&server_instance); - return; -error: - close(connection_fd); - free(poll_client); - return; } /* Add a file descriptor to be passed to select in the main loop. This is * registered with system state so that it is called when any client asks to * have a callback triggered based on an fd being readable. */ -static int add_select_fd(int fd, void (*cb)(void *data), void *callback_data, - void *server_data) +static int add_select_fd(int fd, void (*cb)(void *data), + void *callback_data, void *server_data) { struct client_callback *new_cb; struct client_callback *client_cb; @@ -289,11 +263,11 @@ static int add_select_fd(int fd, void (*cb)(void *data), void *callback_data, return -EINVAL; /* Check if fd already exists. */ - DL_FOREACH (serv->client_callbacks, client_cb) + DL_FOREACH(serv->client_callbacks, client_cb) if (client_cb->select_fd == fd && !client_cb->deleted) return -EEXIST; - new_cb = (struct client_callback *)calloc(1, sizeof(*new_cb)); + new_cb = (struct client_callback *)calloc(1, sizeof(*new_cb)); if (new_cb == NULL) return -ENOMEM; @@ -320,7 +294,7 @@ static void rm_select_fd(int fd, void *server_data) if (serv == NULL) return; - DL_FOREACH (serv->client_callbacks, client_cb) + DL_FOREACH(serv->client_callbacks, client_cb) if (client_cb->select_fd == fd) client_cb->deleted = 1; } @@ -328,7 +302,8 @@ static void rm_select_fd(int fd, void *server_data) /* Creates a new task entry and append to system_tasks list, which will be * executed in main loop later without wait time. */ -static int add_task(void (*cb)(void *data), void *callback_data, +static int add_task(void (*cb)(void *data), + void *callback_data, void *server_data) { struct server_data *serv; @@ -360,7 +335,7 @@ static void cleanup_select_fds(void *server_data) if (serv == NULL) return; - DL_FOREACH (serv->client_callbacks, client_cb) + DL_FOREACH(serv->client_callbacks, client_cb) if (client_cb->deleted) { DL_DELETE(serv->client_callbacks, client_cb); server_instance.num_client_callbacks--; @@ -379,9 +354,8 @@ void check_output_exists(struct cras_timer *t, void *data) #if defined(__amd64__) /* CPU detection - probaby best to move this elsewhere */ static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, - unsigned int *edx, unsigned int op) + unsigned int *edx, unsigned int op) { - // clang-format off __asm__ __volatile__ ( "cpuid" : "=a" (*eax), @@ -389,8 +363,7 @@ static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, "=c" (*ecx), "=d" (*edx) : "a" (op), "c" (0) - ); - // clang-format on + ); } static unsigned int cpu_x86_flags(void) @@ -457,90 +430,7 @@ int cras_server_init() cras_system_set_add_task_handler(add_task, &server_instance); cras_main_message_init(); - /* Initializes all server_sockets */ - for (int conn_type = 0; conn_type < CRAS_NUM_CONN_TYPE; conn_type++) { - server_instance.server_sockets[conn_type].fd = -1; - } - - return 0; -} - -/* - * Creates a server socket with given connection type and listens on it. - * The socket_file will be created under cras_config_get_system_socket_file_dir - * with permission=0770. The socket_fd will be listened with parameter - * backlog=5. - * - * Returns 0 on success and leaves the created fd and the address information - * in server_socket. - * When error occurs, the created fd will be closed and the file path will be - * unlinked. - */ -static int create_and_listen_server_socket(enum CRAS_CONNECTION_TYPE conn_type, - struct server_socket *server_socket) -{ - int socket_fd = -1; - int rc = 0; - struct sockaddr_un *addr = &server_socket->addr; - - socket_fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); - if (socket_fd < 0) { - syslog(LOG_ERR, "Main server socket failed."); - rc = socket_fd; - goto error; - } - - memset(addr, 0, sizeof(*addr)); - addr->sun_family = AF_UNIX; - rc = cras_fill_socket_path(conn_type, addr->sun_path); - if (rc < 0) - goto error; - unlink(addr->sun_path); - - /* Linux quirk: calling fchmod before bind, sets the permissions of the - * file created by bind, leaving no window for it to be modified. Start - * with very restricted permissions. */ - rc = fchmod(socket_fd, 0700); - if (rc < 0) - goto error; - - rc = bind(socket_fd, (struct sockaddr *)addr, - sizeof(struct sockaddr_un)); - if (rc < 0) { - syslog(LOG_ERR, "Bind to server socket failed."); - rc = errno; - goto error; - } - - /* Let other members in our group play audio through this socket. */ - rc = chmod(addr->sun_path, 0770); - if (rc < 0) - goto error; - - if (listen(socket_fd, 5) != 0) { - syslog(LOG_ERR, "Listen on server socket failed."); - rc = errno; - goto error; - } - - server_socket->fd = socket_fd; - server_socket->type = conn_type; return 0; -error: - if (socket_fd >= 0) { - close(socket_fd); - unlink(addr->sun_path); - } - return rc; -} - -/* Cleans up all server_socket in server_instance */ -static void cleanup_server_sockets() -{ - for (int conn_type = 0; conn_type < CRAS_NUM_CONN_TYPE; conn_type++) { - server_socket_cleanup( - &server_instance.server_sockets[conn_type]); - } } int cras_server_run(unsigned int profile_disable_mask) @@ -549,7 +439,10 @@ int cras_server_run(unsigned int profile_disable_mask) #ifdef CRAS_DBUS DBusConnection *dbus_conn; #endif + int socket_fd = -1; int rc = 0; + const char *sockdir; + struct sockaddr_un addr; struct attached_client *elm; struct client_callback *client_cb; struct system_task *tasks; @@ -595,11 +488,48 @@ int cras_server_run(unsigned int profile_disable_mask) } #endif - for (int conn_type = 0; conn_type < CRAS_NUM_CONN_TYPE; conn_type++) { - rc = create_and_listen_server_socket( - conn_type, &server_instance.server_sockets[conn_type]); - if (rc < 0) - goto bail; + socket_fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); + if (socket_fd < 0) { + syslog(LOG_ERR, "Main server socket failed."); + rc = socket_fd; + goto bail; + } + + sockdir = cras_config_get_system_socket_file_dir(); + if (sockdir == NULL) { + rc = -ENOTDIR; + goto bail; + } + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + snprintf(addr.sun_path, sizeof(addr.sun_path), + "%s/%s", sockdir, CRAS_SOCKET_FILE); + unlink(addr.sun_path); + + /* Linux quirk: calling fchmod before bind, sets the permissions of the + * file created by bind, leaving no window for it to be modified. Start + * with very restricted permissions. */ + rc = fchmod(socket_fd, 0700); + if (rc < 0) + goto bail; + + if (bind(socket_fd, (struct sockaddr *) &addr, + sizeof(struct sockaddr_un)) != 0) { + syslog(LOG_ERR, "Bind to server socket failed."); + rc = errno; + goto bail; + } + + /* Let other members in our group play audio through this socket. */ + rc = chmod(addr.sun_path, 0770); + if (rc < 0) + goto bail; + + if (listen(socket_fd, 5) != 0) { + syslog(LOG_ERR, "Listen on server socket failed."); + rc = errno; + goto bail; } tm = cras_system_state_get_tm(); @@ -614,30 +544,25 @@ int cras_server_run(unsigned int profile_disable_mask) /* Main server loop - client callbacks are run from this context. */ while (1) { - poll_size_needed = CRAS_NUM_CONN_TYPE + - server_instance.num_clients + - server_instance.num_client_callbacks; + poll_size_needed = 1 + server_instance.num_clients + + server_instance.num_client_callbacks; if (poll_size_needed > pollfds_size) { pollfds_size = 2 * poll_size_needed; pollfds = realloc(pollfds, - sizeof(*pollfds) * pollfds_size); + sizeof(*pollfds) * pollfds_size); } - for (int conn_type = 0; conn_type < CRAS_NUM_CONN_TYPE; - conn_type++) { - pollfds[conn_type].fd = - server_instance.server_sockets[conn_type].fd; - pollfds[conn_type].events = POLLIN; - } - num_pollfds = CRAS_NUM_CONN_TYPE; + pollfds[0].fd = socket_fd; + pollfds[0].events = POLLIN; + num_pollfds = 1; - DL_FOREACH (server_instance.clients_head, elm) { + DL_FOREACH(server_instance.clients_head, elm) { pollfds[num_pollfds].fd = elm->fd; pollfds[num_pollfds].events = POLLIN; elm->pollfd = &pollfds[num_pollfds]; num_pollfds++; } - DL_FOREACH (server_instance.client_callbacks, client_cb) { + DL_FOREACH(server_instance.client_callbacks, client_cb) { if (client_cb->deleted) continue; pollfds[num_pollfds].fd = client_cb->select_fd; @@ -648,7 +573,7 @@ int cras_server_run(unsigned int profile_disable_mask) tasks = server_instance.system_tasks; server_instance.system_tasks = NULL; - DL_FOREACH (tasks, system_task) { + DL_FOREACH(tasks, system_task) { system_task->callback(system_task->callback_data); DL_DELETE(tasks, system_task); free(system_task); @@ -666,27 +591,22 @@ int cras_server_run(unsigned int profile_disable_mask) poll_timeout = timers_active ? &ts : NULL; rc = ppoll(pollfds, num_pollfds, poll_timeout, NULL); - if (rc < 0) + if (rc < 0) continue; cras_tm_call_callbacks(tm); /* Check for new connections. */ - for (int conn_type = 0; conn_type < CRAS_NUM_CONN_TYPE; - conn_type++) { - if (pollfds[conn_type].revents & POLLIN) - handle_new_connection( - &server_instance - .server_sockets[conn_type]); - } - + if (pollfds[0].revents & POLLIN) + handle_new_connection(&addr, socket_fd); /* Check if there are messages pending for any clients. */ - DL_FOREACH (server_instance.clients_head, elm) + DL_FOREACH(server_instance.clients_head, elm) if (elm->pollfd && elm->pollfd->revents & POLLIN) handle_message_from_client(elm); /* Check any client-registered fd/callback pairs. */ - DL_FOREACH (server_instance.client_callbacks, client_cb) - if (!client_cb->deleted && client_cb->pollfd && + DL_FOREACH(server_instance.client_callbacks, client_cb) + if (!client_cb->deleted && + client_cb->pollfd && (client_cb->pollfd->revents & POLLIN)) client_cb->callback(client_cb->callback_data); @@ -701,7 +621,10 @@ int cras_server_run(unsigned int profile_disable_mask) } bail: - cleanup_server_sockets(); + if (socket_fd >= 0) { + close(socket_fd); + unlink(addr.sun_path); + } free(pollfds); cras_observer_server_free(); return rc; @@ -711,6 +634,6 @@ void cras_server_send_to_all_clients(const struct cras_client_message *msg) { struct attached_client *client; - DL_FOREACH (server_instance.clients_head, client) + DL_FOREACH(server_instance.clients_head, client) cras_rclient_send_message(client->client, msg, NULL, 0); -}
\ No newline at end of file +} |