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