cras_server.c revision c3211501e365373b72e9ca423e837f07bc1f6ac5
1/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6#define _GNU_SOURCE /* Needed for Linux socket credential passing. */ 7 8#include <errno.h> 9#include <stdint.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <sys/select.h> 14#include <sys/socket.h> 15#include <sys/stat.h> 16#include <sys/types.h> 17#include <sys/un.h> 18#include <syslog.h> 19#include <unistd.h> 20 21#include "cras_alert.h" 22#include "cras_bluetooth.h" 23#include "cras_config.h" 24#include "cras_dbus.h" 25#include "cras_dbus_control.h" 26#include "cras_iodev_list.h" 27#include "cras_messages.h" 28#include "cras_metrics.h" 29#include "cras_rclient.h" 30#include "cras_server.h" 31#include "cras_server_metrics.h" 32#include "cras_system_state.h" 33#include "cras_tm.h" 34#include "cras_udev.h" 35#include "cras_util.h" 36#include "utlist.h" 37 38/* Store a list of clients that are attached to the server. 39 * Members: 40 * id - Unique identifier for this client. 41 * fd - socket file descriptor used to communicate with client. 42 * ucred - Process, user, and group ID of the client. 43 * client - rclient to handle messages from this client. 44 */ 45struct attached_client { 46 size_t id; 47 int fd; 48 struct ucred ucred; 49 struct cras_rclient *client; 50 struct attached_client *next, *prev; 51}; 52 53/* Stores file descriptors to callback mappings for clients. Callback/fd/data 54 * args are registered by clients. When fd is ready, the callback will be 55 * called on the main server thread and the callback data will be passed back to 56 * it. This allows the use of the main server loop instead of spawning a thread 57 * to watch file descriptors. The client can then read or write the fd. 58 * Members: 59 * fd - The file descriptor passed to select. 60 * callack - The funciton to call when fd is ready. 61 * callback_data - Pointer passed to the callback. 62 */ 63struct client_callback { 64 int select_fd; 65 void (*callback)(void *); 66 void *callback_data; 67 int deleted; 68 struct client_callback *prev, *next; 69}; 70 71/* Local server data. */ 72struct server_data { 73 struct attached_client *clients_head; 74 size_t num_clients; 75 struct client_callback *client_callbacks; 76 size_t next_client_id; 77} server_instance; 78 79/* Remove a client from the list and destroy it. Calling rclient_destroy will 80 * also free all the streams owned by the client */ 81static void remove_client(struct attached_client *client) 82{ 83 close(client->fd); 84 DL_DELETE(server_instance.clients_head, client); 85 server_instance.num_clients--; 86 cras_rclient_destroy(client->client); 87 free(client); 88} 89 90/* This is called when "select" indicates that the client has written data to 91 * the socket. Read out one message and pass it to the client message handler. 92 */ 93static void handle_message_from_client(struct attached_client *client) 94{ 95 uint8_t buf[CRAS_SERV_MAX_MSG_SIZE]; 96 struct cras_server_message *msg; 97 int nread; 98 int fd; 99 100 msg = (struct cras_server_message *)buf; 101 nread = cras_recv_with_fd(client->fd, buf, sizeof(buf), &fd); 102 if (nread < sizeof(msg->length)) 103 goto read_error; 104 if (msg->length != nread) 105 goto read_error; 106 cras_rclient_message_from_client(client->client, msg, fd); 107 return; 108 109read_error: 110 if (fd != -1) 111 close(fd); 112 syslog(LOG_DEBUG, "read err, removing client %zu", client->id); 113 remove_client(client); 114} 115 116/* Discovers and fills in info about the client that can be obtained from the 117 * socket. The pid of the attaching client identifies it in logs. */ 118static void fill_client_info(struct attached_client *client) 119{ 120 socklen_t ucred_length = sizeof(client->ucred); 121 122 if (getsockopt(client->fd, SOL_SOCKET, SO_PEERCRED, 123 &client->ucred, &ucred_length)) 124 syslog(LOG_INFO, "Failed to get client socket info\n"); 125} 126 127/* Fills the server_state with the current list of attached clients. */ 128static void send_client_list_to_clients(struct server_data *serv) 129{ 130 struct attached_client *c; 131 struct cras_attached_client_info *info; 132 struct cras_server_state *state; 133 unsigned i; 134 135 state = cras_system_state_update_begin(); 136 if (!state) 137 return; 138 139 state->num_attached_clients = 140 min(CRAS_MAX_ATTACHED_CLIENTS, serv->num_clients); 141 142 info = state->client_info; 143 i = 0; 144 DL_FOREACH(serv->clients_head, c) { 145 info->id = c->id; 146 info->pid = c->ucred.pid; 147 info->uid = c->ucred.uid; 148 info->gid = c->ucred.gid; 149 info++; 150 if (++i == CRAS_MAX_ATTACHED_CLIENTS) 151 break; 152 } 153 154 cras_system_state_update_complete(); 155} 156 157/* Handles requests from a client to attach to the server. Create a local 158 * structure to track the client, assign it a unique id and let it attach */ 159static void handle_new_connection(struct sockaddr_un *address, int fd) 160{ 161 int connection_fd; 162 struct attached_client *poll_client; 163 socklen_t address_length; 164 165 poll_client = malloc(sizeof(struct attached_client)); 166 if (poll_client == NULL) { 167 syslog(LOG_ERR, "Allocating poll_client"); 168 return; 169 } 170 171 memset(&address_length, 0, sizeof(address_length)); 172 connection_fd = accept(fd, (struct sockaddr *) address, 173 &address_length); 174 if (connection_fd < 0) { 175 syslog(LOG_ERR, "connecting"); 176 free(poll_client); 177 return; 178 } 179 180 /* find next available client id */ 181 while (1) { 182 struct attached_client *out; 183 DL_SEARCH_SCALAR(server_instance.clients_head, out, id, 184 server_instance.next_client_id); 185 poll_client->id = server_instance.next_client_id; 186 server_instance.next_client_id++; 187 if (out == NULL) 188 break; 189 } 190 191 /* When full, getting an error is preferable to blocking. */ 192 cras_make_fd_nonblocking(connection_fd); 193 194 poll_client->fd = connection_fd; 195 poll_client->next = NULL; 196 fill_client_info(poll_client); 197 poll_client->client = cras_rclient_create(connection_fd, 198 poll_client->id); 199 if (poll_client->client == NULL) { 200 syslog(LOG_ERR, "failed to create client"); 201 close(connection_fd); 202 free(poll_client); 203 return; 204 } 205 206 DL_APPEND(server_instance.clients_head, poll_client); 207 server_instance.num_clients++; 208 /* Send a current list of available inputs and outputs. */ 209 cras_iodev_list_update_device_list(); 210 send_client_list_to_clients(&server_instance); 211} 212 213/* Add a file descriptor to be passed to select in the main loop. This is 214 * registered with system state so that it is called when any client asks to 215 * have a callback triggered based on an fd being readable. */ 216static int add_select_fd(int fd, void (*cb)(void *data), 217 void *callback_data, void *server_data) 218{ 219 struct client_callback *new_cb; 220 struct client_callback *client_cb; 221 struct server_data *serv; 222 223 serv = (struct server_data *)server_data; 224 if (serv == NULL) 225 return -EINVAL; 226 227 /* Check if fd already exists. */ 228 DL_FOREACH(serv->client_callbacks, client_cb) 229 if (client_cb->select_fd == fd && !client_cb->deleted) 230 return -EEXIST; 231 232 new_cb = (struct client_callback *)calloc(1, sizeof(*new_cb)); 233 if (new_cb == NULL) 234 return -ENOMEM; 235 236 new_cb->select_fd = fd; 237 new_cb->callback = cb; 238 new_cb->callback_data = callback_data; 239 new_cb->deleted = 0; 240 241 DL_APPEND(serv->client_callbacks, new_cb); 242 return 0; 243} 244 245/* Removes a file descriptor to be passed to select in the main loop. This is 246 * registered with system state so that it is called when any client asks to 247 * remove a callback added with add_select_fd. */ 248static void rm_select_fd(int fd, void *server_data) 249{ 250 struct server_data *serv; 251 struct client_callback *client_cb, *temp_callback; 252 253 serv = (struct server_data *)server_data; 254 if (serv == NULL) 255 return; 256 257 DL_FOREACH_SAFE(serv->client_callbacks, client_cb, temp_callback) 258 if (client_cb->select_fd == fd) 259 client_cb->deleted = 1; 260} 261 262/* Cleans up the file descriptor list removing items deleted during the main 263 * loop iteration. */ 264static void cleanup_select_fds(void *server_data) 265{ 266 struct server_data *serv; 267 struct client_callback *client_cb, *temp_callback; 268 269 serv = (struct server_data *)server_data; 270 if (serv == NULL) 271 return; 272 273 DL_FOREACH_SAFE(serv->client_callbacks, client_cb, temp_callback) 274 if (client_cb->deleted) { 275 DL_DELETE(serv->client_callbacks, client_cb); 276 free(client_cb); 277 } 278} 279 280/* Checks that at least two outputs are present (one will be the "empty" 281 * default device. */ 282void check_output_exists(struct cras_timer *t, void *data) 283{ 284 if (cras_iodev_list_get_outputs(NULL) < 2) 285 cras_metrics_log_action(kNoCodecsFoundMetric); 286} 287 288/* 289 * Exported Interface. 290 */ 291 292int cras_server_run() 293{ 294 static const unsigned int OUTPUT_CHECK_MS = 5 * 1000; 295 296 DBusConnection *dbus_conn; 297 int socket_fd = -1; 298 int max_poll_fd; 299 fd_set poll_set; 300 int rc = 0; 301 const char *sockdir; 302 struct sockaddr_un addr; 303 struct attached_client *elm, *tmp; 304 struct client_callback *client_cb; 305 struct cras_tm *tm; 306 struct timespec ts; 307 int timers_active; 308 309 /* Log to syslog. */ 310 openlog("cras_server", LOG_PID, LOG_USER); 311 312 /* Allow clients to register callbacks for file descriptors. 313 * add_select_fd and rm_select_fd will add and remove file descriptors 314 * from the list that are passed to select in the main loop below. */ 315 cras_system_set_select_handler(add_select_fd, rm_select_fd, 316 &server_instance); 317 318 cras_udev_start_sound_subsystem_monitor(); 319 dbus_conn = cras_dbus_connect_system_bus(); 320 if (dbus_conn) { 321 cras_bluetooth_start(dbus_conn); 322 cras_dbus_control_start(dbus_conn); 323 } 324 325 socket_fd = socket(PF_UNIX, SOCK_SEQPACKET, 0); 326 if (socket_fd < 0) { 327 syslog(LOG_ERR, "Main server socket failed."); 328 rc = socket_fd; 329 goto bail; 330 } 331 332 sockdir = cras_config_get_system_socket_file_dir(); 333 if (sockdir == NULL) { 334 rc = -ENOTDIR; 335 goto bail; 336 } 337 338 memset(&addr, 0, sizeof(addr)); 339 addr.sun_family = AF_UNIX; 340 snprintf(addr.sun_path, sizeof(addr.sun_path), 341 "%s/%s", sockdir, CRAS_SOCKET_FILE); 342 unlink(addr.sun_path); 343 344 /* Linux quirk: calling fchmod before bind, sets the permissions of the 345 * file created by bind, leaving no window for it to be modified. Start 346 * with very restricted permissions. */ 347 rc = fchmod(socket_fd, 0700); 348 if (rc < 0) 349 goto bail; 350 351 if (bind(socket_fd, (struct sockaddr *) &addr, 352 sizeof(struct sockaddr_un)) != 0) { 353 syslog(LOG_ERR, "Bind to server socket failed."); 354 rc = errno; 355 goto bail; 356 } 357 358 /* Let other members in our group play audio through this socket. */ 359 rc = chmod(addr.sun_path, 0770); 360 if (rc < 0) 361 goto bail; 362 363 if (listen(socket_fd, 5) != 0) { 364 syslog(LOG_ERR, "Listen on server socket failed."); 365 rc = errno; 366 goto bail; 367 } 368 369 tm = cras_system_state_get_tm(); 370 if (!tm) { 371 syslog(LOG_ERR, "Getting timer manager."); 372 rc = -ENOMEM; 373 goto bail; 374 } 375 376 /* After a delay, make sure there is at least one real output device. */ 377 cras_tm_create_timer(tm, OUTPUT_CHECK_MS, check_output_exists, 0); 378 379 /* Main server loop - client callbacks are run from this context. */ 380 while (1) { 381 FD_ZERO(&poll_set); 382 FD_SET(socket_fd, &poll_set); 383 max_poll_fd = socket_fd; 384 DL_FOREACH(server_instance.clients_head, elm) { 385 if (elm->fd > max_poll_fd) 386 max_poll_fd = elm->fd; 387 FD_SET(elm->fd, &poll_set); 388 } 389 DL_FOREACH(server_instance.client_callbacks, client_cb) { 390 if (client_cb->deleted) 391 continue; 392 if (client_cb->select_fd > max_poll_fd) 393 max_poll_fd = client_cb->select_fd; 394 FD_SET(client_cb->select_fd, &poll_set); 395 } 396 397 timers_active = cras_tm_get_next_timeout(tm, &ts); 398 399 rc = pselect(max_poll_fd + 1, &poll_set, NULL, NULL, 400 timers_active ? &ts : NULL, NULL); 401 if (rc < 0) 402 continue; 403 404 cras_tm_call_callbacks(tm); 405 406 /* Check for new connections. */ 407 if (FD_ISSET(socket_fd, &poll_set)) 408 handle_new_connection(&addr, socket_fd); 409 /* Check if there are messages pending for any clients. */ 410 DL_FOREACH_SAFE(server_instance.clients_head, elm, tmp) 411 if (FD_ISSET(elm->fd, &poll_set)) 412 handle_message_from_client(elm); 413 /* Check any client-registered fd/callback pairs. */ 414 DL_FOREACH(server_instance.client_callbacks, client_cb) 415 if (FD_ISSET(client_cb->select_fd, &poll_set) && 416 !client_cb->deleted) 417 client_cb->callback(client_cb->callback_data); 418 419 cleanup_select_fds(&server_instance); 420 421 if (dbus_conn) 422 cras_dbus_dispatch(dbus_conn); 423 424 cras_alert_process_all_pending_alerts(); 425 } 426 427bail: 428 if (socket_fd >= 0) { 429 close(socket_fd); 430 unlink(addr.sun_path); 431 } 432 return rc; 433} 434 435void cras_server_send_to_all_clients(const struct cras_client_message *msg) 436{ 437 struct attached_client *client; 438 439 DL_FOREACH(server_instance.clients_head, client) 440 cras_rclient_send_message(client->client, msg); 441} 442