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;
68 static void *wait_queue (void *arg) {
69 ASM_msg_lib_to_asm_t msg;
71 int *arg_thread = arg;
73 int asm_rcv_msgid = arg_thread[0];
74 int fd = arg_thread[1];
76 if (asm_rcv_msgid == -1) {
77 mrp_log_error("failed to create the receive message queue\n");
82 int ret = msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, 0);
85 /* FIXME: proper error handling */
86 mrp_log_error("error receiving a message: '%s'!", strerror(errno));
87 /* remove message from queue */
88 msgrcv(asm_rcv_msgid, &msg, sizeof(msg.data), 0, MSG_NOERROR);
92 /* alignment is fine, since the first argument to the struct is a long */
93 write(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
100 static void dump_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
104 mrp_log_info("Message id %ld:", msg->instance_id);
106 mrp_log_info("Data handle: %d", msg->data.handle);
107 mrp_log_info(" request id: 0x%04x", msg->data.request_id);
108 mrp_log_info(" sound event: 0x%04x", msg->data.sound_event);
109 mrp_log_info(" sound state: 0x%04x", msg->data.sound_state);
110 mrp_log_info(" system resource: 0x%04x", msg->data.system_resource);
115 mrp_log_info(" cookie: ");
116 for (i = 0; i < COOKIE_SIZE; i++) {
117 mrp_log_info("0x%02x ", msg->data.cookie[i]);
125 static int process_msg(ASM_msg_lib_to_asm_t *msg, ctx_t *ctx)
128 uint8_t cookie_arr[] = {};
129 uint8_t *cookie = cookie_arr;
134 /* FIXME: instance_id is signed? */
135 res.instance_id = msg->instance_id;
136 res.handle = msg->data.handle;
137 res.request_id = msg->data.request_id;
138 res.sound_event = msg->data.sound_event;
139 res.sound_state = msg->data.sound_state;
140 res.system_resource = msg->data.system_resource;
143 cookie_len = COOKIE_SIZE;
144 cookie = msg->data.cookie;
148 res.n_cookie_bytes = cookie_len;
151 if (!mrp_transport_senddata(ctx->mt, &res, lib_to_asm_descr.tag)) {
152 mrp_log_error("Failed to send message to murphy");
160 static void pipe_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
161 mrp_io_event_t events, void *user_data)
163 ASM_msg_lib_to_asm_t msg;
164 ctx_t *ctx = user_data;
172 bytes = read(fd, &msg, sizeof(ASM_msg_lib_to_asm_t));
174 if (bytes != sizeof(ASM_msg_lib_to_asm_t)) {
175 mrp_log_error("failed to read from the pipe");
179 ret = process_msg(&msg, ctx);
182 mrp_log_error("error parsing or proxying message");
187 static void read_watch_cb(mrp_mainloop_t *ml, mrp_io_watch_t *w, int fd,
188 mrp_io_event_t events, void *user_data)
190 struct watched_file *wf = user_data;
191 ctx_t *ctx = wf->ctx;
196 if (events & MRP_IO_EVENT_IN) {
200 ret = read(fd, &buf, sizeof(uint32_t));
202 if (ret == sizeof(uint32_t)) {
205 msg.instance_id = wf->instance_id;
206 msg.handle = wf->handle;
209 if (!mrp_transport_senddata(ctx->mt, &msg, lib_to_asm_cb_descr.tag)) {
210 mrp_log_error("Failed to send message to murphy");
214 if (events & MRP_IO_EVENT_HUP) {
215 /* can we assume that the client went away? */
216 mrp_log_error("HUP event from client");
219 mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
224 static int send_callback_to_client(asm_to_lib_cb_t *msg, ctx_t *ctx)
226 #define ASM_FILENAME_SIZE 64
227 char wr_filename[ASM_FILENAME_SIZE];
228 char rd_filename[ASM_FILENAME_SIZE];
235 struct watched_file *wf = NULL;
237 ret = snprintf(wr_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%u",
238 msg->instance_id, msg->handle);
240 if (ret <= 0 || ret == ASM_FILENAME_SIZE)
243 mrp_log_info("writing client preemption to file %s", wr_filename);
245 wr_fd = open(wr_filename, O_NONBLOCK | O_WRONLY);
247 mrp_log_error("failed to open file '%s' for writing: '%s'", wr_filename,
252 if (msg->callback_expected) {
254 ret = snprintf(rd_filename, ASM_FILENAME_SIZE, "/tmp/ASM.%d.%ur",
255 msg->instance_id, msg->handle);
257 if (ret <= 0 || ret == ASM_FILENAME_SIZE)
260 rd_fd = open(wr_filename, O_NONBLOCK | O_RDONLY);
262 mrp_log_error("failed to open file '%s' for reading: '%s'",
263 rd_filename, strerror(errno));
267 wf = mrp_htbl_lookup(ctx->watched_files, rd_filename);
270 /* already watched, this is a bad thing */
272 mrp_log_error("client %d.%u missed a callback notification",
273 msg->instance_id, msg->handle);
277 wf = mrp_allocz(sizeof(struct watched_file));
279 wf->watched_file = mrp_strdup(rd_filename);
281 wf->instance_id = msg->instance_id;
282 wf->handle = msg->handle;
283 wf->wd = mrp_add_io_watch(ctx->ml, rd_fd, MRP_IO_EVENT_IN | MRP_IO_EVENT_HUP,
286 mrp_htbl_insert(ctx->watched_files, wf->watched_file, wf);
290 /* encode the data for sending */
293 data |= msg->sound_command << 16;
294 data |= msg->event_source << 24;
296 ret = write(wr_fd, &data, sizeof(uint32_t));
298 if (ret < (int) sizeof(uint32_t)) {
299 mrp_log_error("failed to write callback data to %d.%u",
300 msg->instance_id, msg->handle);
309 if (wf && wf->watched_file) {
310 mrp_htbl_remove(ctx->watched_files, wf->watched_file, TRUE);
322 #undef ASM_FILENAME_SIZE
326 static void recvfrom_murphy(mrp_transport_t *t, void *data, uint16_t tag,
327 mrp_sockaddr_t *addr, socklen_t addrlen, void *user_data)
329 ctx_t *ctx = user_data;
338 asm_to_lib_t *res = data;
339 ASM_msg_asm_to_lib_t msg;
341 msg.instance_id = res->instance_id;
342 msg.data.alloc_handle = res->alloc_handle;
343 msg.data.cmd_handle = res->cmd_handle;
344 msg.data.result_sound_command = res->result_sound_command;
345 msg.data.result_sound_state = res->result_sound_state;
347 msg.data.check_privilege = res->check_privilege;
350 if (msgsnd(ctx->snd_msgq, (void *) &msg,
351 sizeof(msg.data), 0) < 0) {
352 mrp_log_error("failed to send message to client");
357 case TAG_ASM_TO_LIB_CB:
359 if (send_callback_to_client(data, ctx) < 0) {
360 mrp_log_error("failed to send callback message to client");
366 mrp_log_error("Unknown message received!");
372 static void recv_murphy(mrp_transport_t *t, void *data, uint16_t tag, void *user_data)
374 recvfrom_murphy(t, data, tag, NULL, 0, user_data);
378 static void closed_evt(mrp_transport_t *t, int error, void *user_data)
380 ctx_t *ctx = user_data;
385 mrp_log_error("server closed the connection");
387 mrp_mainloop_quit(ctx->ml, 0);
391 static int connect_to_murphy(char *address, ctx_t *ctx)
397 static mrp_transport_evt_t evt = {
398 { .recvdata = recv_murphy },
399 { .recvdatafrom = recvfrom_murphy },
400 .closed = closed_evt,
404 if (!mrp_msg_register_type(&lib_to_asm_descr) ||
405 !mrp_msg_register_type(&asm_to_lib_descr) ||
406 !mrp_msg_register_type(&asm_to_lib_cb_descr) ||
407 !mrp_msg_register_type(&lib_to_asm_cb_descr)) {
408 mrp_log_error("Failed to register message types");
412 alen = mrp_transport_resolve(NULL, address, &addr, sizeof(addr), &atype);
415 mrp_log_error("Error resolving transport address");
419 ctx->mt = mrp_transport_create(ctx->ml, atype, &evt, ctx,
420 MRP_TRANSPORT_MODE_CUSTOM | MRP_TRANSPORT_NONBLOCK);
422 if (ctx->mt == NULL) {
423 mrp_log_error("Failed to create the transport");
428 if (!mrp_transport_bind(ctx->mt, &addr, alen)) {
429 mrp_log_error("Failed to bind the transport to address '%s'", address);
434 if (!mrp_transport_connect(ctx->mt, &addr, alen)) {
435 mrp_log_error("Failed to connect the transport");
443 mrp_transport_destroy(ctx->mt);
448 static void htbl_free_watches(void *key, void *object)
450 struct watched_file *wf = object;
454 mrp_free(wf->watched_file);
456 mrp_del_io_watch(wf->wd);
462 int main (int argc, char **argv)
464 pthread_t thread = 0;
468 mrp_io_watch_t *iow = NULL;
469 mrp_io_event_t events = MRP_IO_EVENT_IN;
471 int asm_snd_msgid = msgget((key_t)4102, 0666 | IPC_CREAT);
472 int asm_rcv_msgid = msgget((key_t)2014, 0666 | IPC_CREAT);
474 mrp_htbl_config_t watches_conf;
478 /* set up the signal handling */
480 if (asm_snd_msgid == -1 || asm_rcv_msgid == -1) {
481 mrp_log_error("failed to create the message queues\n");
487 ctx.snd_msgq = asm_snd_msgid;
489 if (argc != 2 || strncmp(argv[1], "unxs", 4) != 0) {
490 mrp_log_error("Usage: asm-bridge <socket_name>");
494 watches_conf.comp = mrp_string_comp;
495 watches_conf.hash = mrp_string_hash;
496 watches_conf.free = htbl_free_watches;
497 watches_conf.nbucket = 0;
498 watches_conf.nentry = 10;
500 ctx.watched_files = mrp_htbl_create(&watches_conf);
502 ctx.ml = mrp_mainloop_create();
504 /* Initialize connection to murphyd */
506 if (connect_to_murphy(argv[1], &ctx) < 0) {
510 /* create a pipe for communicating with the ASM thread */
512 if (pipe(pipes) == -1) {
516 /* pass the message queue and the pipe writing end to the thread */
518 thread_arg[0] = asm_rcv_msgid;
519 thread_arg[1] = pipes[1];
521 /* start listening to the read end of the pipe */
523 iow = mrp_add_io_watch(ctx.ml, pipes[0], events, pipe_cb, &ctx);
529 pthread_create(&thread, NULL, wait_queue, thread_arg);
531 /* start processing events */
533 mrp_mainloop_run(ctx.ml);
535 mrp_log_warning("shutting down asm-bridge");
539 mrp_del_io_watch(iow);
541 if (ctx.watched_files) {
542 mrp_htbl_destroy(ctx.watched_files, TRUE);
546 pthread_cancel(thread);
547 pthread_join(thread, &res);
550 /* free the message queues */
552 msgctl(asm_snd_msgid, IPC_RMID, 0);
553 msgctl(asm_rcv_msgid, IPC_RMID, 0);