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