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