1 /******************************************************************************
2 *
3 * Copyright 2009-2012 Broadcom Corporation
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 /*****************************************************************************
20 *
21 * Filename: uipc.cc
22 *
23 * Description: UIPC implementation for fluoride
24 *
25 *****************************************************************************/
26
27 #define LOG_TAG "uipc"
28
29 #include "udrv/include/uipc.h"
30
31 #include <bluetooth/log.h>
32 #include <fcntl.h>
33 #include <poll.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/mman.h>
37 #include <sys/prctl.h>
38 #include <sys/select.h>
39 #include <sys/socket.h>
40 #include <sys/stat.h>
41 #include <sys/un.h>
42 #include <unistd.h>
43
44 #include <cerrno>
45 #include <mutex>
46
47 #include "osi/include/osi.h"
48 #include "osi/include/socket_utils/sockets.h"
49
50 // TODO(b/369381361) Enfore -Wmissing-prototypes
51 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
52
53 using namespace bluetooth;
54
55 /*****************************************************************************
56 * Constants & Macros
57 *****************************************************************************/
58
59 // AUDIO_STREAM_OUTPUT_BUFFER_SZ controls the size of the audio socket buffer.
60 // If one assumes the write buffer is always full during normal BT playback,
61 // then increasing this value increases our playback latency.
62 //
63 // FIXME: The BT HAL should consume data at a constant rate.
64 // AudioFlinger assumes that the HAL draws data at a constant rate, which is
65 // true for most audio devices; however, the BT engine reads data at a variable
66 // rate (over the short term), which confuses both AudioFlinger as well as
67 // applications which deliver data at a (generally) fixed rate.
68 //
69 // 20 * 512 is not sufficient to smooth the variability for some BT devices,
70 // resulting in mixer sleep and throttling. We increase this to 28 * 512 to help
71 // reduce the effect of variable data consumption.
72 #define AUDIO_STREAM_OUTPUT_BUFFER_SZ (28 * 512)
73
74 #define MAX(a, b) ((a) > (b) ? (a) : (b))
75
76 #define CASE_RETURN_STR(const) \
77 case const: \
78 return #const;
79
80 #define UIPC_DISCONNECTED (-1)
81
82 #define SAFE_FD_ISSET(fd, set) (((fd) == -1) ? false : FD_ISSET((fd), (set)))
83
84 #define UIPC_FLUSH_BUFFER_SIZE 1024
85
86 /*****************************************************************************
87 * Local type definitions
88 *****************************************************************************/
89
90 typedef enum {
91 UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
92 } tUIPC_TASK_FLAGS;
93
94 /*****************************************************************************
95 * Static functions
96 *****************************************************************************/
97 static int uipc_close_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id);
98
99 /*****************************************************************************
100 * Externs
101 *****************************************************************************/
102
103 /*****************************************************************************
104 * Helper functions
105 *****************************************************************************/
106
dump_uipc_event(tUIPC_EVENT event)107 const char* dump_uipc_event(tUIPC_EVENT event) {
108 switch (event) {
109 CASE_RETURN_STR(UIPC_OPEN_EVT)
110 CASE_RETURN_STR(UIPC_CLOSE_EVT)
111 CASE_RETURN_STR(UIPC_RX_DATA_EVT)
112 CASE_RETURN_STR(UIPC_RX_DATA_READY_EVT)
113 CASE_RETURN_STR(UIPC_TX_DATA_READY_EVT)
114 default:
115 return "UNKNOWN MSG ID";
116 }
117 }
118
119 /*****************************************************************************
120 * socket helper functions
121 ****************************************************************************/
122
create_server_socket(const char * name)123 static inline int create_server_socket(const char* name) {
124 int s = socket(AF_LOCAL, SOCK_STREAM, 0);
125 if (s < 0) {
126 return -1;
127 }
128
129 log::debug("create_server_socket {}", name);
130
131 if (osi_socket_local_server_bind(s, name,
132 #ifdef __ANDROID__
133 ANDROID_SOCKET_NAMESPACE_ABSTRACT
134 #else // !__ANDROID__
135 ANDROID_SOCKET_NAMESPACE_FILESYSTEM
136 #endif // __ANDROID__
137 ) < 0) {
138 log::debug("socket failed to create ({})", strerror(errno));
139 close(s);
140 return -1;
141 }
142
143 if (listen(s, 5) < 0) {
144 log::debug("listen failed: {}", strerror(errno));
145 close(s);
146 return -1;
147 }
148
149 log::debug("created socket fd {}", s);
150 return s;
151 }
152
accept_server_socket(int sfd)153 static int accept_server_socket(int sfd) {
154 struct sockaddr_un remote;
155 struct pollfd pfd;
156 int fd;
157 socklen_t len = sizeof(struct sockaddr_un);
158
159 log::debug("accept fd {}", sfd);
160
161 /* make sure there is data to process */
162 pfd.fd = sfd;
163 pfd.events = POLLIN;
164
165 int poll_ret;
166 OSI_NO_INTR(poll_ret = poll(&pfd, 1, 0));
167 if (poll_ret == 0) {
168 log::warn("accept poll timeout");
169 return -1;
170 }
171
172 OSI_NO_INTR(fd = accept(sfd, (struct sockaddr*)&remote, &len));
173 if (fd == -1) {
174 log::error("sock accept failed ({})", strerror(errno));
175 return -1;
176 }
177
178 // match socket buffer size option with client
179 const int size = AUDIO_STREAM_OUTPUT_BUFFER_SZ;
180 int ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&size, (int)sizeof(size));
181 if (ret < 0) {
182 log::error("setsockopt failed ({})", strerror(errno));
183 }
184
185 return fd;
186 }
187
188 /*****************************************************************************
189 *
190 * uipc helper functions
191 *
192 ****************************************************************************/
193
uipc_main_init(tUIPC_STATE & uipc)194 static int uipc_main_init(tUIPC_STATE& uipc) {
195 int i;
196
197 log::debug("### uipc_main_init ###");
198
199 uipc.tid = 0;
200 uipc.running = 0;
201 memset(&uipc.active_set, 0, sizeof(uipc.active_set));
202 memset(&uipc.read_set, 0, sizeof(uipc.read_set));
203 uipc.max_fd = 0;
204 memset(&uipc.signal_fds, 0, sizeof(uipc.signal_fds));
205 memset(&uipc.ch, 0, sizeof(uipc.ch));
206
207 /* setup interrupt socket pair */
208 if (socketpair(AF_UNIX, SOCK_STREAM, 0, uipc.signal_fds) < 0) {
209 return -1;
210 }
211
212 FD_SET(uipc.signal_fds[0], &uipc.active_set);
213 uipc.max_fd = MAX(uipc.max_fd, uipc.signal_fds[0]);
214
215 for (i = 0; i < UIPC_CH_NUM; i++) {
216 tUIPC_CHAN* p = &uipc.ch[i];
217 p->srvfd = UIPC_DISCONNECTED;
218 p->fd = UIPC_DISCONNECTED;
219 p->task_evt_flags = 0;
220 p->cback = NULL;
221 }
222
223 return 0;
224 }
225
uipc_main_cleanup(tUIPC_STATE & uipc)226 void uipc_main_cleanup(tUIPC_STATE& uipc) {
227 int i;
228
229 log::debug("uipc_main_cleanup");
230
231 close(uipc.signal_fds[0]);
232 close(uipc.signal_fds[1]);
233
234 /* close any open channels */
235 for (i = 0; i < UIPC_CH_NUM; i++) {
236 uipc_close_ch_locked(uipc, i);
237 }
238 }
239
240 /* check pending events in read task */
uipc_check_task_flags_locked(tUIPC_STATE & uipc)241 static void uipc_check_task_flags_locked(tUIPC_STATE& uipc) {
242 int i;
243
244 for (i = 0; i < UIPC_CH_NUM; i++) {
245 if (uipc.ch[i].task_evt_flags & UIPC_TASK_FLAG_DISCONNECT_CHAN) {
246 uipc.ch[i].task_evt_flags &= ~UIPC_TASK_FLAG_DISCONNECT_CHAN;
247 uipc_close_ch_locked(uipc, i);
248 }
249
250 /* add here */
251 }
252 }
253
uipc_check_fd_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)254 static int uipc_check_fd_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
255 if (ch_id >= UIPC_CH_NUM) {
256 return -1;
257 }
258
259 if (SAFE_FD_ISSET(uipc.ch[ch_id].srvfd, &uipc.read_set)) {
260 log::debug("INCOMING CONNECTION ON CH {}", ch_id);
261
262 // Close the previous connection
263 if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
264 log::debug("CLOSE CONNECTION (FD {})", uipc.ch[ch_id].fd);
265 close(uipc.ch[ch_id].fd);
266 FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
267 uipc.ch[ch_id].fd = UIPC_DISCONNECTED;
268 }
269
270 uipc.ch[ch_id].fd = accept_server_socket(uipc.ch[ch_id].srvfd);
271
272 log::debug("NEW FD {}", uipc.ch[ch_id].fd);
273
274 if ((uipc.ch[ch_id].fd >= 0) && uipc.ch[ch_id].cback) {
275 /* if we have a callback we should add this fd to the active set
276 and notify user with callback event */
277 log::debug("ADD FD {} TO ACTIVE SET", uipc.ch[ch_id].fd);
278 FD_SET(uipc.ch[ch_id].fd, &uipc.active_set);
279 uipc.max_fd = MAX(uipc.max_fd, uipc.ch[ch_id].fd);
280 }
281
282 if (uipc.ch[ch_id].fd < 0) {
283 log::error("FAILED TO ACCEPT CH {}", ch_id);
284 return -1;
285 }
286
287 if (uipc.ch[ch_id].cback) {
288 uipc.ch[ch_id].cback(ch_id, UIPC_OPEN_EVT);
289 }
290 }
291
292 if (SAFE_FD_ISSET(uipc.ch[ch_id].fd, &uipc.read_set)) {
293 if (uipc.ch[ch_id].cback) {
294 uipc.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
295 }
296 }
297 return 0;
298 }
299
uipc_check_interrupt_locked(tUIPC_STATE & uipc)300 static void uipc_check_interrupt_locked(tUIPC_STATE& uipc) {
301 if (SAFE_FD_ISSET(uipc.signal_fds[0], &uipc.read_set)) {
302 char sig_recv = 0;
303 OSI_NO_INTR(recv(uipc.signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL));
304 }
305 }
306
uipc_wakeup_locked(tUIPC_STATE & uipc)307 static inline void uipc_wakeup_locked(tUIPC_STATE& uipc) {
308 char sig_on = 1;
309 log::debug("UIPC SEND WAKE UP");
310
311 OSI_NO_INTR(send(uipc.signal_fds[1], &sig_on, sizeof(sig_on), 0));
312 }
313
uipc_setup_server_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id,const char * name,tUIPC_RCV_CBACK * cback)314 static int uipc_setup_server_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, const char* name,
315 tUIPC_RCV_CBACK* cback) {
316 int fd;
317
318 log::debug("SETUP CHANNEL SERVER {}", ch_id);
319
320 if (ch_id >= UIPC_CH_NUM) {
321 return -1;
322 }
323
324 std::lock_guard<std::recursive_mutex> guard(uipc.mutex);
325
326 fd = create_server_socket(name);
327
328 if (fd < 0) {
329 log::error("failed to setup {}: {}", name, strerror(errno));
330 return -1;
331 }
332
333 log::debug("ADD SERVER FD TO ACTIVE SET {}", fd);
334 FD_SET(fd, &uipc.active_set);
335 uipc.max_fd = MAX(uipc.max_fd, fd);
336
337 uipc.ch[ch_id].srvfd = fd;
338 uipc.ch[ch_id].cback = cback;
339 uipc.ch[ch_id].read_poll_tmo_ms = DEFAULT_READ_POLL_TMO_MS;
340
341 /* trigger main thread to update read set */
342 uipc_wakeup_locked(uipc);
343
344 return 0;
345 }
346
uipc_flush_ch_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)347 static void uipc_flush_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
348 char buf[UIPC_FLUSH_BUFFER_SIZE];
349 struct pollfd pfd;
350
351 pfd.events = POLLIN;
352 pfd.fd = uipc.ch[ch_id].fd;
353
354 if (uipc.ch[ch_id].fd == UIPC_DISCONNECTED) {
355 log::debug("fd disconnected. Exiting");
356 return;
357 }
358
359 while (1) {
360 int ret;
361 OSI_NO_INTR(ret = poll(&pfd, 1, 1));
362 if (ret == 0) {
363 log::verbose("poll() timeout - nothing to do. Exiting");
364 return;
365 }
366 if (ret < 0) {
367 log::warn("poll() failed: return {} errno {} ({}). Exiting", ret, errno, strerror(errno));
368 return;
369 }
370 log::verbose("polling fd {}, revents: 0x{:x}, ret {}", pfd.fd, pfd.revents, ret);
371 if (pfd.revents & (POLLERR | POLLHUP)) {
372 log::warn("POLLERR or POLLHUP. Exiting");
373 return;
374 }
375
376 /* read sufficiently large buffer to ensure flush empties socket faster than
377 it is getting refilled */
378 (void)read(pfd.fd, &buf, UIPC_FLUSH_BUFFER_SIZE);
379 }
380 }
381
uipc_flush_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)382 static void uipc_flush_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
383 if (ch_id >= UIPC_CH_NUM) {
384 return;
385 }
386
387 switch (ch_id) {
388 case UIPC_CH_ID_AV_CTRL:
389 uipc_flush_ch_locked(uipc, UIPC_CH_ID_AV_CTRL);
390 break;
391
392 case UIPC_CH_ID_AV_AUDIO:
393 uipc_flush_ch_locked(uipc, UIPC_CH_ID_AV_AUDIO);
394 break;
395 }
396 }
397
uipc_close_ch_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)398 static int uipc_close_ch_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
399 int wakeup = 0;
400
401 log::debug("CLOSE CHANNEL {}", ch_id);
402
403 if (ch_id >= UIPC_CH_NUM) {
404 return -1;
405 }
406
407 if (uipc.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
408 log::debug("CLOSE SERVER (FD {})", uipc.ch[ch_id].srvfd);
409 close(uipc.ch[ch_id].srvfd);
410 FD_CLR(uipc.ch[ch_id].srvfd, &uipc.active_set);
411 uipc.ch[ch_id].srvfd = UIPC_DISCONNECTED;
412 wakeup = 1;
413 }
414
415 if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
416 log::debug("CLOSE CONNECTION (FD {})", uipc.ch[ch_id].fd);
417 close(uipc.ch[ch_id].fd);
418 FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
419 uipc.ch[ch_id].fd = UIPC_DISCONNECTED;
420 wakeup = 1;
421 }
422
423 /* notify this connection is closed */
424 if (uipc.ch[ch_id].cback) {
425 uipc.ch[ch_id].cback(ch_id, UIPC_CLOSE_EVT);
426 }
427
428 /* trigger main thread update if something was updated */
429 if (wakeup) {
430 uipc_wakeup_locked(uipc);
431 }
432
433 return 0;
434 }
435
uipc_close_locked(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)436 void uipc_close_locked(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
437 if (uipc.ch[ch_id].srvfd == UIPC_DISCONNECTED) {
438 log::debug("CHANNEL {} ALREADY CLOSED", ch_id);
439 return;
440 }
441
442 /* schedule close on this channel */
443 uipc.ch[ch_id].task_evt_flags |= UIPC_TASK_FLAG_DISCONNECT_CHAN;
444 uipc_wakeup_locked(uipc);
445 }
446
uipc_read_task(void * arg)447 static void* uipc_read_task(void* arg) {
448 tUIPC_STATE& uipc = *((tUIPC_STATE*)arg);
449 int ch_id;
450 int result;
451
452 prctl(PR_SET_NAME, (unsigned long)"uipc-main", 0, 0, 0);
453
454 while (uipc.running) {
455 uipc.read_set = uipc.active_set;
456
457 result = select(uipc.max_fd + 1, &uipc.read_set, NULL, NULL, NULL);
458
459 if (result == 0) {
460 log::debug("select timeout");
461 continue;
462 }
463 if (result < 0) {
464 if (errno != EINTR) {
465 log::debug("select failed {}", strerror(errno));
466 }
467 continue;
468 }
469
470 {
471 std::lock_guard<std::recursive_mutex> guard(uipc.mutex);
472
473 /* clear any wakeup interrupt */
474 uipc_check_interrupt_locked(uipc);
475
476 /* check pending task events */
477 uipc_check_task_flags_locked(uipc);
478
479 /* make sure we service audio channel first */
480 uipc_check_fd_locked(uipc, UIPC_CH_ID_AV_AUDIO);
481
482 /* check for other connections */
483 for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
484 if (ch_id != UIPC_CH_ID_AV_AUDIO) {
485 uipc_check_fd_locked(uipc, ch_id);
486 }
487 }
488 }
489 }
490
491 log::debug("UIPC READ THREAD EXITING");
492
493 uipc_main_cleanup(uipc);
494
495 uipc.tid = 0;
496
497 log::debug("UIPC READ THREAD DONE");
498
499 return nullptr;
500 }
501
uipc_start_main_server_thread(tUIPC_STATE & uipc)502 int uipc_start_main_server_thread(tUIPC_STATE& uipc) {
503 uipc.running = 1;
504
505 if (pthread_create(&uipc.tid, (const pthread_attr_t*)NULL, uipc_read_task, &uipc) != 0) {
506 log::error("uipc_thread_create pthread_create failed:{}", errno);
507 return -1;
508 }
509
510 return 0;
511 }
512
513 /* blocking call */
uipc_stop_main_server_thread(tUIPC_STATE & uipc)514 void uipc_stop_main_server_thread(tUIPC_STATE& uipc) {
515 /* request shutdown of read thread */
516 {
517 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
518 uipc.running = 0;
519 uipc_wakeup_locked(uipc);
520 }
521
522 /* wait until read thread is fully terminated */
523 /* tid might hold pointer value where it's value
524 is negative value with signed bit is set, so
525 corrected the logic to check zero or non zero */
526 if (uipc.tid) {
527 pthread_join(uipc.tid, NULL);
528 }
529 }
530
531 /*******************************************************************************
532 **
533 ** Function UIPC_Init
534 **
535 ** Description Initialize UIPC module
536 **
537 ** Returns void
538 **
539 ******************************************************************************/
UIPC_Init()540 std::unique_ptr<tUIPC_STATE> UIPC_Init() {
541 std::unique_ptr<tUIPC_STATE> uipc = std::make_unique<tUIPC_STATE>();
542 log::debug("UIPC_Init");
543
544 std::lock_guard<std::recursive_mutex> lock(uipc->mutex);
545
546 uipc_main_init(*uipc);
547 uipc_start_main_server_thread(*uipc);
548
549 return uipc;
550 }
551
552 /*******************************************************************************
553 **
554 ** Function UIPC_Open
555 **
556 ** Description Open UIPC interface
557 **
558 ** Returns true in case of success, false in case of failure.
559 **
560 ******************************************************************************/
UIPC_Open(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id,tUIPC_RCV_CBACK * p_cback,const char * socket_path)561 bool UIPC_Open(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, tUIPC_RCV_CBACK* p_cback,
562 const char* socket_path) {
563 log::debug("UIPC_Open : ch_id {}", ch_id);
564
565 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
566
567 if (ch_id >= UIPC_CH_NUM) {
568 return false;
569 }
570
571 if (uipc.ch[ch_id].srvfd != UIPC_DISCONNECTED) {
572 log::debug("CHANNEL {} ALREADY OPEN", ch_id);
573 return 0;
574 }
575
576 uipc_setup_server_locked(uipc, ch_id, socket_path, p_cback);
577
578 return true;
579 }
580
581 /*******************************************************************************
582 **
583 ** Function UIPC_Close
584 **
585 ** Description Close UIPC interface
586 **
587 ** Returns void
588 **
589 ******************************************************************************/
UIPC_Close(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id)590 void UIPC_Close(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id) {
591 log::debug("UIPC_Close : ch_id {}", ch_id);
592
593 /* special case handling uipc shutdown */
594 if (ch_id != UIPC_CH_ID_ALL) {
595 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
596 uipc_close_locked(uipc, ch_id);
597 return;
598 }
599
600 log::debug("UIPC_Close : waiting for shutdown to complete");
601 uipc_stop_main_server_thread(uipc);
602 log::debug("UIPC_Close : shutdown complete");
603 }
604
605 /*******************************************************************************
606 **
607 ** Function UIPC_Send
608 **
609 ** Description Called to transmit a message over UIPC.
610 **
611 ** Returns true in case of success, false in case of failure.
612 **
613 ******************************************************************************/
UIPC_Send(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id,uint16_t,const uint8_t * p_buf,uint16_t msglen)614 bool UIPC_Send(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint16_t /* msg_evt */, const uint8_t* p_buf,
615 uint16_t msglen) {
616 log::verbose("UIPC_Send : ch_id:{} {} bytes", ch_id, msglen);
617
618 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
619
620 ssize_t ret;
621 OSI_NO_INTR(ret = write(uipc.ch[ch_id].fd, p_buf, msglen));
622 if (ret < 0) {
623 log::error("failed to write ({})", strerror(errno));
624 return false;
625 }
626
627 return true;
628 }
629
630 /*******************************************************************************
631 **
632 ** Function UIPC_Read
633 **
634 ** Description Called to read a message from UIPC.
635 **
636 ** Returns return the number of bytes read.
637 **
638 ******************************************************************************/
639
UIPC_Read(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id,uint8_t * p_buf,uint32_t len)640 uint32_t UIPC_Read(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint8_t* p_buf, uint32_t len) {
641 if (ch_id >= UIPC_CH_NUM) {
642 log::error("UIPC_Read : invalid ch id {}", ch_id);
643 return 0;
644 }
645
646 int n_read = 0;
647 int fd = uipc.ch[ch_id].fd;
648 struct pollfd pfd;
649
650 if (fd == UIPC_DISCONNECTED) {
651 log::error("UIPC_Read : channel {} closed", ch_id);
652 return 0;
653 }
654
655 while (n_read < (int)len) {
656 pfd.fd = fd;
657 pfd.events = POLLIN | POLLHUP;
658
659 /* make sure there is data prior to attempting read to avoid blocking
660 a read for more than poll timeout */
661
662 int poll_ret;
663 OSI_NO_INTR(poll_ret = poll(&pfd, 1, uipc.ch[ch_id].read_poll_tmo_ms));
664 if (poll_ret == 0) {
665 log::warn("poll timeout ({} ms)", uipc.ch[ch_id].read_poll_tmo_ms);
666 break;
667 }
668 if (poll_ret < 0) {
669 log::error("poll() failed: return {} errno {} ({})", poll_ret, errno, strerror(errno));
670 break;
671 }
672
673 if (pfd.revents & (POLLHUP | POLLNVAL)) {
674 log::warn("poll : channel detached remotely");
675 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
676 uipc_close_locked(uipc, ch_id);
677 return 0;
678 }
679
680 ssize_t n;
681 OSI_NO_INTR(n = recv(fd, p_buf + n_read, len - n_read, 0));
682
683 if (n == 0) {
684 log::warn("UIPC_Read : channel detached remotely");
685 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
686 uipc_close_locked(uipc, ch_id);
687 return 0;
688 }
689
690 if (n < 0) {
691 log::warn("UIPC_Read : read failed ({})", strerror(errno));
692 return 0;
693 }
694
695 n_read += n;
696 }
697
698 return n_read;
699 }
700
701 /*******************************************************************************
702 *
703 * Function UIPC_Ioctl
704 *
705 * Description Called to control UIPC.
706 *
707 * Returns void
708 *
709 ******************************************************************************/
710
UIPC_Ioctl(tUIPC_STATE & uipc,tUIPC_CH_ID ch_id,uint32_t request,void * param)711 bool UIPC_Ioctl(tUIPC_STATE& uipc, tUIPC_CH_ID ch_id, uint32_t request, void* param) {
712 log::debug("#### UIPC_Ioctl : ch_id {}, request {} ####", ch_id, request);
713 std::lock_guard<std::recursive_mutex> lock(uipc.mutex);
714
715 switch (request) {
716 case UIPC_REQ_RX_FLUSH:
717 uipc_flush_locked(uipc, ch_id);
718 break;
719
720 case UIPC_REG_REMOVE_ACTIVE_READSET:
721 /* user will read data directly and not use select loop */
722 if (uipc.ch[ch_id].fd != UIPC_DISCONNECTED) {
723 /* remove this channel from active set */
724 FD_CLR(uipc.ch[ch_id].fd, &uipc.active_set);
725
726 /* refresh active set */
727 uipc_wakeup_locked(uipc);
728 }
729 break;
730
731 case UIPC_SET_READ_POLL_TMO:
732 uipc.ch[ch_id].read_poll_tmo_ms = (intptr_t)param;
733 log::debug("UIPC_SET_READ_POLL_TMO : CH {}, TMO {} ms", ch_id,
734 uipc.ch[ch_id].read_poll_tmo_ms);
735 break;
736
737 default:
738 log::debug("UIPC_Ioctl : request not handled ({})", request);
739 break;
740 }
741
742 return false;
743 }
744