Home | History | Annotate | Download | only in server
      1 /* Copyright (c) 2015 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 #include <errno.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <syslog.h>
     10 
     11 #include "cras_main_message.h"
     12 #include "cras_system_state.h"
     13 #include "cras_util.h"
     14 
     15 
     16 /* Callback to handle specific type of main thread message. */
     17 struct cras_main_msg_callback {
     18 	enum CRAS_MAIN_MESSAGE_TYPE type;
     19 	cras_message_callback callback;
     20 	void *callback_data;
     21 	struct cras_main_msg_callback *prev, *next;
     22 };
     23 
     24 static int main_msg_fds[2];
     25 static struct cras_main_msg_callback *main_msg_callbacks;
     26 
     27 int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type,
     28 				  cras_message_callback callback,
     29 				  void *callback_data)
     30 {
     31 	struct cras_main_msg_callback *msg_cb;
     32 
     33 	DL_FOREACH(main_msg_callbacks, msg_cb) {
     34 		if (msg_cb->type == type) {
     35 			syslog(LOG_ERR, "Main message type %u already exists",
     36 			       type);
     37 			return -EEXIST;
     38 		}
     39 	}
     40 
     41 	msg_cb = (struct cras_main_msg_callback *)calloc(1, sizeof(*msg_cb));
     42 	msg_cb->type = type;
     43 	msg_cb->callback = callback;
     44 	msg_cb->callback_data = callback_data;
     45 
     46 	DL_APPEND(main_msg_callbacks, msg_cb);
     47 	return 0;
     48 }
     49 
     50 int cras_main_message_send(struct cras_main_message *msg)
     51 {
     52 	int err;
     53 
     54 	err = write(main_msg_fds[1], msg, msg->length);
     55 	if (err < 0) {
     56 		syslog(LOG_ERR, "Failed to send main message, type %u",
     57 		       msg->type);
     58 		return err;
     59 	}
     60 	return 0;
     61 }
     62 
     63 static int read_main_message(int msg_fd, uint8_t *buf, size_t max_len) {
     64 	int to_read, nread, rc;
     65 	struct cras_main_message *msg = (struct cras_main_message *)buf;
     66 
     67 	nread = read(msg_fd, buf, sizeof(msg->length));
     68 	if (nread < 0)
     69 		return nread;
     70 	if (msg->length > max_len)
     71 		return -ENOMEM;
     72 
     73 	to_read = msg->length - nread;
     74 	rc = read(msg_fd, &buf[0] + nread, to_read);
     75 	if (rc < 0)
     76 		return rc;
     77 	return 0;
     78 }
     79 
     80 static void handle_main_messages(void *arg)
     81 {
     82 	uint8_t buf[256];
     83 	int rc;
     84 	struct cras_main_msg_callback *main_msg_cb;
     85 	struct cras_main_message *msg = (struct cras_main_message *)buf;
     86 
     87 	rc = read_main_message(main_msg_fds[0], buf, sizeof(buf));
     88 	if (rc < 0) {
     89 		syslog(LOG_ERR, "Failed to read main message");
     90 		return;
     91 	}
     92 
     93 	DL_FOREACH(main_msg_callbacks, main_msg_cb) {
     94 		if (main_msg_cb->type == msg->type) {
     95 			main_msg_cb->callback(msg, main_msg_cb->callback_data);
     96 			break;
     97 		}
     98 	}
     99 }
    100 
    101 void cras_main_message_init() {
    102 	int rc;
    103 
    104 	rc = pipe(main_msg_fds);
    105 	if (rc < 0) {
    106 		syslog(LOG_ERR, "Fatal: main message init");
    107 		exit(-ENOMEM);
    108 	}
    109 
    110 	/* When full it's preferred to get error instead of blocked. */
    111 	cras_make_fd_nonblocking(main_msg_fds[0]);
    112 	cras_make_fd_nonblocking(main_msg_fds[1]);
    113 
    114 	cras_system_add_select_fd(main_msg_fds[0],
    115 				  handle_main_messages,
    116 				  NULL);
    117 }
    118