JNIEXPORT jboolean JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_populateServiceRecordAttributeValuesImpl (JNIEnv *env, jobject peer, jlong localDeviceBTAddress, jlong remoteDeviceAddressLong, jlong sdpSession, jlong handle, jintArray attrIDs, jobject serviceRecord) { sdp_session_t* session = (sdp_session_t*)jlong2ptr(sdpSession); sdp_session_t* close_session_on_return = NULL; if (session != NULL) { debug("populateServiceRecordAttributeValuesImpl connected %p, recordHandle %li", session, handle); } else { debug("populateServiceRecordAttributeValuesImpl connects, recordHandle %li", handle); bdaddr_t localAddr; longToDeviceAddr(localDeviceBTAddress, &localAddr); bdaddr_t remoteAddress; longToDeviceAddr(remoteDeviceAddressLong, &remoteAddress); session = sdp_connect(&localAddr, &remoteAddress, SDP_RETRY_IF_BUSY); if (session == NULL) { debug("populateServiceRecordAttributeValuesImpl can't connect"); return JNI_FALSE; } // Close session on exit close_session_on_return = session; } sdp_list_t *attr_list = NULL; jboolean isCopy = JNI_FALSE; jint* ids = (*env)->GetIntArrayElements(env, attrIDs, &isCopy); int i; for(i = 0; i < (*env)->GetArrayLength(env, attrIDs); i++) { uint16_t* id = (uint16_t*)malloc(sizeof(uint16_t)); *id=(uint16_t)ids[i]; attr_list = sdp_list_append(attr_list,id); } jboolean rc = JNI_FALSE; sdp_record_t *sdpRecord = sdp_service_attr_req(session, (uint32_t)handle, SDP_ATTR_REQ_INDIVIDUAL, attr_list); if (!sdpRecord) { debug("sdp_service_attr_req return error"); rc = JNI_FALSE; } else { populateServiceRecord(env, serviceRecord, sdpRecord, attr_list); sdp_record_free(sdpRecord); rc = JNI_TRUE; } sdp_list_free(attr_list, free); if (close_session_on_return != NULL) { sdp_close(close_session_on_return); } return rc; }
JNIEXPORT jstring JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_getRemoteDeviceVersionInfoImpl (JNIEnv *env, jobject peer, jint deviceDescriptor, jlong remoteDeviceAddressLong) { struct hci_conn_info_req *conn_info; struct hci_version ver; char info[256]; conn_info = (struct hci_conn_info_req*)malloc(sizeof(*conn_info) + sizeof(struct hci_conn_info)); if (!conn_info) { throwRuntimeException(env, cOUT_OF_MEMORY); return NULL; } memset(conn_info, 0, sizeof(struct hci_conn_info)); longToDeviceAddr(remoteDeviceAddressLong, &(conn_info->bdaddr)); conn_info->type = ACL_LINK; if (ioctl((int)deviceDescriptor, HCIGETCONNINFO, (unsigned long) conn_info) < 0) { free(conn_info); throwRuntimeException(env, "Fail to get connection info"); return NULL; } int error = hci_read_remote_version((int)deviceDescriptor, conn_info->conn_info->handle, &ver, READ_REMOTE_NAME_TIMEOUT); if (error < 0) { throwRuntimeException(env, "Can not get remote device info"); free(conn_info); return NULL; } snprintf(info, 256, "manufacturer=%i,lmp_version=%i,lmp_sub_version=%i", ver.manufacturer, ver.lmp_ver, ver.lmp_subver); free(conn_info); return (*env)->NewStringUTF(env, info); }
JNIEXPORT jstring JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_getRemoteDeviceFriendlyNameImpl (JNIEnv *env, jobject peer, jint deviceDescriptor, jlong remoteAddress) { bdaddr_t address; longToDeviceAddr(remoteAddress, &address); char name[DEVICE_NAME_MAX_SIZE]; int error = hci_read_remote_name(deviceDescriptor, &address, sizeof(name), name, READ_REMOTE_NAME_TIMEOUT); if (error < 0) { throwIOException(env, "Can not get remote device name"); return NULL; } return (*env)->NewStringUTF(env, name); }
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_getRemoteDeviceRSSIImpl (JNIEnv *env, jobject peer, jint deviceDescriptor, jlong remoteDeviceAddressLong) { struct hci_request rq; struct hci_conn_info_req *conn_info; read_rssi_rp rssi_rp; conn_info = (struct hci_conn_info_req*)malloc(sizeof(*conn_info) + sizeof(struct hci_conn_info)); if (!conn_info) { throwRuntimeException(env, cOUT_OF_MEMORY); return -1; } memset(conn_info, 0, sizeof(struct hci_conn_info)); longToDeviceAddr(remoteDeviceAddressLong, &(conn_info->bdaddr)); conn_info->type = ACL_LINK; if (ioctl((int)deviceDescriptor, HCIGETCONNINFO, (unsigned long) conn_info) < 0) { free(conn_info); throwRuntimeException(env, "Fail to get connection info"); return -1; } memset(&rq, 0, sizeof(rq)); rq.ogf = OGF_STATUS_PARAM; rq.ocf = OCF_READ_RSSI; rq.cparam = &conn_info->conn_info->handle; rq.clen = 2; rq.rparam = &rssi_rp; rq.rlen = READ_RSSI_RP_SIZE; if ((hci_send_req((int)deviceDescriptor, &rq, READ_REMOTE_NAME_TIMEOUT) < 0) || rssi_rp.status) { free(conn_info); throwRuntimeException(env, "Fail to send hci request"); return -1; } free(conn_info); return rssi_rp.rssi; }
JNIEXPORT jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZDBus_connectionRfOpenClientConnectionImpl (JNIEnv* env, jobject peer, jlong localDeviceBTAddress, jlong address, jint channel, jboolean authenticate, jboolean encrypt, jint timeout) { debug("RFCOMM connect, channel %d", channel); // allocate socket int handle = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (handle < 0) { throwIOException(env, "Failed to create socket. [%d] %s", errno, strerror(errno)); return 0; } struct sockaddr_rc localAddr; //bind local address memset(&localAddr, 0, sizeof(localAddr)); localAddr.rc_family = AF_BLUETOOTH; localAddr.rc_channel = 0; //bacpy(&localAddr.rc_bdaddr, BDADDR_ANY); longToDeviceAddr(localDeviceBTAddress, &localAddr.rc_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; } // TODO verify how this works, I think device needs to paird before this can be setup. // Set link security options if (encrypt || authenticate) { int socket_opt = 0; socklen_t len = sizeof(socket_opt); if (getsockopt(handle, SOL_RFCOMM, RFCOMM_LM, &socket_opt, &len) < 0) { throwIOException(env, "Failed to read RFCOMM link mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } //if (master) { // socket_opt |= RFCOMM_LM_MASTER; //} if (authenticate) { socket_opt |= RFCOMM_LM_AUTH; debug("RFCOMM set authenticate"); } if (encrypt) { socket_opt |= RFCOMM_LM_ENCRYPT; } //if (socket_opt != 0) { // socket_opt |= RFCOMM_LM_SECURE; //} if ((socket_opt != 0) && setsockopt(handle, SOL_RFCOMM, RFCOMM_LM, &socket_opt, sizeof(socket_opt)) < 0) { throwIOException(env, "Failed to set RFCOMM link mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } } struct sockaddr_rc remoteAddr; memset(&remoteAddr, 0, sizeof(remoteAddr)); remoteAddr.rc_family = AF_BLUETOOTH; longToDeviceAddr(address, &remoteAddr.rc_bdaddr); remoteAddr.rc_channel = 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("RFCOMM connected, handle %li", handle); return handle; }
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 jlong JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_l2ServerOpenImpl (JNIEnv* env, jobject peer, jlong localDeviceBTAddress, jboolean authorize, jboolean authenticate, jboolean encrypt, jboolean master, jboolean timeouts, jint backlog, jint receiveMTU, jint transmitMTU) { // 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; } // Set link security options if (encrypt || authenticate || authorize || master) { 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 server mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } if (master) { socket_opt |= L2CAP_LM_MASTER; } if (authenticate) { socket_opt |= L2CAP_LM_AUTH; debug("L2CAP set authenticate"); } if (encrypt) { socket_opt |= L2CAP_LM_ENCRYPT; } if (authorize) { socket_opt |= L2CAP_LM_SECURE; } if ((socket_opt != 0) && setsockopt(handle, SOL_L2CAP, L2CAP_LM, &socket_opt, sizeof(socket_opt)) < 0) { throwIOException(env, "Failed to set L2CAP server mode. [%d] %s", errno, strerror(errno)); close(handle); return 0; } } // put socket into listening mode if (listen(handle, backlog) < 0) { throwIOException(env, "Failed to listen for L2CAP connections. [%d] %s", errno, strerror(errno)); close(handle); return 0; } return handle; }
JNIEXPORT jint JNICALL Java_com_intel_bluetooth_BluetoothStackBlueZ_runSearchServicesImpl (JNIEnv *env, jobject peer, jobject searchServicesThread, jlong localDeviceBTAddress, jobjectArray uuidValues, jlong remoteDeviceAddressLong) { // Prepare serviceDiscoveredCallback jclass peerClass = (*env)->GetObjectClass(env, peer); if (peerClass == NULL) { throwRuntimeException(env, "Fail to get Object Class"); return SERVICE_SEARCH_ERROR; } jmethodID serviceDiscoveredCallback = getGetMethodID(env, peerClass, "serviceDiscoveredCallback", "(Lcom/intel/bluetooth/SearchServicesThread;JJ)Z"); if (serviceDiscoveredCallback == NULL) { return SERVICE_SEARCH_ERROR; } sdp_list_t *uuidList = NULL; sdp_list_t *rsp_list = NULL; sdp_session_t *session = NULL; jint rc = SERVICE_SEARCH_ERROR; const uint16_t max_rec_num = 256; int serviceCount = 0; int error; // convert uuid set from java array to bluez sdp_list_t jsize uuidSetSize = (*env)->GetArrayLength(env, uuidValues); jsize i; debug("runSearchServicesImpl uuidSetSize %i", uuidSetSize); for(i = 0; i < uuidSetSize; i++) { jbyteArray byteArray = (jbyteArray)(*env)->GetObjectArrayElement(env, uuidValues, i); uuid_t* uuid = (uuid_t*)malloc(sizeof(uuid_t)); convertUUIDByteArrayToUUID(env, byteArray, uuid); uuidList = sdp_list_append(uuidList, uuid); } // convert remote device address from jlong to bluez bdaddr_t bdaddr_t remoteAddress; longToDeviceAddr(remoteDeviceAddressLong, &remoteAddress); bdaddr_t localAddr; longToDeviceAddr(localDeviceBTAddress, &localAddr); // connect to the device to retrieve services session = sdp_connect(&localAddr, &remoteAddress, SDP_RETRY_IF_BUSY); // if connection is not established throw an exception if (session == NULL) { rc = SERVICE_SEARCH_DEVICE_NOT_REACHABLE; goto searchServicesImplEnd; } // then ask the device for service record handles error = sdp_service_search_req(session, uuidList, max_rec_num, &(rsp_list)); if (error) { debug("sdp_service_search_req error %i", error); rc = SERVICE_SEARCH_ERROR; goto searchServicesImplEnd; } Edebug("runSearchServicesImpl session %p %li", session, ptr2jlong(session)); // Notify java about found services sdp_list_t* handle; for(handle = rsp_list; handle; handle = handle->next) { uint32_t record = *(uint32_t*)handle->data; jlong recordHandle = record; Edebug("runSearchServicesImpl serviceRecordHandle %li", recordHandle); jboolean isTerminated = (*env)->CallBooleanMethod(env, peer, serviceDiscoveredCallback, searchServicesThread, ptr2jlong(session), recordHandle); if ((*env)->ExceptionCheck(env)) { rc = SERVICE_SEARCH_ERROR; goto searchServicesImplEnd; } else if (isTerminated) { rc = SERVICE_SEARCH_TERMINATED; goto searchServicesImplEnd; } serviceCount ++; } debug("runSearchServicesImpl found %i", serviceCount); rc = SERVICE_SEARCH_COMPLETED; searchServicesImplEnd: sdp_list_free(uuidList, free); sdp_list_free(rsp_list, free); if (session != NULL) { sdp_close(session); } return rc; }