JNIEXPORT void JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2Send (JNIEnv* env, jobject peer, jlong handle, jbyteArray data, jint transmitMTU) { #ifdef BLUECOVE_L2CAP_MTU_TRUNCATE struct l2cap_options opt; if (!l2Get_options(env, handle, &opt)) { return; } #endif //BLUECOVE_L2CAP_MTU_TRUNCATE if (data == NULL) { throwRuntimeException(env, "Invalid argument"); return; } jbyte *bytes = (*env)->GetByteArrayElements(env, data, 0); if (bytes == NULL) { throwRuntimeException(env, "Invalid argument"); return; } int len = (int)(*env)->GetArrayLength(env, data); if (len > transmitMTU) { len = transmitMTU; } #ifdef BLUECOVE_L2CAP_MTU_TRUNCATE if (len > opt.omtu) { len = opt.omtu; } #endif //BLUECOVE_L2CAP_MTU_TRUNCATE int count = send(handle, (char *)bytes, len, 0); if (count < 0) { throwIOException(env, "Failed to write. [%d] %s", errno, strerror(errno)); } (*env)->ReleaseByteArrayElements(env, data, bytes, 0); }
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2GetTransmitMTU (JNIEnv* env, jobject peer, jlong handle) { struct l2cap_options opt; if (l2Get_options(env, handle, &opt)) { return opt.omtu; } else { return 0; } }
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2OpenClientConnectionImpl (JNIEnv* env, jobject peer, jlong localDeviceBTAddress, jlong address, jint channel, jboolean authenticate, jboolean encrypt, jint receiveMTU, jint transmitMTU, jint timeout) { debug("CONNECT connect, psm %d", channel); // allocate socket int handle = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (handle < 0) { throwIOException(env, "Failed to create socket. [%d] %s", errno, strerror(errno)); return 0; } struct sockaddr_l2 localAddr; //bind local address localAddr.l2_family = AF_BLUETOOTH; localAddr.l2_psm = 0; //bacpy(&localAddr.l2_bdaddr, BDADDR_ANY); longToDeviceAddr(localDeviceBTAddress, &localAddr.l2_bdaddr); if (bind(handle, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) { throwIOException(env, "Failed to bind socket. [%d] %s", errno, strerror(errno)); close(handle); return 0; } // Set link mtu and security options struct l2cap_options opt; socklen_t opt_len = sizeof(opt); memset(&opt, 0, opt_len); opt.imtu = receiveMTU; opt.omtu = (transmitMTU > 0)?transmitMTU:L2CAP_DEFAULT_MTU; opt.flush_to = L2CAP_DEFAULT_FLUSH_TO; Edebug("L2CAP set imtu %i, omtu %i", opt.imtu, opt.omtu); if (setsockopt(handle, SOL_L2CAP, L2CAP_OPTIONS, &opt, opt_len) < 0) { throwIOException(env, "Failed to set L2CAP mtu options. [%d] %s", errno, strerror(errno)); close(handle); return 0; } if (encrypt || authenticate) { int socket_opt = 0; socklen_t len = sizeof(socket_opt); if (getsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, &len) < 0) { throwIOException(env, "Failed to read L2CAP link mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } //if (master) { // socket_opt |= L2CAP_LM_MASTER; //} if (authenticate) { socket_opt |= L2CAP_LM_AUTH; Edebug("L2CAP set authenticate"); } if (encrypt) { socket_opt |= L2CAP_LM_ENCRYPT; } if ((socket_opt != 0) && setsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, sizeof(socket_opt)) < 0) { throwIOException(env, "Failed to set L2CAP link mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } } struct sockaddr_l2 remoteAddr; remoteAddr.l2_family = AF_BLUETOOTH; longToDeviceAddr(address, &remoteAddr.l2_bdaddr); remoteAddr.l2_psm = channel; // connect to server if (connect(handle, (struct sockaddr*)&remoteAddr, sizeof(remoteAddr)) != 0) { throwIOException(env, "Failed to connect. [%d] %s", errno, strerror(errno)); close(handle); return 0; } debug("L2CAP connected, handle %li", handle); struct l2cap_options copt; if (!l2Get_options(env, handle, &copt)) { close(handle); return 0; } debug("L2CAP imtu %i, omtu %i", copt.imtu, copt.omtu); return handle; }
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2Receive (JNIEnv* env, jobject peer, jlong handle, jbyteArray inBuf) { #ifdef BLUECOVE_L2CAP_MTU_TRUNCATE struct l2cap_options opt; if (!l2Get_options(env, handle, &opt)) { return 0; } #endif //BLUECOVE_L2CAP_MTU_TRUNCATE bool dataReady = false; while(!dataReady) { struct pollfd fds; int timeout = 10; // milliseconds fds.fd = handle; fds.events = POLLIN | POLLHUP | POLLERR;// | POLLRDHUP; fds.revents = 0; if (poll(&fds, 1, timeout) > 0) { if (fds.revents & (POLLHUP | POLLERR /*| POLLRDHUP*/)) { throwIOException(env, "Peer closed connection"); return 0; } else if (fds.revents & POLLIN) { dataReady = true; } } if(isCurrentThreadInterrupted(env, peer)) { return 0; } } jbyte *bytes = (*env)->GetByteArrayElements(env, inBuf, 0); size_t inBufLen = (size_t)(*env)->GetArrayLength(env, inBuf); int readLen = inBufLen; #ifdef BLUECOVE_L2CAP_MTU_TRUNCATE if (readLen > opt.imtu) { readLen = opt.imtu; } #endif //BLUECOVE_L2CAP_MTU_TRUNCATE #ifdef BLUECOVE_L2CAP_USE_MSG int flags = 0; iovec iov; msghdr msg; memset((void*)&iov, 0, sizeof(iov)); memset((void*)&msg, 0, sizeof(msg)); iov.iov_base = bytes; iov.iov_len = readLen; msg.msg_iov = &iov; msg.msg_iovlen = 1; int count = recvmsg(handle, &msg, flags); #else int count = recv(handle, (char *)bytes, readLen, 0); #endif //BLUECOVE_L2CAP_USE_MSG if (count < 0) { throwIOException(env, "Failed to read. [%d] %s", errno, strerror(errno)); count = 0; } (*env)->ReleaseByteArrayElements(env, inBuf, bytes, 0); debug("receive[] returns %i", count); return count; }