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
73typedef enum {
74  UIPC_TASK_FLAG_DISCONNECT_CHAN = 0x1,
75} tUIPC_TASK_FLAGS;
76
77typedef 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
85typedef 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
102static tUIPC_MAIN uipc_main;
103
104/*****************************************************************************
105 *  Static functions
106 *****************************************************************************/
107
108static int uipc_close_ch_locked(tUIPC_CH_ID ch_id);
109
110/*****************************************************************************
111 *  Externs
112 *****************************************************************************/
113
114/*****************************************************************************
115 *   Helper functions
116 *****************************************************************************/
117
118const 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
134static 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
162static 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
208static 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
240void 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 */
253static 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
266static 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 (%s)", ch_id, strerror(errno));
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
315static 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
323static 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
330static 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
361static 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
400static 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
414static 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
447void 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
458static 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
513int 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 */
526void 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
551void 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 ******************************************************************************/
567bool 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
604void 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 ******************************************************************************/
627bool 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
652uint32_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
730extern 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