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