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 "BT HSHFP"
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#include <stdio.h>
27#include <string.h>
28#include <stdlib.h>
29#include <errno.h>
30#include <unistd.h>
31#include <fcntl.h>
32#include <sys/socket.h>
33#include <sys/uio.h>
34#include <sys/poll.h>
35
36#ifdef HAVE_BLUETOOTH
37#include <bluetooth/bluetooth.h>
38#include <bluetooth/rfcomm.h>
39#include <bluetooth/sco.h>
40#endif
41
42namespace android {
43
44#ifdef HAVE_BLUETOOTH
45static jfieldID field_mNativeData;
46static jfieldID field_mAddress;
47static jfieldID field_mRfcommChannel;
48static jfieldID field_mTimeoutRemainingMs;
49
50typedef struct {
51    jstring address;
52    const char *c_address;
53    int rfcomm_channel;
54    int last_read_err;
55    int rfcomm_sock;
56    int rfcomm_connected; // -1 in progress, 0 not connected, 1 connected
57    int rfcomm_sock_flags;
58} native_data_t;
59
60static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
61    return (native_data_t *)(env->GetIntField(object, field_mNativeData));
62}
63
64static const char CRLF[] = "\xd\xa";
65static const int CRLF_LEN = 2;
66
67static inline int write_error_check(int fd, const char* line, int len) {
68    int ret;
69    errno = 0;
70    ret = write(fd, line, len);
71    if (ret < 0) {
72        LOGE("%s: write() failed: %s (%d)", __FUNCTION__, strerror(errno),
73             errno);
74        return -1;
75    }
76    if (ret != len) {
77        LOGE("%s: write() only wrote %d of %d bytes", __FUNCTION__, ret, len);
78        return -1;
79    }
80    return 0;
81}
82
83static int send_line(int fd, const char* line) {
84    int nw;
85    int len = strlen(line);
86    int llen = len + CRLF_LEN * 2 + 1;
87    char *buffer = (char *)calloc(llen, sizeof(char));
88
89    snprintf(buffer, llen, "%s%s%s", CRLF, line, CRLF);
90
91    if (write_error_check(fd, buffer, llen - 1)) {
92        free(buffer);
93        return -1;
94    }
95    free(buffer);
96    return 0;
97}
98
99static int is_ascii(char *line) {
100    for (;;line++) {
101        if (*line == 0) return 1;
102        if (*line >> 7) return 0;
103    }
104}
105
106static const char* get_line(int fd, char *buf, int len, int timeout_ms,
107                            int *err) {
108    char *bufit=buf;
109    int fd_flags = fcntl(fd, F_GETFL, 0);
110    struct pollfd pfd;
111
112again:
113    *bufit = 0;
114    pfd.fd = fd;
115    pfd.events = POLLIN;
116    *err = errno = 0;
117    int ret = poll(&pfd, 1, timeout_ms);
118    if (ret < 0) {
119        LOGE("poll() error\n");
120        *err = errno;
121        return NULL;
122    }
123    if (ret == 0) {
124        return NULL;
125    }
126
127    if (pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) {
128        LOGW("RFCOMM poll() returned  success (%d), "
129             "but with an unexpected revents bitmask: %#x\n", ret, pfd.revents);
130        errno = EIO;
131        *err = errno;
132        return NULL;
133    }
134
135    while ((int)(bufit - buf) < (len - 1))
136    {
137        errno = 0;
138        int rc = read(fd, bufit, 1);
139
140        if (!rc)
141            break;
142
143        if (rc < 0) {
144            if (errno == EBUSY) {
145                LOGI("read() error %s (%d): repeating read()...",
146                     strerror(errno), errno);
147                goto again;
148            }
149            *err = errno;
150            LOGE("read() error %s (%d)", strerror(errno), errno);
151            return NULL;
152        }
153
154
155        if (*bufit=='\xd') {
156            break;
157        }
158
159        if (*bufit=='\xa')
160            bufit = buf;
161        else
162            bufit++;
163    }
164
165    *bufit = NULL;
166
167    // Simple validation. Must be all ASCII.
168    // (we sometimes send non-ASCII UTF-8 in address book, but should
169    // never receive non-ASCII UTF-8).
170    // This was added because of the BMW 2005 E46 which sends binary junk.
171    if (is_ascii(buf)) {
172        IF_LOGV() LOG(LOG_VERBOSE, "Bluetooth AT recv", "%s", buf);
173    } else {
174        LOGW("Ignoring invalid AT command: %s", buf);
175        buf[0] = NULL;
176    }
177
178    return buf;
179}
180#endif
181
182static void classInitNative(JNIEnv* env, jclass clazz) {
183    LOGV(__FUNCTION__);
184#ifdef HAVE_BLUETOOTH
185    field_mNativeData = get_field(env, clazz, "mNativeData", "I");
186    field_mAddress = get_field(env, clazz, "mAddress", "Ljava/lang/String;");
187    field_mTimeoutRemainingMs = get_field(env, clazz, "mTimeoutRemainingMs", "I");
188    field_mRfcommChannel = get_field(env, clazz, "mRfcommChannel", "I");
189#endif
190}
191
192static void initializeNativeDataNative(JNIEnv* env, jobject object,
193                                       jint socketFd) {
194    LOGV(__FUNCTION__);
195#ifdef HAVE_BLUETOOTH
196    native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
197    if (NULL == nat) {
198        LOGE("%s: out of memory!", __FUNCTION__);
199        return;
200    }
201
202    env->SetIntField(object, field_mNativeData, (jint)nat);
203    nat->address =
204        (jstring)env->NewGlobalRef(env->GetObjectField(object,
205                                                       field_mAddress));
206    nat->c_address = env->GetStringUTFChars(nat->address, NULL);
207    nat->rfcomm_channel = env->GetIntField(object, field_mRfcommChannel);
208    nat->rfcomm_sock = socketFd;
209    nat->rfcomm_connected = socketFd >= 0;
210    if (nat->rfcomm_connected)
211        LOGI("%s: ALREADY CONNECTED!", __FUNCTION__);
212#endif
213}
214
215static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
216    LOGV(__FUNCTION__);
217#ifdef HAVE_BLUETOOTH
218    native_data_t *nat =
219        (native_data_t *)env->GetIntField(object, field_mNativeData);
220    env->ReleaseStringUTFChars(nat->address, nat->c_address);
221    env->DeleteGlobalRef(nat->address);
222    if (nat)
223        free(nat);
224#endif
225}
226
227static jboolean connectNative(JNIEnv *env, jobject obj)
228{
229    LOGV(__FUNCTION__);
230#ifdef HAVE_BLUETOOTH
231    int lm;
232    struct sockaddr_rc addr;
233    native_data_t *nat = get_native_data(env, obj);
234
235    nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
236
237    if (nat->rfcomm_sock < 0) {
238        LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
239             strerror(errno));
240        return JNI_FALSE;
241    }
242
243    if (debug_no_encrypt()) {
244        lm = RFCOMM_LM_AUTH;
245    } else {
246        lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
247    }
248
249    if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
250                sizeof(lm)) < 0) {
251        LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
252        close(nat->rfcomm_sock);
253        return JNI_FALSE;
254    }
255
256    memset(&addr, 0, sizeof(struct sockaddr_rc));
257    get_bdaddr(nat->c_address, &addr.rc_bdaddr);
258    addr.rc_channel = nat->rfcomm_channel;
259    addr.rc_family = AF_BLUETOOTH;
260    nat->rfcomm_connected = 0;
261    while (nat->rfcomm_connected == 0) {
262        if (connect(nat->rfcomm_sock, (struct sockaddr *)&addr,
263                      sizeof(addr)) < 0) {
264            if (errno == EINTR) continue;
265            LOGE("%s: connect() failed: %s\n", __FUNCTION__, strerror(errno));
266            close(nat->rfcomm_sock);
267            nat->rfcomm_sock = -1;
268            return JNI_FALSE;
269        } else {
270            nat->rfcomm_connected = 1;
271        }
272    }
273
274    return JNI_TRUE;
275#else
276    return JNI_FALSE;
277#endif
278}
279
280static jint connectAsyncNative(JNIEnv *env, jobject obj) {
281    LOGV(__FUNCTION__);
282#ifdef HAVE_BLUETOOTH
283    struct sockaddr_rc addr;
284    native_data_t *nat = get_native_data(env, obj);
285
286    if (nat->rfcomm_connected) {
287        LOGV("RFCOMM socket is already connected or connection is in progress.");
288        return 0;
289    }
290
291    if (nat->rfcomm_sock < 0) {
292        int lm;
293
294        nat->rfcomm_sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
295        if (nat->rfcomm_sock < 0) {
296            LOGE("%s: Could not create RFCOMM socket: %s\n", __FUNCTION__,
297                 strerror(errno));
298            return -1;
299        }
300
301        if (debug_no_encrypt()) {
302            lm = RFCOMM_LM_AUTH;
303        } else {
304            lm = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
305        }
306
307        if (lm && setsockopt(nat->rfcomm_sock, SOL_RFCOMM, RFCOMM_LM, &lm,
308                    sizeof(lm)) < 0) {
309            LOGE("%s: Can't set RFCOMM link mode", __FUNCTION__);
310            close(nat->rfcomm_sock);
311            return -1;
312        }
313        LOGI("Created RFCOMM socket fd %d.", nat->rfcomm_sock);
314    }
315
316    memset(&addr, 0, sizeof(struct sockaddr_rc));
317    get_bdaddr(nat->c_address, &addr.rc_bdaddr);
318    addr.rc_channel = nat->rfcomm_channel;
319    addr.rc_family = AF_BLUETOOTH;
320    if (nat->rfcomm_sock_flags >= 0) {
321        nat->rfcomm_sock_flags = fcntl(nat->rfcomm_sock, F_GETFL, 0);
322        if (fcntl(nat->rfcomm_sock,
323                  F_SETFL, nat->rfcomm_sock_flags | O_NONBLOCK) >= 0) {
324            int rc;
325            nat->rfcomm_connected = 0;
326            errno = 0;
327            rc = connect(nat->rfcomm_sock,
328                        (struct sockaddr *)&addr,
329                         sizeof(addr));
330
331            if (rc >= 0) {
332                nat->rfcomm_connected = 1;
333                LOGI("async connect successful");
334                return 0;
335            }
336            else if (rc < 0) {
337                if (errno == EINPROGRESS || errno == EAGAIN)
338                {
339                    LOGI("async connect is in progress (%s)",
340                         strerror(errno));
341                    nat->rfcomm_connected = -1;
342                    return 0;
343                }
344                else
345                {
346                    LOGE("async connect error: %s (%d)", strerror(errno), errno);
347                    close(nat->rfcomm_sock);
348                    nat->rfcomm_sock = -1;
349                    return -errno;
350                }
351            }
352        } // fcntl(nat->rfcomm_sock ...)
353    } // if (nat->rfcomm_sock_flags >= 0)
354#endif
355    return -1;
356}
357
358static jint waitForAsyncConnectNative(JNIEnv *env, jobject obj,
359                                           jint timeout_ms) {
360    LOGV(__FUNCTION__);
361#ifdef HAVE_BLUETOOTH
362    struct sockaddr_rc addr;
363    native_data_t *nat = get_native_data(env, obj);
364
365    env->SetIntField(obj, field_mTimeoutRemainingMs, timeout_ms);
366
367    if (nat->rfcomm_connected > 0) {
368        LOGI("RFCOMM is already connected!");
369        return 1;
370    }
371
372    if (nat->rfcomm_sock >= 0 && nat->rfcomm_connected == 0) {
373        LOGI("Re-opening RFCOMM socket.");
374        close(nat->rfcomm_sock);
375        nat->rfcomm_sock = -1;
376    }
377    int ret = connectAsyncNative(env, obj);
378
379    if (ret < 0) {
380        LOGI("Failed to re-open RFCOMM socket!");
381        return ret;
382    }
383
384    if (nat->rfcomm_sock >= 0) {
385        /* Do an asynchronous select() */
386        int n;
387        fd_set rset, wset;
388        struct timeval to;
389
390        FD_ZERO(&rset);
391        FD_ZERO(&wset);
392        FD_SET(nat->rfcomm_sock, &rset);
393        FD_SET(nat->rfcomm_sock, &wset);
394        if (timeout_ms >= 0) {
395            to.tv_sec = timeout_ms / 1000;
396            to.tv_usec = 1000 * (timeout_ms % 1000);
397        }
398        n = select(nat->rfcomm_sock + 1,
399                   &rset,
400                   &wset,
401                   NULL,
402                   (timeout_ms < 0 ? NULL : &to));
403
404        if (timeout_ms > 0) {
405            jint remaining = to.tv_sec*1000 + to.tv_usec/1000;
406            LOGV("Remaining time %ldms", (long)remaining);
407            env->SetIntField(obj, field_mTimeoutRemainingMs,
408                             remaining);
409        }
410
411        if (n <= 0) {
412            if (n < 0)  {
413                LOGE("select() on RFCOMM socket: %s (%d)",
414                     strerror(errno),
415                     errno);
416                return -errno;
417            }
418            return 0;
419        }
420        /* n must be equal to 1 and either rset or wset must have the
421           file descriptor set. */
422        LOGV("select() returned %d.", n);
423        if (FD_ISSET(nat->rfcomm_sock, &rset) ||
424            FD_ISSET(nat->rfcomm_sock, &wset))
425        {
426            /* A trial async read() will tell us if everything is OK. */
427            {
428                char ch;
429                errno = 0;
430                int nr = read(nat->rfcomm_sock, &ch, 1);
431                /* It should be that nr != 1 because we just opened a socket
432                   and we haven't sent anything over it for the other side to
433                   respond... but one can't be paranoid enough.
434                */
435                if (nr >= 0 || errno != EAGAIN) {
436                    LOGE("RFCOMM async connect() error: %s (%d), nr = %d\n",
437                         strerror(errno),
438                         errno,
439                         nr);
440                    /* Clear the rfcomm_connected flag to cause this function
441                       to re-create the socket and re-attempt the connect()
442                       the next time it is called.
443                    */
444                    nat->rfcomm_connected = 0;
445                    /* Restore the blocking properties of the socket. */
446                    fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
447                    close(nat->rfcomm_sock);
448                    nat->rfcomm_sock = -1;
449                    return -errno;
450                }
451            }
452            /* Restore the blocking properties of the socket. */
453            fcntl(nat->rfcomm_sock, F_SETFL, nat->rfcomm_sock_flags);
454            LOGI("Successful RFCOMM socket connect.");
455            nat->rfcomm_connected = 1;
456            return 1;
457        }
458    }
459    else LOGE("RFCOMM socket file descriptor %d is bad!",
460              nat->rfcomm_sock);
461#endif
462    return -1;
463}
464
465static void disconnectNative(JNIEnv *env, jobject obj) {
466    LOGV(__FUNCTION__);
467#ifdef HAVE_BLUETOOTH
468    native_data_t *nat = get_native_data(env, obj);
469    if (nat->rfcomm_sock >= 0) {
470        close(nat->rfcomm_sock);
471        nat->rfcomm_sock = -1;
472        nat->rfcomm_connected = 0;
473    }
474#endif
475}
476
477static void pretty_log_urc(const char *urc) {
478    size_t i;
479    bool in_line_break = false;
480    char *buf = (char *)calloc(strlen(urc) + 1, sizeof(char));
481
482    strcpy(buf, urc);
483    for (i = 0; i < strlen(buf); i++) {
484        switch(buf[i]) {
485        case '\r':
486        case '\n':
487            in_line_break = true;
488            buf[i] = ' ';
489            break;
490        default:
491            if (in_line_break) {
492                in_line_break = false;
493                buf[i-1] = '\n';
494            }
495        }
496    }
497    IF_LOGV() LOG(LOG_VERBOSE, "Bluetooth AT sent", "%s", buf);
498
499    free(buf);
500}
501
502static jboolean sendURCNative(JNIEnv *env, jobject obj, jstring urc) {
503#ifdef HAVE_BLUETOOTH
504    native_data_t *nat = get_native_data(env, obj);
505    if (nat->rfcomm_connected) {
506        const char *c_urc = env->GetStringUTFChars(urc, NULL);
507        jboolean ret = send_line(nat->rfcomm_sock, c_urc) == 0 ? JNI_TRUE : JNI_FALSE;
508        if (ret == JNI_TRUE) pretty_log_urc(c_urc);
509        env->ReleaseStringUTFChars(urc, c_urc);
510        return ret;
511    }
512#endif
513    return JNI_FALSE;
514}
515
516static jstring readNative(JNIEnv *env, jobject obj, jint timeout_ms) {
517#ifdef HAVE_BLUETOOTH
518    {
519        native_data_t *nat = get_native_data(env, obj);
520        if (nat->rfcomm_connected) {
521            char buf[256];
522            const char *ret = get_line(nat->rfcomm_sock,
523                                       buf, sizeof(buf),
524                                       timeout_ms,
525                                       &nat->last_read_err);
526            return ret ? env->NewStringUTF(ret) : NULL;
527        }
528        return NULL;
529    }
530#else
531    return NULL;
532#endif
533}
534
535static jint getLastReadStatusNative(JNIEnv *env, jobject obj) {
536#ifdef HAVE_BLUETOOTH
537    {
538        native_data_t *nat = get_native_data(env, obj);
539        if (nat->rfcomm_connected)
540            return (jint)nat->last_read_err;
541        return 0;
542    }
543#else
544    return 0;
545#endif
546}
547
548static JNINativeMethod sMethods[] = {
549     /* name, signature, funcPtr */
550    {"classInitNative", "()V", (void*)classInitNative},
551    {"initializeNativeDataNative", "(I)V", (void *)initializeNativeDataNative},
552    {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
553    {"connectNative", "()Z", (void *)connectNative},
554    {"connectAsyncNative", "()I", (void *)connectAsyncNative},
555    {"waitForAsyncConnectNative", "(I)I", (void *)waitForAsyncConnectNative},
556    {"disconnectNative", "()V", (void *)disconnectNative},
557    {"sendURCNative", "(Ljava/lang/String;)Z", (void *)sendURCNative},
558    {"readNative", "(I)Ljava/lang/String;", (void *)readNative},
559    {"getLastReadStatusNative", "()I", (void *)getLastReadStatusNative},
560};
561
562int register_android_bluetooth_HeadsetBase(JNIEnv *env) {
563    return AndroidRuntime::registerNativeMethods(env,
564            "android/bluetooth/HeadsetBase", sMethods, NELEM(sMethods));
565}
566
567} /* namespace android */
568