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