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