/src/adhd/cras/server/main_message.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2015 The ChromiumOS Authors |
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 "cras/server/main_message.h" |
7 | | |
8 | | #include <errno.h> |
9 | | #include <linux/limits.h> |
10 | | #include <stdint.h> |
11 | | #include <stdio.h> |
12 | | #include <stdlib.h> |
13 | | #include <syslog.h> |
14 | | #include <unistd.h> |
15 | | |
16 | | #include "cras/common/check.h" |
17 | | #include "cras_util.h" |
18 | | #include "third_party/utlist/utlist.h" |
19 | | |
20 | | static_assert(CRAS_MAIN_MESSAGE_MAX_LENGTH <= PIPE_BUF, |
21 | | "CRAS_MAIN_MESSAGE_MAX_LENGTH must not be longer than PIPE_BUF " |
22 | | "to ensure atomic writes"); |
23 | | |
24 | | // Callback to handle specific type of main thread message. |
25 | | struct cras_main_msg_callback { |
26 | | enum CRAS_MAIN_MESSAGE_TYPE type; |
27 | | cras_message_callback callback; |
28 | | void* callback_data; |
29 | | struct cras_main_msg_callback *prev, *next; |
30 | | }; |
31 | | |
32 | | static int main_msg_fds[2] = {-1, -1}; |
33 | | static struct cras_main_msg_callback* main_msg_callbacks; |
34 | | |
35 | | int cras_main_message_add_handler(enum CRAS_MAIN_MESSAGE_TYPE type, |
36 | | cras_message_callback callback, |
37 | 397 | void* callback_data) { |
38 | 397 | struct cras_main_msg_callback* msg_cb; |
39 | | |
40 | 397 | DL_FOREACH (main_msg_callbacks, msg_cb) { |
41 | 393 | if (msg_cb->type == type) { |
42 | 0 | syslog(LOG_ERR, "Main message type %u already exists", type); |
43 | 0 | return -EEXIST; |
44 | 0 | } |
45 | 393 | } |
46 | | |
47 | 397 | msg_cb = (struct cras_main_msg_callback*)calloc(1, sizeof(*msg_cb)); |
48 | 397 | msg_cb->type = type; |
49 | 397 | msg_cb->callback = callback; |
50 | 397 | msg_cb->callback_data = callback_data; |
51 | | |
52 | 397 | DL_APPEND(main_msg_callbacks, msg_cb); |
53 | 397 | return 0; |
54 | 397 | } |
55 | | |
56 | 393 | void cras_main_message_rm_handler(enum CRAS_MAIN_MESSAGE_TYPE type) { |
57 | 393 | struct cras_main_msg_callback* cb; |
58 | | |
59 | 786 | DL_FOREACH (main_msg_callbacks, cb) { |
60 | 786 | if (cb->type == type) { |
61 | 393 | DL_DELETE(main_msg_callbacks, cb); |
62 | 393 | free(cb); |
63 | 393 | break; |
64 | 393 | } |
65 | 786 | } |
66 | 393 | } |
67 | | |
68 | 1.05k | int cras_main_message_send(struct cras_main_message* msg) { |
69 | 1.05k | CRAS_CHECK(msg->length <= CRAS_MAIN_MESSAGE_MAX_LENGTH && "message too long"); |
70 | | |
71 | 1.05k | int err = write(main_msg_fds[1], msg, msg->length); |
72 | 1.05k | if (err < 0) { |
73 | 1.05k | syslog(LOG_ERR, "Failed to send main message, type %u", msg->type); |
74 | 1.05k | return err; |
75 | 1.05k | } |
76 | 0 | return 0; |
77 | 1.05k | } |
78 | | |
79 | 0 | static int read_main_message(int msg_fd, uint8_t* buf, size_t max_len) { |
80 | 0 | int to_read, nread, rc; |
81 | 0 | struct cras_main_message* msg = (struct cras_main_message*)buf; |
82 | |
|
83 | 0 | nread = read(msg_fd, buf, sizeof(msg->length)); |
84 | 0 | if (nread < 0) { |
85 | 0 | return nread; |
86 | 0 | } |
87 | 0 | if (msg->length > max_len) { |
88 | 0 | return -ENOMEM; |
89 | 0 | } |
90 | | |
91 | 0 | to_read = msg->length - nread; |
92 | 0 | rc = read(msg_fd, &buf[0] + nread, to_read); |
93 | 0 | if (rc < 0) { |
94 | 0 | return rc; |
95 | 0 | } |
96 | 0 | return 0; |
97 | 0 | } |
98 | | |
99 | 0 | void handle_main_messages(void* arg, int revents) { |
100 | 0 | uint8_t buf[CRAS_MAIN_MESSAGE_MAX_LENGTH]; |
101 | 0 | int rc; |
102 | 0 | struct cras_main_msg_callback* main_msg_cb; |
103 | 0 | struct cras_main_message* msg = (struct cras_main_message*)buf; |
104 | |
|
105 | 0 | rc = read_main_message(main_msg_fds[0], buf, sizeof(buf)); |
106 | 0 | if (rc < 0) { |
107 | 0 | syslog(LOG_ERR, "Failed to read main message"); |
108 | 0 | return; |
109 | 0 | } |
110 | | |
111 | 0 | DL_FOREACH (main_msg_callbacks, main_msg_cb) { |
112 | 0 | if (main_msg_cb->type == msg->type) { |
113 | 0 | main_msg_cb->callback(msg, main_msg_cb->callback_data); |
114 | 0 | break; |
115 | 0 | } |
116 | 0 | } |
117 | 0 | } |
118 | | |
119 | 0 | int cras_main_message_init() { |
120 | 0 | int rc; |
121 | |
|
122 | 0 | rc = pipe(main_msg_fds); |
123 | 0 | if (rc < 0) { |
124 | 0 | syslog(LOG_ERR, "Fatal: main message init"); |
125 | 0 | exit(-ENOMEM); |
126 | 0 | } |
127 | | |
128 | | // When full it's preferred to get error instead of blocked. |
129 | 0 | cras_make_fd_nonblocking(main_msg_fds[0]); |
130 | 0 | cras_make_fd_nonblocking(main_msg_fds[1]); |
131 | |
|
132 | 0 | return main_msg_fds[0]; |
133 | 0 | } |