• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2009, 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 "BluetoothSocket.cpp"
18 
19 #include "android_bluetooth_common.h"
20 #include "android_runtime/AndroidRuntime.h"
21 #include "JNIHelp.h"
22 #include "utils/Log.h"
23 #include "cutils/abort_socket.h"
24 
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <sys/socket.h>
29 #include <sys/ioctl.h>
30 
31 #ifdef HAVE_BLUETOOTH
32 #include <bluetooth/bluetooth.h>
33 #include <bluetooth/rfcomm.h>
34 #include <bluetooth/l2cap.h>
35 #include <bluetooth/sco.h>
36 #endif
37 
38 #define TYPE_AS_STR(t) \
39     ((t) == TYPE_RFCOMM ? "RFCOMM" : ((t) == TYPE_SCO ? "SCO" : "L2CAP"))
40 
41 namespace android {
42 
43 static jfieldID  field_mAuth;     /* read-only */
44 static jfieldID  field_mEncrypt;  /* read-only */
45 static jfieldID  field_mType;     /* read-only */
46 static jfieldID  field_mAddress;  /* read-only */
47 static jfieldID  field_mPort;     /* read-only */
48 static jfieldID  field_mSocketData;
49 static jmethodID method_BluetoothSocket_ctor;
50 static jclass    class_BluetoothSocket;
51 
52 /* Keep TYPE_RFCOMM etc in sync with BluetoothSocket.java */
53 static const int TYPE_RFCOMM = 1;
54 static const int TYPE_SCO = 2;
55 static const int TYPE_L2CAP = 3;  // TODO: Test l2cap code paths
56 
57 static const int RFCOMM_SO_SNDBUF = 70 * 1024;  // 70 KB send buffer
58 
get_socketData(JNIEnv * env,jobject obj)59 static struct asocket *get_socketData(JNIEnv *env, jobject obj) {
60     struct asocket *s =
61             (struct asocket *) env->GetIntField(obj, field_mSocketData);
62     if (!s)
63         jniThrowException(env, "java/io/IOException", "null socketData");
64     return s;
65 }
66 
initSocketFromFdNative(JNIEnv * env,jobject obj,jint fd)67 static void initSocketFromFdNative(JNIEnv *env, jobject obj, jint fd) {
68 #ifdef HAVE_BLUETOOTH
69     LOGV(__FUNCTION__);
70 
71     struct asocket *s = asocket_init(fd);
72 
73     if (!s) {
74         LOGV("asocket_init() failed, throwing");
75         jniThrowIOException(env, errno);
76         return;
77     }
78 
79     env->SetIntField(obj, field_mSocketData, (jint)s);
80 
81     return;
82 #endif
83     jniThrowIOException(env, ENOSYS);
84 }
85 
initSocketNative(JNIEnv * env,jobject obj)86 static void initSocketNative(JNIEnv *env, jobject obj) {
87 #ifdef HAVE_BLUETOOTH
88     LOGV(__FUNCTION__);
89 
90     int fd;
91     int lm = 0;
92     int sndbuf;
93     jboolean auth;
94     jboolean encrypt;
95     jint type;
96 
97     type = env->GetIntField(obj, field_mType);
98 
99     switch (type) {
100     case TYPE_RFCOMM:
101         fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
102         break;
103     case TYPE_SCO:
104         fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
105         break;
106     case TYPE_L2CAP:
107         fd = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
108         break;
109     default:
110         jniThrowIOException(env, ENOSYS);
111         return;
112     }
113 
114     if (fd < 0) {
115         LOGV("socket() failed, throwing");
116         jniThrowIOException(env, errno);
117         return;
118     }
119 
120     auth = env->GetBooleanField(obj, field_mAuth);
121     encrypt = env->GetBooleanField(obj, field_mEncrypt);
122 
123     /* kernel does not yet support LM for SCO */
124     switch (type) {
125     case TYPE_RFCOMM:
126         lm |= auth ? RFCOMM_LM_AUTH : 0;
127         lm |= encrypt ? RFCOMM_LM_ENCRYPT : 0;
128         lm |= (auth && encrypt) ? RFCOMM_LM_SECURE : 0;
129         break;
130     case TYPE_L2CAP:
131         lm |= auth ? L2CAP_LM_AUTH : 0;
132         lm |= encrypt ? L2CAP_LM_ENCRYPT : 0;
133         lm |= (auth && encrypt) ? L2CAP_LM_SECURE : 0;
134         break;
135     }
136 
137     if (lm) {
138         if (setsockopt(fd, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm))) {
139             LOGV("setsockopt(RFCOMM_LM) failed, throwing");
140             jniThrowIOException(env, errno);
141             return;
142         }
143     }
144 
145     if (type == TYPE_RFCOMM) {
146         sndbuf = RFCOMM_SO_SNDBUF;
147         if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf))) {
148             LOGV("setsockopt(SO_SNDBUF) failed, throwing");
149             jniThrowIOException(env, errno);
150             return;
151         }
152     }
153 
154     LOGV("...fd %d created (%s, lm = %x)", fd, TYPE_AS_STR(type), lm);
155 
156     initSocketFromFdNative(env, obj, fd);
157     return;
158 #endif
159     jniThrowIOException(env, ENOSYS);
160 }
161 
connectNative(JNIEnv * env,jobject obj)162 static void connectNative(JNIEnv *env, jobject obj) {
163 #ifdef HAVE_BLUETOOTH
164     LOGV(__FUNCTION__);
165 
166     int ret;
167     jint type;
168     const char *c_address;
169     jstring address;
170     bdaddr_t bdaddress;
171     socklen_t addr_sz;
172     struct sockaddr *addr;
173     struct asocket *s = get_socketData(env, obj);
174 
175     if (!s)
176         return;
177 
178     type = env->GetIntField(obj, field_mType);
179 
180     /* parse address into bdaddress */
181     address = (jstring) env->GetObjectField(obj, field_mAddress);
182     c_address = env->GetStringUTFChars(address, NULL);
183     if (get_bdaddr(c_address, &bdaddress)) {
184         env->ReleaseStringUTFChars(address, c_address);
185         jniThrowIOException(env, EINVAL);
186         return;
187     }
188     env->ReleaseStringUTFChars(address, c_address);
189 
190     switch (type) {
191     case TYPE_RFCOMM:
192         struct sockaddr_rc addr_rc;
193         addr = (struct sockaddr *)&addr_rc;
194         addr_sz = sizeof(addr_rc);
195 
196         memset(addr, 0, addr_sz);
197         addr_rc.rc_family = AF_BLUETOOTH;
198         addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
199         memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t));
200 
201         break;
202     case TYPE_SCO:
203         struct sockaddr_sco addr_sco;
204         addr = (struct sockaddr *)&addr_sco;
205         addr_sz = sizeof(addr_sco);
206 
207         memset(addr, 0, addr_sz);
208         addr_sco.sco_family = AF_BLUETOOTH;
209         memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t));
210 
211         break;
212     case TYPE_L2CAP:
213         struct sockaddr_l2 addr_l2;
214         addr = (struct sockaddr *)&addr_l2;
215         addr_sz = sizeof(addr_l2);
216 
217         memset(addr, 0, addr_sz);
218         addr_l2.l2_family = AF_BLUETOOTH;
219         addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
220         memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t));
221 
222         break;
223     default:
224         jniThrowIOException(env, ENOSYS);
225         return;
226     }
227 
228     ret = asocket_connect(s, addr, addr_sz, -1);
229     LOGV("...connect(%d, %s) = %d (errno %d)",
230             s->fd, TYPE_AS_STR(type), ret, errno);
231 
232     if (ret)
233         jniThrowIOException(env, errno);
234 
235     return;
236 #endif
237     jniThrowIOException(env, ENOSYS);
238 }
239 
240 /* Returns errno instead of throwing, so java can check errno */
bindListenNative(JNIEnv * env,jobject obj)241 static int bindListenNative(JNIEnv *env, jobject obj) {
242 #ifdef HAVE_BLUETOOTH
243     LOGV(__FUNCTION__);
244 
245     jint type;
246     socklen_t addr_sz;
247     struct sockaddr *addr;
248     bdaddr_t bdaddr = *BDADDR_ANY;
249     struct asocket *s = get_socketData(env, obj);
250 
251     if (!s)
252         return EINVAL;
253 
254     type = env->GetIntField(obj, field_mType);
255 
256     switch (type) {
257     case TYPE_RFCOMM:
258         struct sockaddr_rc addr_rc;
259         addr = (struct sockaddr *)&addr_rc;
260         addr_sz = sizeof(addr_rc);
261 
262         memset(addr, 0, addr_sz);
263         addr_rc.rc_family = AF_BLUETOOTH;
264         addr_rc.rc_channel = env->GetIntField(obj, field_mPort);
265         memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t));
266         break;
267     case TYPE_SCO:
268         struct sockaddr_sco addr_sco;
269         addr = (struct sockaddr *)&addr_sco;
270         addr_sz = sizeof(addr_sco);
271 
272         memset(addr, 0, addr_sz);
273         addr_sco.sco_family = AF_BLUETOOTH;
274         memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t));
275         break;
276     case TYPE_L2CAP:
277         struct sockaddr_l2 addr_l2;
278         addr = (struct sockaddr *)&addr_l2;
279         addr_sz = sizeof(addr_l2);
280 
281         memset(addr, 0, addr_sz);
282         addr_l2.l2_family = AF_BLUETOOTH;
283         addr_l2.l2_psm = env->GetIntField(obj, field_mPort);
284         memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t));
285         break;
286     default:
287         return ENOSYS;
288     }
289 
290     if (bind(s->fd, addr, addr_sz)) {
291         LOGV("...bind(%d) gave errno %d", s->fd, errno);
292         return errno;
293     }
294 
295     if (listen(s->fd, 1)) {
296         LOGV("...listen(%d) gave errno %d", s->fd, errno);
297         return errno;
298     }
299 
300     LOGV("...bindListenNative(%d) success", s->fd);
301 
302     return 0;
303 
304 #endif
305     return ENOSYS;
306 }
307 
acceptNative(JNIEnv * env,jobject obj,int timeout)308 static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) {
309 #ifdef HAVE_BLUETOOTH
310     LOGV(__FUNCTION__);
311 
312     int fd;
313     jint type;
314     struct sockaddr *addr;
315     socklen_t addr_sz;
316     jstring addr_jstr;
317     char addr_cstr[BTADDR_SIZE];
318     bdaddr_t *bdaddr;
319     jboolean auth;
320     jboolean encrypt;
321 
322     struct asocket *s = get_socketData(env, obj);
323 
324     if (!s)
325         return NULL;
326 
327     type = env->GetIntField(obj, field_mType);
328 
329     switch (type) {
330     case TYPE_RFCOMM:
331         struct sockaddr_rc addr_rc;
332         addr = (struct sockaddr *)&addr_rc;
333         addr_sz = sizeof(addr_rc);
334         bdaddr = &addr_rc.rc_bdaddr;
335         memset(addr, 0, addr_sz);
336         break;
337     case TYPE_SCO:
338         struct sockaddr_sco addr_sco;
339         addr = (struct sockaddr *)&addr_sco;
340         addr_sz = sizeof(addr_sco);
341         bdaddr = &addr_sco.sco_bdaddr;
342         memset(addr, 0, addr_sz);
343         break;
344     case TYPE_L2CAP:
345         struct sockaddr_l2 addr_l2;
346         addr = (struct sockaddr *)&addr_l2;
347         addr_sz = sizeof(addr_l2);
348         bdaddr = &addr_l2.l2_bdaddr;
349         memset(addr, 0, addr_sz);
350         break;
351     default:
352         jniThrowIOException(env, ENOSYS);
353         return NULL;
354     }
355 
356     fd = asocket_accept(s, addr, &addr_sz, timeout);
357 
358     LOGV("...accept(%d, %s) = %d (errno %d)",
359             s->fd, TYPE_AS_STR(type), fd, errno);
360 
361     if (fd < 0) {
362         jniThrowIOException(env, errno);
363         return NULL;
364     }
365 
366     /* Connected - return new BluetoothSocket */
367     auth = env->GetBooleanField(obj, field_mAuth);
368     encrypt = env->GetBooleanField(obj, field_mEncrypt);
369 
370     get_bdaddr_as_string(bdaddr, addr_cstr);
371 
372     addr_jstr = env->NewStringUTF(addr_cstr);
373     return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor,
374             type, fd, auth, encrypt, addr_jstr, -1);
375 
376 #endif
377     jniThrowIOException(env, ENOSYS);
378     return NULL;
379 }
380 
availableNative(JNIEnv * env,jobject obj)381 static jint availableNative(JNIEnv *env, jobject obj) {
382 #ifdef HAVE_BLUETOOTH
383     LOGV(__FUNCTION__);
384 
385     int available;
386     struct asocket *s = get_socketData(env, obj);
387 
388     if (!s)
389         return -1;
390 
391     if (ioctl(s->fd, FIONREAD, &available) < 0) {
392         jniThrowIOException(env, errno);
393         return -1;
394     }
395 
396     return available;
397 
398 #endif
399     jniThrowIOException(env, ENOSYS);
400     return -1;
401 }
402 
readNative(JNIEnv * env,jobject obj,jbyteArray jb,jint offset,jint length)403 static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
404         jint length) {
405 #ifdef HAVE_BLUETOOTH
406     LOGV(__FUNCTION__);
407 
408     int ret;
409     jbyte *b;
410     int sz;
411     struct asocket *s = get_socketData(env, obj);
412 
413     if (!s)
414         return -1;
415     if (jb == NULL) {
416         jniThrowIOException(env, EINVAL);
417         return -1;
418     }
419     sz = env->GetArrayLength(jb);
420     if (offset < 0 || length < 0 || offset + length > sz) {
421         jniThrowIOException(env, EINVAL);
422         return -1;
423     }
424 
425     b = env->GetByteArrayElements(jb, NULL);
426     if (b == NULL) {
427         jniThrowIOException(env, EINVAL);
428         return -1;
429     }
430 
431     ret = asocket_read(s, &b[offset], length, -1);
432     if (ret < 0) {
433         jniThrowIOException(env, errno);
434         env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
435         return -1;
436     }
437 
438     env->ReleaseByteArrayElements(jb, b, 0);
439     return (jint)ret;
440 
441 #endif
442     jniThrowIOException(env, ENOSYS);
443     return -1;
444 }
445 
writeNative(JNIEnv * env,jobject obj,jbyteArray jb,jint offset,jint length)446 static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
447         jint length) {
448 #ifdef HAVE_BLUETOOTH
449     LOGV(__FUNCTION__);
450 
451     int ret;
452     jbyte *b;
453     int sz;
454     struct asocket *s = get_socketData(env, obj);
455 
456     if (!s)
457         return -1;
458     if (jb == NULL) {
459         jniThrowIOException(env, EINVAL);
460         return -1;
461     }
462     sz = env->GetArrayLength(jb);
463     if (offset < 0 || length < 0 || offset + length > sz) {
464         jniThrowIOException(env, EINVAL);
465         return -1;
466     }
467 
468     b = env->GetByteArrayElements(jb, NULL);
469     if (b == NULL) {
470         jniThrowIOException(env, EINVAL);
471         return -1;
472     }
473 
474     ret = asocket_write(s, &b[offset], length, -1);
475     if (ret < 0) {
476         jniThrowIOException(env, errno);
477         env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
478         return -1;
479     }
480 
481     env->ReleaseByteArrayElements(jb, b, JNI_ABORT);  // no need to commit
482     return (jint)ret;
483 
484 #endif
485     jniThrowIOException(env, ENOSYS);
486     return -1;
487 }
488 
abortNative(JNIEnv * env,jobject obj)489 static void abortNative(JNIEnv *env, jobject obj) {
490 #ifdef HAVE_BLUETOOTH
491     LOGV(__FUNCTION__);
492     struct asocket *s = get_socketData(env, obj);
493 
494     if (!s)
495         return;
496 
497     asocket_abort(s);
498 
499     LOGV("...asocket_abort(%d) complete", s->fd);
500     return;
501 #endif
502     jniThrowIOException(env, ENOSYS);
503 }
504 
destroyNative(JNIEnv * env,jobject obj)505 static void destroyNative(JNIEnv *env, jobject obj) {
506 #ifdef HAVE_BLUETOOTH
507     LOGV(__FUNCTION__);
508     struct asocket *s = get_socketData(env, obj);
509     int fd = s->fd;
510 
511     if (!s)
512         return;
513 
514     asocket_destroy(s);
515 
516     LOGV("...asocket_destroy(%d) complete", fd);
517     return;
518 #endif
519     jniThrowIOException(env, ENOSYS);
520 }
521 
throwErrnoNative(JNIEnv * env,jobject obj,jint err)522 static void throwErrnoNative(JNIEnv *env, jobject obj, jint err) {
523     jniThrowIOException(env, err);
524 }
525 
526 static JNINativeMethod sMethods[] = {
527     {"initSocketNative", "()V",  (void*) initSocketNative},
528     {"initSocketFromFdNative", "(I)V",  (void*) initSocketFromFdNative},
529     {"connectNative", "()V", (void *) connectNative},
530     {"bindListenNative", "()I", (void *) bindListenNative},
531     {"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
532     {"availableNative", "()I",    (void *) availableNative},
533     {"readNative", "([BII)I",    (void *) readNative},
534     {"writeNative", "([BII)I",    (void *) writeNative},
535     {"abortNative", "()V",    (void *) abortNative},
536     {"destroyNative", "()V",    (void *) destroyNative},
537     {"throwErrnoNative", "(I)V",    (void *) throwErrnoNative},
538 };
539 
register_android_bluetooth_BluetoothSocket(JNIEnv * env)540 int register_android_bluetooth_BluetoothSocket(JNIEnv *env) {
541     jclass clazz = env->FindClass("android/bluetooth/BluetoothSocket");
542     if (clazz == NULL)
543         return -1;
544     class_BluetoothSocket = (jclass) env->NewGlobalRef(clazz);
545     field_mType = env->GetFieldID(clazz, "mType", "I");
546     field_mAddress = env->GetFieldID(clazz, "mAddress", "Ljava/lang/String;");
547     field_mPort = env->GetFieldID(clazz, "mPort", "I");
548     field_mAuth = env->GetFieldID(clazz, "mAuth", "Z");
549     field_mEncrypt = env->GetFieldID(clazz, "mEncrypt", "Z");
550     field_mSocketData = env->GetFieldID(clazz, "mSocketData", "I");
551     method_BluetoothSocket_ctor = env->GetMethodID(clazz, "<init>", "(IIZZLjava/lang/String;I)V");
552     return AndroidRuntime::registerNativeMethods(env,
553         "android/bluetooth/BluetoothSocket", sMethods, NELEM(sMethods));
554 }
555 
556 } /* namespace android */
557 
558