2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 #include <sys/types.h>
46 #include <audio-session-manager.h>
48 #include <murphy/common.h>
50 #include "asm-bridge.h"
53 typedef struct ctx_s {
57 mrp_htbl_t *watched_files;
69 static void *wait_queue (void *arg) {
70 ASM_msg_lib_to_asm_t msg;
72 int *arg_thread = arg;
74 int asm_rcv_msgid = arg_thread[0];
75 int fd = arg_thread[1];
77 if (asm_rcv_msgid == -1) {
78 mrp_log_error("failed to create the receive message queue\n");
83 int ret = msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, 0);
86 /* FIXME: proper error handling */
87 mrp_log_error("error receiving a message: '%s'!", strerror(errno));
88 /* remove message from queue */
89 msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, MSG_NOERROR);
93 /* alignment is fine, since the first argument to the struct is a long */
94 write(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
101 static void dump_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
105 mrp_log_info("Message id %ld:", msg->instance_id);
107 mrp_log_info("Data handle: %d", msg->data.handle);
108 mrp_log_info(" request id: 0x%04x", msg->data.request_id);
109 mrp_log_info(" sound event: 0x%04x", msg->data.sound_event);
110 mrp_log_info(" sound state: 0x%04x", msg->data.sound_state);
111 mrp_log_info(" system resource: 0x%04x", msg->data.system_resource);
116 mrp_log_info(" cookie: ");
117 for (i = 0; i < COOKIE_SIZE; i++) {
118 mrp_log_info("0x%02x ", msg->data.cookie[i]);
126 static int process_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
129 uint8_t cookie_arr[] = {};
130 uint8_t *cookie = cookie_arr;
135 /* FIXME: instance_id is signed? */
136 res.instance_id = msg->instance_id;
137 res.handle = msg->data.handle;
138 res.request_id = msg->data.request_id;
139 res.sound_event = msg->data.sound_event;
140 res.sound_state = msg->data.sound_state;
141 res.system_resource = msg->data.system_resource;
143 cookie_len = COOKIE_SIZE;
144 cookie = msg->data.cookie;
147 res.n_cookie_bytes = cookie_len;
150 if (!mrp_transport_senddata(ctx->mt, &res, lib_to_asm_descr.tag)) {
151 mrp_log_error("Failed to send message to murphy");
159 static void pipe_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
160 mrp_io_event_t events, void *user_data)
162 ASM_msg_lib_to_asm_t msg;
163 ctx_t *ctx = user_data;
171 bytes = read(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
173 if (bytes != sizeof(ASM_msg_lib_to_asm_t)) {
174 mrp_log_error("failed to read from the pipe");
178 ret = process_msg(&msg, ctx);
181 mrp_log_error("error parsing or proxying message");
186 static void read_watch_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
187 mrp_io_event_t events, void *user_data)
189 struct watched_file *wf = user_data;
190 ctx_t *ctx = wf->ctx;
195 if (events & MRP_IO_EVENT_IN) {
199 ret = read(fd, &buf, sizeof(uint32_t));
201 if (ret == sizeof(uint32_t)) {
204 msg.instance_id = wf->instance_id;
205 msg.handle = wf->handle;
208 if (!mrp_transport_senddata(ctx->mt, &msg, lib_to_asm_cb_descr.tag)) {
209 mrp_log_error("Failed to send message to murphy");
213 if (events & MRP_IO_EVENT_HUP) {
214 /* can we assume that the client went away? */
215 mrp_log_error("HUP event from client");
218 mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
223 static int send_callback_to_client(asm_to_lib_cb_t *msg, ctx_t *ctx)
225 #define ASM_FILENAME_SIZE 64
226 char wr_filename[ASM_FILENAME_SIZE];
227 char rd_filename[ASM_FILENAME_SIZE];
234 struct watched_file *wf = NULL;
236 ret = snprintf(wr_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%u",
237 msg->instance_id, msg->handle);
239 if (ret <= 0 || ret == ASM_FILENAME_SIZE)
242 mrp_log_info("writing client preemption to file %s", wr_filename);
244 wr_fd = open(wr_filename, O_NONBLOCK | O_WRONLY);
246 mrp_log_error("failed to open file '%s' for writing: '%s'", wr_filename,
251 if (msg->callback_expected) {
253 ret = snprintf(rd_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%ur",
254 msg->instance_id, msg->handle);
256 if (ret <= 0 || ret == ASM_FILENAME_SIZE)
259 rd_fd = open(wr_filename, O_NONBLOCK | O_RDONLY);
261 mrp_log_error("failed to open file '%s' for reading: '%s'",
262 rd_filename, strerror(errno));
266 wf = mrp_htbl_lookup(ctx->watched_files, rd_filename);
269 /* already watched, this is a bad thing */
271 mrp_log_error("client %d.%u missed a callback notification",
272 msg->instance_id, msg->handle);
275 wf = mrp_allocz(sizeof(struct watched_file));
280 wf->watched_file = mrp_strdup(rd_filename);
282 wf->instance_id = msg->instance_id;
283 wf->handle = msg->handle;
284 wf->wd = mrp_add_io_watch(ctx->ml, rd_fd, MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP,
287 mrp_htbl_insert(ctx->watched_files, wf->watched_file, wf);
291 /* encode the data for sending */
294 data |= msg->sound_command << 16;
295 data |= msg->event_source << 24;
297 ret = write(wr_fd, &data, sizeof(uint32_t));
299 if (ret < (int) sizeof(uint32_t)) {
300 mrp_log_error("failed to write callback data to %d.%u",
301 msg->instance_id, msg->handle);
310 if (wf && wf->watched_file) {
311 mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
323 #undef ASM_FILENAME_SIZE
327 static void recvfrom_murphy(mrp_transport_t *t, void *data, uint16_t tag,
328 mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
330 ctx_t *ctx = user_data;
339 asm_to_lib_t *res = data;
340 ASM_msg_asm_to_lib_t msg;
342 msg.instance_id = res->instance_id;
343 msg.data.alloc_handle = res->alloc_handle;
344 msg.data.cmd_handle = res->cmd_handle;
345 msg.data.result_sound_command = res->result_sound_command;
346 msg.data.result_sound_state = res->result_sound_state;
348 msg.data.check_privilege = res->check_privilege;
351 if (msgsnd(ctx->snd_msgq, (void *) &msg,
352 sizeof(msg.data), 0) < 0) {
353 mrp_log_error("failed to send message to client");
358 case TAG_ASM_TO_LIB_CB:
360 if (send_callback_to_client(data, ctx) < 0) {
361 mrp_log_error("failed to send callback message to client");
367 mrp_log_error("Unknown message received!");
373 static void recv_murphy(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
375 recvfrom_murphy(t, data, tag, NULL, 0, user_data);
379 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
381 ctx_t *ctx = user_data;
386 mrp_log_error("server closed the connection");
388 mrp_mainloop_quit(ctx->ml, 0);
392 static int connect_to_murphy(char *address, ctx_t *ctx)
398 static mrp_transport_evt_t evt = {
399 { .recvdata = recv_murphy },
400 { .recvdatafrom = recvfrom_murphy },
401 .closed = closed_evt,
405 if (!mrp_msg_register_type(&lib_to_asm_descr) ||
406 !mrp_msg_register_type(&asm_to_lib_descr) ||
407 !mrp_msg_register_type(&asm_to_lib_cb_descr) ||
408 !mrp_msg_register_type(&lib_to_asm_cb_descr)) {
409 mrp_log_error("Failed to register message types");
413 alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype);
416 mrp_log_error("Error resolving transport address");
420 ctx->mt = mrp_transport_create(ctx->ml, atype, &evt, ctx,
421 MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK);
423 if (ctx->mt == NULL) {
424 mrp_log_error("Failed to create the transport");
428 if (!mrp_transport_connect(ctx->mt, &addr, alen)) {
429 mrp_log_error("Failed to connect the transport");
437 mrp_transport_destroy(ctx->mt);
442 static void htbl_free_watches(void *key, void *object)
444 struct watched_file *wf = object;
448 mrp_free(wf->watched_file);
450 mrp_del_io_watch(wf->wd);
456 int main (int argc, char **argv)
458 pthread_t thread = 0;
462 mrp_io_watch_t *iow = NULL;
463 mrp_io_event_t events = MRP_IO_EVENT_IN;
465 int asm_snd_msgid = msgget((key_t)4102, 0666 | IPC_CREAT);
466 int asm_rcv_msgid = msgget((key_t)2014, 0666 | IPC_CREAT);
468 mrp_htbl_config_t watches_conf;
471 ctx.watched_files = NULL;
473 /* set up the signal handling */
475 if (asm_snd_msgid == -1 || asm_rcv_msgid == -1) {
476 mrp_log_error("failed to create the message queues\n");
482 ctx.snd_msgq = asm_snd_msgid;
484 if (argc != 2 || strncmp(argv[1], "unxs", 4) != 0) {
485 mrp_log_error("Usage: asm-bridge <socket_name>");
489 watches_conf.comp = mrp_string_comp;
490 watches_conf.hash = mrp_string_hash;
491 watches_conf.free = htbl_free_watches;
492 watches_conf.nbucket = 0;
493 watches_conf.nentry = 10;
495 ctx.watched_files = mrp_htbl_create(&watches_conf);
497 ctx.ml = mrp_mainloop_create();
499 /* Initialize connection to murphyd */
501 if (connect_to_murphy(argv[1], &ctx) < 0) {
505 /* create a pipe for communicating with the ASM thread */
507 if (pipe(pipes) == -1) {
511 /* pass the message queue and the pipe writing end to the thread */
513 thread_arg[0] = asm_rcv_msgid;
514 thread_arg[1] = pipes[1];
516 /* start listening to the read end of the pipe */
518 iow = mrp_add_io_watch(ctx.ml, pipes[0], events, pipe_cb, &ctx);
524 pthread_create(&thread, NULL, wait_queue, thread_arg);
526 /* start processing events */
528 mrp_mainloop_run(ctx.ml);
530 mrp_log_warning("shutting down asm-bridge");
534 mrp_del_io_watch(iow);
536 if (ctx.watched_files) {
537 mrp_htbl_destroy(ctx.watched_files, TRUE);
541 pthread_cancel(thread);
542 pthread_join(thread, &res);
545 /* free the message queues */
547 msgctl(asm_snd_msgid, IPC_RMID, 0);
548 msgctl(asm_rcv_msgid, IPC_RMID, 0);