bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t *service_uuid, int channel, int *sock_fd, int flags) { assert(sock_fd != NULL); assert(service_uuid != NULL || (channel >= 1 && channel <= MAX_RFC_CHANNEL)); *sock_fd = INVALID_FD; // TODO(sharvil): not sure that this check makes sense; seems like a logic error to call // functions on RFCOMM sockets before initializing the module. Probably should be an assert. if (!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false); if (!slot) { LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__); goto out; } if (is_uuid_empty(service_uuid)) { tBTA_JV_STATUS ret = BTA_JvRfcommConnect(slot->security, slot->role, slot->scn, slot->addr.address, rfcomm_cback, (void *)(uintptr_t)slot->id); if (ret != BTA_JV_SUCCESS) { LOG_ERROR(LOG_TAG, "%s unable to initiate RFCOMM connection: %d", __func__, ret); cleanup_rfc_slot(slot); goto out; } if (!send_app_scn(slot)) { LOG_ERROR(LOG_TAG, "%s unable to send channel number.", __func__); cleanup_rfc_slot(slot); goto out; } } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); if (!is_requesting_sdp()) { BTA_JvStartDiscovery((uint8_t *)bd_addr->address, 1, &sdp_uuid, (void *)(uintptr_t)slot->id); slot->f.pending_sdp_request = false; slot->f.doing_sdp_request = true; } else { slot->f.pending_sdp_request = true; slot->f.doing_sdp_request = false; } } *sock_fd = slot->app_fd; // Transfer ownership of fd to caller. slot->app_fd = INVALID_FD; // Drop our reference to the fd. btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); status = BT_STATUS_SUCCESS; out:; pthread_mutex_unlock(&slot_lock); return status; }
bt_status_t btsock_rfc_listen(const char *service_name, const uint8_t *service_uuid, int channel, int *sock_fd, int flags) { assert(sock_fd != NULL); assert((service_uuid != NULL) || (channel >= 1 && channel <= MAX_RFC_CHANNEL) || ((flags & BTSOCK_FLAG_NO_SDP) != 0)); *sock_fd = INVALID_FD; // TODO(sharvil): not sure that this check makes sense; seems like a logic error to call // functions on RFCOMM sockets before initializing the module. Probably should be an assert. if (!is_init_done()) return BT_STATUS_NOT_READY; if((flags & BTSOCK_FLAG_NO_SDP) == 0) { if(is_uuid_empty(service_uuid)) { APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_uuid not set AND " "BTSOCK_FLAG_NO_SDP is not set - changing to SPP"); service_uuid = UUID_SPP; // Use serial port profile to listen to specified channel } else { //Check the service_uuid. overwrite the channel # if reserved int reserved_channel = get_reserved_rfc_channel(service_uuid); if (reserved_channel > 0) { channel = reserved_channel; } } } int status = BT_STATUS_FAIL; pthread_mutex_lock(&slot_lock); rfc_slot_t *slot = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true); if (!slot) { LOG_ERROR(LOG_TAG, "%s unable to allocate RFCOMM slot.", __func__); goto out; } APPL_TRACE_DEBUG("BTA_JvGetChannelId: service_name: %s - channel: %d", service_name, channel); BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, UINT_TO_PTR(slot->id), channel); *sock_fd = slot->app_fd; // Transfer ownership of fd to caller. /*TODO: * We are leaking one of the app_fd's - either the listen socket, or the connection socket. * WE need to close this in native, as the FD might belong to another process - This is the server socket FD - For accepted connections, we close the FD after passing it to JAVA. - Try to simply remove the = -1 to free the FD at rs cleanup.*/ // close(rs->app_fd); slot->app_fd = INVALID_FD; // Drop our reference to the fd. btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, slot->id); status = BT_STATUS_SUCCESS; out:; pthread_mutex_unlock(&slot_lock); return status; }
static rfc_slot_t *alloc_rfc_slot(const bt_bdaddr_t *addr, const char *name, const uint8_t *uuid, int channel, int flags, bool server) { int security = 0; if(flags & BTSOCK_FLAG_ENCRYPT) security |= server ? BTM_SEC_IN_ENCRYPT : BTM_SEC_OUT_ENCRYPT; if(flags & BTSOCK_FLAG_AUTH) security |= server ? BTM_SEC_IN_AUTHENTICATE : BTM_SEC_OUT_AUTHENTICATE; rfc_slot_t *slot = find_free_slot(); if (!slot) { LOG_ERROR(LOG_TAG, "%s unable to find free RFCOMM slot.", __func__); return NULL; } int fds[2] = { INVALID_FD, INVALID_FD }; if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) { LOG_ERROR(LOG_TAG, "%s error creating socketpair: %s", __func__, strerror(errno)); return NULL; } // Increment slot id and make sure we don't use id=0. if (++rfc_slot_id == 0) rfc_slot_id = 1; slot->fd = fds[0]; slot->app_fd = fds[1]; slot->security = security; slot->scn = channel; if(!is_uuid_empty(uuid)) { memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid)); slot->is_service_uuid_valid = true; } else { memset(slot->service_uuid, 0, sizeof(slot->service_uuid)); slot->is_service_uuid_valid = false; } if(name && *name) { strlcpy(slot->service_name, name, sizeof(slot->service_name)); } else { memset(slot->service_name, 0, sizeof(slot->service_name)); } if (addr) slot->addr = *addr; slot->id = rfc_slot_id; slot->f.server = server; return slot; }
bt_status_t btsock_rfc_listen(const char* service_name, const uint8_t* service_uuid, int channel, int* sock_fd, int flags) { APPL_TRACE_DEBUG1("btsock_rfc_listen, service_name:%s", service_name); if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30))) { APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; if(is_uuid_empty(service_uuid)) service_uuid = UUID_SPP; //use serial port profile to listen to specified channel else { //Check the service_uuid. overwrite the channel # if reserved int reserved_channel = get_reserved_rfc_channel(service_uuid); if(reserved_channel > 0) { channel = reserved_channel; } } int status = BT_STATUS_FAIL; lock_slot(&slot_lock); rfc_slot_t* rs = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, TRUE); if(rs) { APPL_TRACE_DEBUG1("BTA_JvCreateRecordByUser:%s", service_name); BTA_JvCreateRecordByUser((void *)rs->id); *sock_fd = rs->app_fd; rs->app_fd = -1; //the fd ownership is transferred to app status = BT_STATUS_SUCCESS; btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id); } unlock_slot(&slot_lock); return status; }
bt_status_t btsock_rfc_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid, int channel, int* sock_fd, int flags) { if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > 30))) { APPL_TRACE_ERROR3("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; lock_slot(&slot_lock); rfc_slot_t* rs = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE); if(rs) { if(is_uuid_empty(service_uuid)) { APPL_TRACE_DEBUG1("connecting to rfcomm channel:%d without service discovery", channel); if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address, rfcomm_cback, (void*)rs->id) == BTA_JV_SUCCESS) { if(send_app_scn(rs)) { btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); *sock_fd = rs->app_fd; rs->app_fd = -1; //the fd ownership is transferred to app status = BT_STATUS_SUCCESS; } else cleanup_rfc_slot(rs); } else cleanup_rfc_slot(rs); } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); logu("service_uuid", service_uuid); *sock_fd = rs->app_fd; rs->app_fd = -1; //the fd ownership is transferred to app status = BT_STATUS_SUCCESS; rfc_slot_t* rs_doing_sdp = find_rfc_slot_requesting_sdp(); if(rs_doing_sdp == NULL) { BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)rs->id); rs->f.pending_sdp_request = FALSE; rs->f.doing_sdp_request = TRUE; } else { rs->f.pending_sdp_request = TRUE; rs->f.doing_sdp_request = FALSE; } btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); } } unlock_slot(&slot_lock); return status; }
bt_status_t btsock_l2c_connect(const bt_bdaddr_t *bd_addr, const uint8_t* service_uuid, int channel, int* sock_fd, int flags) { if(sock_fd == NULL || (service_uuid == NULL)) { APPL_TRACE_ERROR("invalid sock_fd:%p, uuid:%p", sock_fd, service_uuid); return BT_STATUS_PARM_INVALID; } *sock_fd = -1; if(!is_init_done()) return BT_STATUS_NOT_READY; int status = BT_STATUS_FAIL; lock_slot(&slot_lock); l2c_slot_t* ls = alloc_l2c_slot(bd_addr, NULL, service_uuid, channel, flags, FALSE); if(ls) { ls->f.client = TRUE; if(is_uuid_empty(service_uuid)) { APPL_TRACE_DEBUG("connecting to l2cap channel:%d without service discovery", channel); if(BTA_JvL2capConnect(ls->security, ls->role, ls->psm, 672, ls->addr.address, l2cap_cback, (void*)ls->id) == BTA_JV_SUCCESS) { if(send_app_psm(ls)) { btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->id); *sock_fd = ls->app_fd; ls->app_fd = -1; //the fd ownelship is transferred to app status = BT_STATUS_SUCCESS; } else cleanup_l2c_slot(ls); } else cleanup_l2c_slot(ls); } else { tSDP_UUID sdp_uuid; sdp_uuid.len = 16; memcpy(sdp_uuid.uu.uuid128, service_uuid, sizeof(sdp_uuid.uu.uuid128)); logu("service_uuid", service_uuid); *sock_fd = ls->app_fd; ls->app_fd = -1; //the fd ownelship is transferred to app status = BT_STATUS_SUCCESS; l2c_slot_t* ls_doing_sdp = find_l2c_slot_requesting_sdp(); if(ls_doing_sdp == NULL) { BTA_JvStartDiscovery((UINT8*)bd_addr->address, 1, &sdp_uuid, (void*)(ls->id)); ls->f.pending_sdp_request = FALSE; ls->f.doing_sdp_request = TRUE; } else { ls->f.pending_sdp_request = TRUE; ls->f.doing_sdp_request = FALSE; } btsock_thread_add_fd(pth, ls->fd, BTSOCK_L2CAP, SOCK_THREAD_FD_RD, ls->id); } } unlock_slot(&slot_lock); return status; }