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