static int getMtuNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH ALOGV(__FUNCTION__); jint type = env->GetIntField(obj, field_mType); struct asocket *s = get_socketData(env, obj); if (type == TYPE_RFCOMM || !s) return L2CAP_MAX_MTU; struct l2cap_options opts; int optlen = sizeof(opts), err; err = getsockopt(s->fd, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen ); if (!err) { return opts.omtu; } else { ALOGV("getsockopt() failed, throwing"); jniThrowIOException(env, errno); } return L2CAP_MAX_MTU; #endif jniThrowIOException(env, ENOSYS); return -1; }
static void abortNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); struct asocket *s = get_socketData(env, obj); if (!s) return; asocket_abort(s); ALOGV("...asocket_abort(%d) complete", s->fd); return; #endif jniThrowIOException(env, ENOSYS); }
static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset, jint length) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); int ret, total; jbyte *b; int sz; struct asocket *s = get_socketData(env, obj); if (!s) return -1; if (jb == NULL) { jniThrowIOException(env, EINVAL); return -1; } sz = env->GetArrayLength(jb); if (offset < 0 || length < 0 || offset + length > sz) { jniThrowIOException(env, EINVAL); return -1; } b = env->GetByteArrayElements(jb, NULL); if (b == NULL) { jniThrowIOException(env, EINVAL); return -1; } total = 0; while (length > 0) { ret = asocket_write(s, &b[offset], length, -1); if (ret < 0) { jniThrowIOException(env, errno); env->ReleaseByteArrayElements(jb, b, JNI_ABORT); return -1; } offset += ret; total += ret; length -= ret; } env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit return (jint)total; #endif jniThrowIOException(env, ENOSYS); return -1; }
static void destroyNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); struct asocket *s = get_socketData(env, obj); int fd = s->fd; if (!s) return; asocket_destroy(s); LOGV("...asocket_destroy(%d) complete", fd); return; #endif jniThrowIOException(env, ENOSYS); }
static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset, jint length) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); int ret; jbyte *b; int sz; struct asocket *s = get_socketData(env, obj); if (!s) return -1; if (jb == NULL) { jniThrowIOException(env, EINVAL); return -1; } sz = env->GetArrayLength(jb); if (offset < 0 || length < 0 || offset + length > sz) { jniThrowIOException(env, EINVAL); return -1; } b = env->GetByteArrayElements(jb, NULL); if (b == NULL) { jniThrowIOException(env, EINVAL); return -1; } ret = asocket_read(s, &b[offset], length, -1); if (ret < 0) { jniThrowIOException(env, errno); env->ReleaseByteArrayElements(jb, b, JNI_ABORT); return -1; } env->ReleaseByteArrayElements(jb, b, 0); return (jint)ret; #endif jniThrowIOException(env, ENOSYS); return -1; }
static jint availableNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); int available; struct asocket *s = get_socketData(env, obj); if (!s) return -1; if (ioctl(s->fd, FIONREAD, &available) < 0) { jniThrowIOException(env, errno); return -1; } return available; #endif jniThrowIOException(env, ENOSYS); return -1; }
static void setAmpPolicyNative(JNIEnv *env, jobject obj, jint amppol) { #ifdef HAVE_BLUETOOTH ALOGV(__FUNCTION__); struct asocket *s = get_socketData(env, obj); if (!s) return; int err; err = setsockopt(s->fd, SOL_BLUETOOTH, BT_AMP_POLICY, &pol, sizeof(amppol)); if (err) { ALOGV("setsockopt() failed, throwing"); jniThrowIOException(env, errno); return; } return; #endif jniThrowIOException(env, ENOSYS); }
static jobject acceptNative(JNIEnv *env, jobject obj, int timeout) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); int fd; jint type; struct sockaddr *addr; socklen_t addr_sz; jstring addr_jstr; char addr_cstr[BTADDR_SIZE]; bdaddr_t *bdaddr; jboolean auth; jboolean encrypt; struct asocket *s = get_socketData(env, obj); if (!s) return NULL; type = env->GetIntField(obj, field_mType); switch (type) { case TYPE_RFCOMM: struct sockaddr_rc addr_rc; addr = (struct sockaddr *)&addr_rc; addr_sz = sizeof(addr_rc); bdaddr = &addr_rc.rc_bdaddr; memset(addr, 0, addr_sz); break; case TYPE_SCO: struct sockaddr_sco addr_sco; addr = (struct sockaddr *)&addr_sco; addr_sz = sizeof(addr_sco); bdaddr = &addr_sco.sco_bdaddr; memset(addr, 0, addr_sz); break; case TYPE_L2CAP: case TYPE_EL2CAP: struct sockaddr_l2 addr_l2; addr = (struct sockaddr *)&addr_l2; addr_sz = sizeof(addr_l2); bdaddr = &addr_l2.l2_bdaddr; memset(addr, 0, addr_sz); break; default: jniThrowIOException(env, ENOSYS); return NULL; } fd = asocket_accept(s, addr, &addr_sz, timeout); ALOGV("...accept(%d, %s) = %d (errno %d)", s->fd, TYPE_AS_STR(type), fd, errno); if (fd < 0) { jniThrowIOException(env, errno); return NULL; } /* Connected - return new BluetoothSocket */ auth = env->GetBooleanField(obj, field_mAuth); encrypt = env->GetBooleanField(obj, field_mEncrypt); get_bdaddr_as_string(bdaddr, addr_cstr); addr_jstr = env->NewStringUTF(addr_cstr); return env->NewObject(class_BluetoothSocket, method_BluetoothSocket_ctor, type, fd, auth, encrypt, addr_jstr, -1); #endif jniThrowIOException(env, ENOSYS); return NULL; }
/* Returns errno instead of throwing, so java can check errno */ static int bindListenNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); jint type; socklen_t addr_sz; struct sockaddr *addr; bdaddr_t bdaddr = android_bluetooth_bdaddr_any(); struct asocket *s = get_socketData(env, obj); if (!s) return EINVAL; type = env->GetIntField(obj, field_mType); switch (type) { case TYPE_RFCOMM: struct sockaddr_rc addr_rc; addr = (struct sockaddr *)&addr_rc; addr_sz = sizeof(addr_rc); memset(addr, 0, addr_sz); addr_rc.rc_family = AF_BLUETOOTH; addr_rc.rc_channel = env->GetIntField(obj, field_mPort); memcpy(&addr_rc.rc_bdaddr, &bdaddr, sizeof(bdaddr_t)); break; case TYPE_SCO: struct sockaddr_sco addr_sco; addr = (struct sockaddr *)&addr_sco; addr_sz = sizeof(addr_sco); memset(addr, 0, addr_sz); addr_sco.sco_family = AF_BLUETOOTH; memcpy(&addr_sco.sco_bdaddr, &bdaddr, sizeof(bdaddr_t)); break; case TYPE_L2CAP: case TYPE_EL2CAP: struct sockaddr_l2 addr_l2; addr = (struct sockaddr *)&addr_l2; addr_sz = sizeof(addr_l2); memset(addr, 0, addr_sz); addr_l2.l2_family = AF_BLUETOOTH; addr_l2.l2_psm = env->GetIntField(obj, field_mPort); memcpy(&addr_l2.l2_bdaddr, &bdaddr, sizeof(bdaddr_t)); break; default: return ENOSYS; } if (bind(s->fd, addr, addr_sz)) { ALOGV("...bind(%d) gave errno %d", s->fd, errno); return errno; } if (listen(s->fd, 1)) { ALOGV("...listen(%d) gave errno %d", s->fd, errno); return errno; } ALOGV("...bindListenNative(%d) success", s->fd); return 0; #endif return ENOSYS; }
static void connectNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH ALOGV("%s", __FUNCTION__); int ret; jint type; const char *c_address; jstring address; bdaddr_t bdaddress; socklen_t addr_sz; struct sockaddr *addr; struct asocket *s = get_socketData(env, obj); int retry = 0; if (!s) return; type = env->GetIntField(obj, field_mType); /* parse address into bdaddress */ address = (jstring) env->GetObjectField(obj, field_mAddress); c_address = env->GetStringUTFChars(address, NULL); if (get_bdaddr(c_address, &bdaddress)) { env->ReleaseStringUTFChars(address, c_address); jniThrowIOException(env, EINVAL); return; } env->ReleaseStringUTFChars(address, c_address); switch (type) { case TYPE_RFCOMM: struct sockaddr_rc addr_rc; addr = (struct sockaddr *)&addr_rc; addr_sz = sizeof(addr_rc); memset(addr, 0, addr_sz); addr_rc.rc_family = AF_BLUETOOTH; addr_rc.rc_channel = env->GetIntField(obj, field_mPort); memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; case TYPE_SCO_WBS: case TYPE_SCO: struct sockaddr_sco addr_sco; addr = (struct sockaddr *)&addr_sco; addr_sz = sizeof(addr_sco); memset(addr, 0, addr_sz); addr_sco.sco_family = AF_BLUETOOTH; addr_sco.is_wbs = (type == TYPE_SCO_WBS); memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; case TYPE_L2CAP: case TYPE_EL2CAP: struct sockaddr_l2 addr_l2; addr = (struct sockaddr *)&addr_l2; addr_sz = sizeof(addr_l2); memset(addr, 0, addr_sz); addr_l2.l2_family = AF_BLUETOOTH; addr_l2.l2_psm = env->GetIntField(obj, field_mPort); memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; default: jniThrowIOException(env, ENOSYS); return; } connect: ret = asocket_connect(s, addr, addr_sz, -1); ALOGV("...connect(%d, %s) = %d (errno %d)", s->fd, TYPE_AS_STR(type), ret, errno); if (ret && errno == EALREADY && retry < 2) { /* workaround for bug 5082381 (EALREADY on ACL collision): * retry the connect. Unfortunately we have to create a new fd. * It's not ideal to switch the fd underneath the object, but * is currently safe */ ALOGD("Hit bug 5082381 (EALREADY on ACL collision), trying workaround"); usleep(100000); retry++; abortNative(env, obj); destroyNative(env, obj); initSocketNative(env, obj); if (env->ExceptionOccurred()) { return; } s = get_socketData(env, obj); //Due to init socket ptr would be updated goto connect; } if (!ret && retry > 0) ALOGD("...workaround ok"); if (ret) jniThrowIOException(env, errno); return; #endif jniThrowIOException(env, ENOSYS); }
static void connectNative(JNIEnv *env, jobject obj) { #ifdef HAVE_BLUETOOTH LOGV(__FUNCTION__); int ret; jint type; const char *c_address; jstring address; bdaddr_t bdaddress; socklen_t addr_sz; struct sockaddr *addr; struct asocket *s = get_socketData(env, obj); if (!s) return; type = env->GetIntField(obj, field_mType); /* parse address into bdaddress */ address = (jstring) env->GetObjectField(obj, field_mAddress); c_address = env->GetStringUTFChars(address, NULL); if (get_bdaddr(c_address, &bdaddress)) { env->ReleaseStringUTFChars(address, c_address); jniThrowIOException(env, EINVAL); return; } env->ReleaseStringUTFChars(address, c_address); switch (type) { case TYPE_RFCOMM: struct sockaddr_rc addr_rc; addr = (struct sockaddr *)&addr_rc; addr_sz = sizeof(addr_rc); memset(addr, 0, addr_sz); addr_rc.rc_family = AF_BLUETOOTH; addr_rc.rc_channel = env->GetIntField(obj, field_mPort); memcpy(&addr_rc.rc_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; case TYPE_SCO: struct sockaddr_sco addr_sco; addr = (struct sockaddr *)&addr_sco; addr_sz = sizeof(addr_sco); memset(addr, 0, addr_sz); addr_sco.sco_family = AF_BLUETOOTH; memcpy(&addr_sco.sco_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; case TYPE_L2CAP: struct sockaddr_l2 addr_l2; addr = (struct sockaddr *)&addr_l2; addr_sz = sizeof(addr_l2); memset(addr, 0, addr_sz); addr_l2.l2_family = AF_BLUETOOTH; addr_l2.l2_psm = env->GetIntField(obj, field_mPort); memcpy(&addr_l2.l2_bdaddr, &bdaddress, sizeof(bdaddr_t)); break; default: jniThrowIOException(env, ENOSYS); return; } ret = asocket_connect(s, addr, addr_sz, -1); LOGV("...connect(%d, %s) = %d (errno %d)", s->fd, TYPE_AS_STR(type), ret, errno); if (ret) jniThrowIOException(env, errno); return; #endif jniThrowIOException(env, ENOSYS); }