1/*
2** Copyright 2006, The Android Open Source Project
3**
4** Licensed under the Apache License, Version 2.0 (the "License");
5** you may not use this file except in compliance with the License.
6** You may obtain a copy of the License at
7**
8**     http://www.apache.org/licenses/LICENSE-2.0
9**
10** Unless required by applicable law or agreed to in writing, software
11** distributed under the License is distributed on an "AS IS" BASIS,
12** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13** See the License for the specific language governing permissions and
14** limitations under the License.
15*/
16
17#define LOG_TAG "BluetoothAudioGateway.cpp"
18
19#include "android_bluetooth_common.h"
20#include "android_bluetooth_c.h"
21#include "android_runtime/AndroidRuntime.h"
22#include "JNIHelp.h"
23#include "jni.h"
24#include "utils/Log.h"
25#include "utils/misc.h"
26
27#define USE_ACCEPT_DIRECTLY (0)
28#define USE_SELECT (0) /* 1 for select(), 0 for poll(); used only when
29                          USE_ACCEPT_DIRECTLY == 0 */
30
31#include <stdio.h>
32#include <string.h>
33#include <stdlib.h>
34#include <errno.h>
35#include <unistd.h>
36#include <fcntl.h>
37#include <sys/socket.h>
38#include <sys/time.h>
39#include <sys/types.h>
40#include <unistd.h>
41#include <fcntl.h>
42#include <sys/uio.h>
43#include <ctype.h>
44
45#if USE_SELECT
46#include <sys/select.h>
47#else
48#include <sys/poll.h>
49#endif
50
51#ifdef HAVE_BLUETOOTH
52#include <bluetooth/bluetooth.h>
53#include <bluetooth/rfcomm.h>
54#include <bluetooth/sco.h>
55#endif
56
57namespace android {
58
59#ifdef HAVE_BLUETOOTH
60static jfieldID field_mNativeData;
61    /* in */
62static jfieldID field_mHandsfreeAgRfcommChannel;
63static jfieldID field_mHeadsetAgRfcommChannel;
64    /* out */
65static jfieldID field_mTimeoutRemainingMs; /* out */
66
67static jfieldID field_mConnectingHeadsetAddress;
68static jfieldID field_mConnectingHeadsetRfcommChannel; /* -1 when not connected */
69static jfieldID field_mConnectingHeadsetSocketFd;
70
71static jfieldID field_mConnectingHandsfreeAddress;
72static jfieldID field_mConnectingHandsfreeRfcommChannel; /* -1 when not connected */
73static jfieldID field_mConnectingHandsfreeSocketFd;
74
75
76typedef struct {
77    int hcidev;
78    int hf_ag_rfcomm_channel;
79    int hs_ag_rfcomm_channel;
80    int hf_ag_rfcomm_sock;
81    int hs_ag_rfcomm_sock;
82} native_data_t;
83
84static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
85    return (native_data_t *)(env->GetIntField(object,
86                                                 field_mNativeData));
87}
88
89static int setup_listening_socket(int dev, int channel);
90#endif
91
92static void classInitNative(JNIEnv* env, jclass clazz) {
93    LOGV("%s", __FUNCTION__);
94#ifdef HAVE_BLUETOOTH
95
96    /* in */
97    field_mNativeData = get_field(env, clazz, "mNativeData", "I");
98    field_mHandsfreeAgRfcommChannel =
99        get_field(env, clazz, "mHandsfreeAgRfcommChannel", "I");
100    field_mHeadsetAgRfcommChannel =
101        get_field(env, clazz, "mHeadsetAgRfcommChannel", "I");
102
103    /* out */
104    field_mConnectingHeadsetAddress =
105        get_field(env, clazz,
106                  "mConnectingHeadsetAddress", "Ljava/lang/String;");
107    field_mConnectingHeadsetRfcommChannel =
108        get_field(env, clazz, "mConnectingHeadsetRfcommChannel", "I");
109    field_mConnectingHeadsetSocketFd =
110        get_field(env, clazz, "mConnectingHeadsetSocketFd", "I");
111
112    field_mConnectingHandsfreeAddress =
113        get_field(env, clazz,
114                  "mConnectingHandsfreeAddress", "Ljava/lang/String;");
115    field_mConnectingHandsfreeRfcommChannel =
116        get_field(env, clazz, "mConnectingHandsfreeRfcommChannel", "I");
117    field_mConnectingHandsfreeSocketFd =
118        get_field(env, clazz, "mConnectingHandsfreeSocketFd", "I");
119
120    field_mTimeoutRemainingMs =
121        get_field(env, clazz, "mTimeoutRemainingMs", "I");
122#endif
123}
124
125static void initializeNativeDataNative(JNIEnv* env, jobject object) {
126    LOGV("%s", __FUNCTION__);
127#ifdef HAVE_BLUETOOTH
128    native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
129    if (NULL == nat) {
130        LOGE("%s: out of memory!", __FUNCTION__);
131        return;
132    }
133
134    nat->hcidev = BLUETOOTH_ADAPTER_HCI_NUM;
135
136    env->SetIntField(object, field_mNativeData, (jint)nat);
137    nat->hf_ag_rfcomm_channel =
138        env->GetIntField(object, field_mHandsfreeAgRfcommChannel);
139    nat->hs_ag_rfcomm_channel =
140        env->GetIntField(object, field_mHeadsetAgRfcommChannel);
141    LOGV("HF RFCOMM channel = %d.", nat->hf_ag_rfcomm_channel);
142    LOGV("HS RFCOMM channel = %d.", nat->hs_ag_rfcomm_channel);
143
144    /* Set the default values of these to -1. */
145    env->SetIntField(object, field_mConnectingHeadsetRfcommChannel, -1);
146    env->SetIntField(object, field_mConnectingHandsfreeRfcommChannel, -1);
147
148    nat->hf_ag_rfcomm_sock = -1;
149    nat->hs_ag_rfcomm_sock = -1;
150#endif
151}
152
153static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
154    LOGV("%s", __FUNCTION__);
155#ifdef HAVE_BLUETOOTH
156    native_data_t *nat = get_native_data(env, object);
157    if (nat) {
158        free(nat);
159    }
160#endif
161}
162
163#ifdef HAVE_BLUETOOTH
164
165#if USE_ACCEPT_DIRECTLY==0
166static int set_nb(int sk, bool nb) {
167    int flags = fcntl(sk, F_GETFL);
168    if (flags < 0) {
169        LOGE("Can't get socket flags with fcntl(): %s (%d)",
170             strerror(errno), errno);
171        close(sk);
172        return -1;
173    }
174    flags &= ~O_NONBLOCK;
175    if (nb) flags |= O_NONBLOCK;
176    int status = fcntl(sk, F_SETFL, flags);
177    if (status < 0) {
178        LOGE("Can't set socket to nonblocking mode with fcntl(): %s (%d)",
179             strerror(errno), errno);
180        close(sk);
181        return -1;
182    }
183    return 0;
184}
185#endif /*USE_ACCEPT_DIRECTLY==0*/
186
187static int do_accept(JNIEnv* env, jobject object, int ag_fd,
188                     jfieldID out_fd,
189                     jfieldID out_address,
190                     jfieldID out_channel) {
191
192#if USE_ACCEPT_DIRECTLY==0
193    if (set_nb(ag_fd, true) < 0)
194        return -1;
195#endif
196
197    struct sockaddr_rc raddr;
198    int alen = sizeof(raddr);
199    int nsk = accept(ag_fd, (struct sockaddr *) &raddr, &alen);
200    if (nsk < 0) {
201        LOGE("Error on accept from socket fd %d: %s (%d).",
202             ag_fd,
203             strerror(errno),
204             errno);
205#if USE_ACCEPT_DIRECTLY==0
206        set_nb(ag_fd, false);
207#endif
208        return -1;
209    }
210
211    env->SetIntField(object, out_fd, nsk);
212    env->SetIntField(object, out_channel, raddr.rc_channel);
213
214    char addr[BTADDR_SIZE];
215    get_bdaddr_as_string(&raddr.rc_bdaddr, addr);
216    env->SetObjectField(object, out_address, env->NewStringUTF(addr));
217
218    LOGI("Successful accept() on AG socket %d: new socket %d, address %s, RFCOMM channel %d",
219         ag_fd,
220         nsk,
221         addr,
222         raddr.rc_channel);
223#if USE_ACCEPT_DIRECTLY==0
224    set_nb(ag_fd, false);
225#endif
226    return 0;
227}
228
229#if USE_SELECT
230static inline int on_accept_set_fields(JNIEnv* env, jobject object,
231                                       fd_set *rset, int ag_fd,
232                                       jfieldID out_fd,
233                                       jfieldID out_address,
234                                       jfieldID out_channel) {
235
236    env->SetIntField(object, out_channel, -1);
237
238    if (ag_fd >= 0 && FD_ISSET(ag_fd, &rset)) {
239        return do_accept(env, object, ag_fd,
240                         out_fd, out_address, out_channel);
241    }
242    else {
243        LOGI("fd = %d, FD_ISSET() = %d",
244             ag_fd,
245             FD_ISSET(ag_fd, &rset));
246        if (ag_fd >= 0 && !FD_ISSET(ag_fd, &rset)) {
247            LOGE("WTF???");
248            return -1;
249        }
250    }
251
252    return 0;
253}
254#endif
255#endif /* HAVE_BLUETOOTH */
256
257static jboolean waitForHandsfreeConnectNative(JNIEnv* env, jobject object,
258                                              jint timeout_ms) {
259//    LOGV("%s", __FUNCTION__);
260#ifdef HAVE_BLUETOOTH
261
262    env->SetIntField(object, field_mTimeoutRemainingMs, timeout_ms);
263
264    int n = 0;
265    native_data_t *nat = get_native_data(env, object);
266#if USE_ACCEPT_DIRECTLY
267    if (nat->hf_ag_rfcomm_channel > 0) {
268        LOGI("Setting HF AG server socket to RFCOMM port %d!",
269             nat->hf_ag_rfcomm_channel);
270        struct timeval tv;
271        int len = sizeof(tv);
272        if (getsockopt(nat->hf_ag_rfcomm_channel,
273                       SOL_SOCKET, SO_RCVTIMEO, &tv, &len) < 0) {
274            LOGE("getsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
275                 nat->hf_ag_rfcomm_channel,
276                 strerror(errno),
277                 errno);
278            return JNI_FALSE;
279        }
280        LOGI("Current HF AG server socket RCVTIMEO is (%d(s), %d(us))!",
281             (int)tv.tv_sec, (int)tv.tv_usec);
282        if (timeout_ms >= 0) {
283            tv.tv_sec = timeout_ms / 1000;
284            tv.tv_usec = 1000 * (timeout_ms % 1000);
285            if (setsockopt(nat->hf_ag_rfcomm_channel,
286                           SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
287                LOGE("setsockopt(%d, SOL_SOCKET, SO_RCVTIMEO): %s (%d)",
288                     nat->hf_ag_rfcomm_channel,
289                     strerror(errno),
290                     errno);
291                return JNI_FALSE;
292            }
293            LOGI("Changed HF AG server socket RCVTIMEO to (%d(s), %d(us))!",
294                 (int)tv.tv_sec, (int)tv.tv_usec);
295        }
296
297        if (!do_accept(env, object, nat->hf_ag_rfcomm_sock,
298                       field_mConnectingHandsfreeSocketFd,
299                       field_mConnectingHandsfreeAddress,
300                       field_mConnectingHandsfreeRfcommChannel))
301        {
302            env->SetIntField(object, field_mTimeoutRemainingMs, 0);
303            return JNI_TRUE;
304        }
305        return JNI_FALSE;
306    }
307#else
308#if USE_SELECT
309    fd_set rset;
310    FD_ZERO(&rset);
311    int cnt = 0;
312    if (nat->hf_ag_rfcomm_channel > 0) {
313        LOGI("Setting HF AG server socket to RFCOMM port %d!",
314             nat->hf_ag_rfcomm_channel);
315        cnt++;
316        FD_SET(nat->hf_ag_rfcomm_sock, &rset);
317    }
318    if (nat->hs_ag_rfcomm_channel > 0) {
319        LOGI("Setting HS AG server socket to RFCOMM port %d!",
320             nat->hs_ag_rfcomm_channel);
321        cnt++;
322        FD_SET(nat->hs_ag_rfcomm_sock, &rset);
323    }
324    if (cnt == 0) {
325        LOGE("Neither HF nor HS listening sockets are open!");
326        return JNI_FALSE;
327    }
328
329    struct timeval to;
330    if (timeout_ms >= 0) {
331        to.tv_sec = timeout_ms / 1000;
332        to.tv_usec = 1000 * (timeout_ms % 1000);
333    }
334    n = select(MAX(nat->hf_ag_rfcomm_sock,
335                       nat->hs_ag_rfcomm_sock) + 1,
336                   &rset,
337                   NULL,
338                   NULL,
339                   (timeout_ms < 0 ? NULL : &to));
340    if (timeout_ms > 0) {
341        jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
342        LOGI("Remaining time %ldms", (long)remaining);
343        env->SetIntField(object, field_mTimeoutRemainingMs,
344                         remaining);
345    }
346
347    LOGI("listening select() returned %d", n);
348
349    if (n <= 0) {
350        if (n < 0)  {
351            LOGE("listening select() on RFCOMM sockets: %s (%d)",
352                 strerror(errno),
353                 errno);
354        }
355        return JNI_FALSE;
356    }
357
358    n = on_accept_set_fields(env, object,
359                             &rset, nat->hf_ag_rfcomm_sock,
360                             field_mConnectingHandsfreeSocketFd,
361                             field_mConnectingHandsfreeAddress,
362                             field_mConnectingHandsfreeRfcommChannel);
363
364    n += on_accept_set_fields(env, object,
365                              &rset, nat->hs_ag_rfcomm_sock,
366                              field_mConnectingHeadsetSocketFd,
367                              field_mConnectingHeadsetAddress,
368                              field_mConnectingHeadsetRfcommChannel);
369
370    return !n ? JNI_TRUE : JNI_FALSE;
371#else
372    struct pollfd fds[2];
373    int cnt = 0;
374    if (nat->hf_ag_rfcomm_channel > 0) {
375//        LOGI("Setting HF AG server socket %d to RFCOMM port %d!",
376//             nat->hf_ag_rfcomm_sock,
377//             nat->hf_ag_rfcomm_channel);
378        fds[cnt].fd = nat->hf_ag_rfcomm_sock;
379        fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
380        cnt++;
381    }
382    if (nat->hs_ag_rfcomm_channel > 0) {
383//        LOGI("Setting HS AG server socket %d to RFCOMM port %d!",
384//             nat->hs_ag_rfcomm_sock,
385//             nat->hs_ag_rfcomm_channel);
386        fds[cnt].fd = nat->hs_ag_rfcomm_sock;
387        fds[cnt].events = POLLIN | POLLPRI | POLLOUT | POLLERR;
388        cnt++;
389    }
390    if (cnt == 0) {
391        LOGE("Neither HF nor HS listening sockets are open!");
392        return JNI_FALSE;
393    }
394    n = poll(fds, cnt, timeout_ms);
395    if (n <= 0) {
396        if (n < 0)  {
397            LOGE("listening poll() on RFCOMM sockets: %s (%d)",
398                 strerror(errno),
399                 errno);
400        }
401        else {
402            env->SetIntField(object, field_mTimeoutRemainingMs, 0);
403//            LOGI("listening poll() on RFCOMM socket timed out");
404        }
405        return JNI_FALSE;
406    }
407
408    //LOGI("listening poll() on RFCOMM socket returned %d", n);
409    int err = 0;
410    for (cnt = 0; cnt < (int)(sizeof(fds)/sizeof(fds[0])); cnt++) {
411        //LOGI("Poll on fd %d revent = %d.", fds[cnt].fd, fds[cnt].revents);
412        if (fds[cnt].fd == nat->hf_ag_rfcomm_sock) {
413            if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
414                LOGI("Accepting HF connection.\n");
415                err += do_accept(env, object, fds[cnt].fd,
416                               field_mConnectingHandsfreeSocketFd,
417                               field_mConnectingHandsfreeAddress,
418                               field_mConnectingHandsfreeRfcommChannel);
419                n--;
420            }
421        }
422        else if (fds[cnt].fd == nat->hs_ag_rfcomm_sock) {
423            if (fds[cnt].revents & (POLLIN | POLLPRI | POLLOUT)) {
424                LOGI("Accepting HS connection.\n");
425                err += do_accept(env, object, fds[cnt].fd,
426                               field_mConnectingHeadsetSocketFd,
427                               field_mConnectingHeadsetAddress,
428                               field_mConnectingHeadsetRfcommChannel);
429                n--;
430            }
431        }
432    } /* for */
433
434    if (n != 0) {
435        LOGI("Bogus poll(): %d fake pollfd entrie(s)!", n);
436        return JNI_FALSE;
437    }
438
439    return !err ? JNI_TRUE : JNI_FALSE;
440#endif /* USE_SELECT */
441#endif /* USE_ACCEPT_DIRECTLY */
442#else
443    return JNI_FALSE;
444#endif /* HAVE_BLUETOOTH */
445}
446
447static jboolean setUpListeningSocketsNative(JNIEnv* env, jobject object) {
448    LOGV("%s", __FUNCTION__);
449#ifdef HAVE_BLUETOOTH
450    native_data_t *nat = get_native_data(env, object);
451
452    nat->hf_ag_rfcomm_sock =
453        setup_listening_socket(nat->hcidev, nat->hf_ag_rfcomm_channel);
454    if (nat->hf_ag_rfcomm_sock < 0)
455        return JNI_FALSE;
456
457    nat->hs_ag_rfcomm_sock =
458        setup_listening_socket(nat->hcidev, nat->hs_ag_rfcomm_channel);
459    if (nat->hs_ag_rfcomm_sock < 0) {
460        close(nat->hf_ag_rfcomm_sock);
461        nat->hf_ag_rfcomm_sock = -1;
462        return JNI_FALSE;
463    }
464
465    return JNI_TRUE;
466#else
467    return JNI_FALSE;
468#endif /* HAVE_BLUETOOTH */
469}
470
471#ifdef HAVE_BLUETOOTH
472static int setup_listening_socket(int dev, int channel) {
473    struct sockaddr_rc laddr;
474    int sk, lm;
475
476    sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
477    if (sk < 0) {
478        LOGE("Can't create RFCOMM socket");
479        return -1;
480    }
481
482    if (debug_no_encrypt()) {
483        lm = RFCOMM_LM_AUTH;
484    } else {
485        lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
486    }
487
488    if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
489        LOGE("Can't set RFCOMM link mode");
490        close(sk);
491        return -1;
492    }
493
494    laddr.rc_family = AF_BLUETOOTH;
495    bdaddr_t any = android_bluetooth_bdaddr_any();
496    memcpy(&laddr.rc_bdaddr, &any, sizeof(bdaddr_t));
497    laddr.rc_channel = channel;
498
499    if (bind(sk, (struct sockaddr *)&laddr, sizeof(laddr)) < 0) {
500        LOGE("Can't bind RFCOMM socket");
501        close(sk);
502        return -1;
503    }
504
505    listen(sk, 10);
506    return sk;
507}
508#endif /* HAVE_BLUETOOTH */
509
510/*
511    private native void tearDownListeningSocketsNative();
512*/
513static void tearDownListeningSocketsNative(JNIEnv *env, jobject object) {
514    LOGV("%s", __FUNCTION__);
515#ifdef HAVE_BLUETOOTH
516    native_data_t *nat = get_native_data(env, object);
517
518    if (nat->hf_ag_rfcomm_sock > 0) {
519        if (close(nat->hf_ag_rfcomm_sock) < 0) {
520            LOGE("Could not close HF server socket: %s (%d)\n",
521                 strerror(errno), errno);
522        }
523        nat->hf_ag_rfcomm_sock = -1;
524    }
525    if (nat->hs_ag_rfcomm_sock > 0) {
526        if (close(nat->hs_ag_rfcomm_sock) < 0) {
527            LOGE("Could not close HS server socket: %s (%d)\n",
528                 strerror(errno), errno);
529        }
530        nat->hs_ag_rfcomm_sock = -1;
531    }
532#endif /* HAVE_BLUETOOTH */
533}
534
535static JNINativeMethod sMethods[] = {
536     /* name, signature, funcPtr */
537
538    {"classInitNative", "()V", (void*)classInitNative},
539    {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
540    {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
541
542    {"setUpListeningSocketsNative", "()Z", (void *)setUpListeningSocketsNative},
543    {"tearDownListeningSocketsNative", "()V", (void *)tearDownListeningSocketsNative},
544    {"waitForHandsfreeConnectNative", "(I)Z", (void *)waitForHandsfreeConnectNative},
545};
546
547int register_android_bluetooth_BluetoothAudioGateway(JNIEnv *env) {
548    return AndroidRuntime::registerNativeMethods(env,
549            "android/bluetooth/BluetoothAudioGateway", sMethods,
550            NELEM(sMethods));
551}
552
553} /* namespace android */
554