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