• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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