diff options
author | Sharvil Nanavati <sharvil@google.com> | 2014-08-22 13:44:24 -0700 |
---|---|---|
committer | Andre Eisenbach <eisenbach@google.com> | 2015-03-16 16:51:29 -0700 |
commit | 284440f0c9f9fe15b162e37ef2bf6af439407447 (patch) | |
tree | 38ba15cc1643021d721b34c8b2eaeedfcf73fc67 | |
parent | 3b72a14c2515c1169d5501ada5499cf232fc643b (diff) | |
download | android_system_bt-284440f0c9f9fe15b162e37ef2bf6af439407447.tar.gz android_system_bt-284440f0c9f9fe15b162e37ef2bf6af439407447.tar.bz2 android_system_bt-284440f0c9f9fe15b162e37ef2bf6af439407447.zip |
Refactor RFCOMM code; also fixes a random-disconnect / performance bug.
The majority of this change is just style cleanup and eliminating
unnecessary code. There was a bug in the code where, if an entire
data buffer gets successfully written to the app, the rest of the
queue is not drained and the connection may get dropped. This bug
came about due to an early function exit from a switch statement
instead of breaking out of the switch.
-rw-r--r-- | btif/src/btif_sock_rfc.c | 1614 |
1 files changed, 700 insertions, 914 deletions
diff --git a/btif/src/btif_sock_rfc.c b/btif/src/btif_sock_rfc.c index 65cc2ee63..7ff36cb7c 100644 --- a/btif/src/btif_sock_rfc.c +++ b/btif/src/btif_sock_rfc.c @@ -16,80 +16,62 @@ * ******************************************************************************/ -/************************************************************************************ - * - * Filename: btif_sock_rfc.c - * - * Description: Handsfree Profile Bluetooth Interface - * - ***********************************************************************************/ +#define LOG_TAG "btif_sock_rfcomm" + #include <assert.h> +#include <cutils/log.h> +#include <errno.h> #include <hardware/bluetooth.h> #include <hardware/bt_sock.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <errno.h> #include <sys/ioctl.h> - -#define LOG_TAG "BTIF_SOCK" -#include "btif_common.h" -#include "btif_util.h" +#include <sys/socket.h> +#include <sys/types.h> +#include <utils/Log.h> #include "bd.h" - #include "bta_api.h" -#include "btif_sock_thread.h" +#include "bt_target.h" +#include "bta_jv_api.h" +#include "bta_jv_co.h" +#include "btif_common.h" #include "btif_sock_sdp.h" +#include "btif_sock_thread.h" #include "btif_sock_util.h" - -#include "bt_target.h" -#include "gki.h" -#include "hcimsgs.h" -#include "sdp_api.h" -#include "btu.h" +#include "btif_util.h" #include "btm_api.h" #include "btm_int.h" -#include "bta_jv_api.h" -#include "bta_jv_co.h" -#include "port_api.h" +#include "btu.h" +#include "gki.h" +#include "hcimsgs.h" #include "list.h" +#include "osi.h" +#include "port_api.h" +#include "sdp_api.h" -#include <cutils/log.h> -#include <hardware/bluetooth.h> -#define asrt(s) if(!(s)) APPL_TRACE_ERROR("## %s assert %s failed at line:%d ##",__FUNCTION__, #s, __LINE__) - -extern void uuid_to_string(bt_uuid_t *p_uuid, char *str); -static inline void logu(const char* title, const uint8_t * p_uuid) -{ - char uuids[128]; - uuid_to_string((bt_uuid_t*)p_uuid, uuids); - ALOGD("%s: %s", title, uuids); -} - - +#define MAX_RFC_CHANNEL 30 // Maximum number of RFCOMM channels (1-30 inclusive). +#define MAX_RFC_SESSION 7 // Maximum number of devices we can have an RFCOMM connection with. -#define MAX_RFC_CHANNEL 30 -#define MAX_RFC_SESSION BTA_JV_MAX_RFC_SR_SESSION //3 by default typedef struct { - int outgoing_congest : 1; - int pending_sdp_request : 1; - int doing_sdp_request : 1; - int server : 1; - int connected : 1; - int closing : 1; + int outgoing_congest : 1; + int pending_sdp_request : 1; + int doing_sdp_request : 1; + int server : 1; + int connected : 1; + int closing : 1; } flags_t; typedef struct { flags_t f; - uint32_t id; + uint32_t id; // Non-zero indicates a valid (in-use) slot. int security; - int scn; + int scn; // Server channel number bt_bdaddr_t addr; uint8_t service_uuid[16]; char service_name[256]; - int fd, app_fd; + int fd; + int app_fd; // Temporary storage for the half of the socketpair that's sent back to upper layers. int mtu; - uint8_t* packet; + uint8_t *packet; int sdp_handle; int rfc_handle; int rfc_port_handle; @@ -99,937 +81,741 @@ typedef struct { static rfc_slot_t rfc_slots[MAX_RFC_CHANNEL]; static uint32_t rfc_slot_id; -static volatile int pth = -1; //poll thread handle +static volatile int pth = -1; // poll thread handle +static pthread_mutex_t slot_lock; + +static rfc_slot_t *find_free_slot(void); +static void cleanup_rfc_slot(rfc_slot_t *rs); static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data); -static void cleanup_rfc_slot(rfc_slot_t* rs); static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data); -static inline BOOLEAN send_app_scn(rfc_slot_t* rs); -static pthread_mutex_t slot_lock; -#define is_init_done() (pth != -1) -static inline void clear_slot_flag(flags_t* f) -{ - memset(f, 0, sizeof(*f)); +static bool send_app_scn(const rfc_slot_t *rs); + +static bool is_init_done(void) { + return pth != -1; } -static inline void bd_copy(UINT8* dest, UINT8* src, BOOLEAN swap) -{ - if (swap) - { - int i; - for (i =0; i < 6 ;i++) - dest[i]= src[5-i]; - } - else memcpy(dest, src, 6); +bt_status_t btsock_rfc_init(int poll_thread_handle) { + pth = poll_thread_handle; + + memset(rfc_slots, 0, sizeof(rfc_slots)); + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) { + rfc_slots[i].scn = -1; + rfc_slots[i].sdp_handle = 0; + rfc_slots[i].fd = INVALID_FD; + rfc_slots[i].app_fd = INVALID_FD; + rfc_slots[i].incoming_queue = list_new(GKI_freebuf); + assert(rfc_slots[i].incoming_queue != NULL); + } + + BTA_JvEnable(jv_dm_cback); + init_slot_lock(&slot_lock); + + return BT_STATUS_SUCCESS; } -static void init_rfc_slots() -{ - int i; - memset(rfc_slots, 0, sizeof(rfc_slot_t)*MAX_RFC_CHANNEL); - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - rfc_slots[i].scn = -1; - rfc_slots[i].sdp_handle = 0; - rfc_slots[i].fd = rfc_slots[i].app_fd = -1; - rfc_slots[i].incoming_queue = list_new(GKI_freebuf); - assert(rfc_slots[i].incoming_queue != NULL); + +void btsock_rfc_cleanup(void) { + pth = -1; + + lock_slot(&slot_lock); + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) + if (rfc_slots[i].id) { + cleanup_rfc_slot(&rfc_slots[i]); + list_free(rfc_slots[i].incoming_queue); + rfc_slots[i].incoming_queue = NULL; } - BTA_JvEnable(jv_dm_cback); - init_slot_lock(&slot_lock); + unlock_slot(&slot_lock); } -bt_status_t btsock_rfc_init(int poll_thread_handle) -{ - pth = poll_thread_handle; - init_rfc_slots(); - return BT_STATUS_SUCCESS; + +static rfc_slot_t *find_free_slot(void) { + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) + if (rfc_slots[i].fd == INVALID_FD) + return &rfc_slots[i]; + return NULL; } -void btsock_rfc_cleanup() -{ - int curr_pth = pth; - pth = -1; - btsock_thread_exit(curr_pth); - lock_slot(&slot_lock); - int i; - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].id) { - cleanup_rfc_slot(&rfc_slots[i]); - list_free(rfc_slots[i].incoming_queue); - } - } - unlock_slot(&slot_lock); + +static rfc_slot_t *find_rfc_slot_by_id(uint32_t id) { + assert(id != 0); + + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) + if (rfc_slots[i].id == id) + return &rfc_slots[i]; + + ALOGE("%s unable to find RFCOMM slot id: %d", __func__, id); + return NULL; } -static inline rfc_slot_t* find_free_slot() -{ - int i; - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].fd == -1) - { - return &rfc_slots[i]; - } + +static rfc_slot_t *find_rfc_slot_by_pending_sdp(void) { + uint32_t min_id = UINT32_MAX; + int slot = -1; + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) + if (rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request && rfc_slots[i].id < min_id) { + min_id = rfc_slots[i].id; + slot = i; } - return NULL; + + return (slot == -1) ? NULL : &rfc_slots[slot]; } -static inline rfc_slot_t* find_rfc_slot_by_id(uint32_t id) -{ - int i; - if(id) - { - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].id == id) - { - return &rfc_slots[i]; - } - } - } - APPL_TRACE_WARNING("invalid rfc slot id: %d", id); - return NULL; + +static bool is_requesting_sdp(void) { + for (size_t i = 0; i < ARRAY_SIZE(rfc_slots); ++i) + if (rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request) + return true; + return false; } -static inline rfc_slot_t* find_rfc_slot_by_pending_sdp() -{ - uint32_t min_id = (uint32_t)-1; - int slot = -1; - int i; - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].id && rfc_slots[i].f.pending_sdp_request) - { - if(rfc_slots[i].id < min_id) - { - min_id = rfc_slots[i].id; - slot = i; - } - } - } - if(0<= slot && slot < MAX_RFC_CHANNEL) - return &rfc_slots[slot]; + +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) { + ALOGE("%s unable to find free RFCOMM slot.", __func__); return NULL; -} -static inline rfc_slot_t* find_rfc_slot_requesting_sdp() -{ - int i; - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].id && rfc_slots[i].f.doing_sdp_request) - return &rfc_slots[i]; - } - APPL_TRACE_DEBUG("can not find any slot is requesting sdp"); + } + + int fds[2] = { INVALID_FD, INVALID_FD }; + if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == -1) { + ALOGE("%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 (uuid) + memcpy(slot->service_uuid, uuid, sizeof(slot->service_uuid)); + else + memset(&slot->service_uuid, 0, sizeof(slot->service_uuid)); + + if (name) + strlcpy(slot->service_name, name, sizeof(slot->service_name)); + + if (addr) + slot->addr = *addr; + + slot->id = rfc_slot_id; + slot->f.server = server; + + return slot; } -static inline rfc_slot_t* find_rfc_slot_by_fd(int fd) -{ - int i; - if(fd >= 0) - { - for(i = 0; i < MAX_RFC_CHANNEL; i++) - { - if(rfc_slots[i].fd == fd) - { - if(rfc_slots[i].id) - return &rfc_slots[i]; - else - { - APPL_TRACE_ERROR("invalid rfc slot id, cannot be 0"); - break; - } - } - } - } +static rfc_slot_t *create_srv_accept_rfc_slot(rfc_slot_t *srv_rs, const bt_bdaddr_t *addr, int open_handle, int new_listen_handle) { + rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, false); + if (!accept_rs) { + ALOGE("%s unable to allocate RFCOMM slot.", __func__); return NULL; + } + + accept_rs->f.server = false; + accept_rs->f.connected = true; + accept_rs->security = srv_rs->security; + accept_rs->mtu = srv_rs->mtu; + accept_rs->role = srv_rs->role; + accept_rs->rfc_handle = open_handle; + accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle); + + srv_rs->rfc_handle = new_listen_handle; + srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle); + + assert(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle); + + // now swap the slot id + uint32_t new_listen_id = accept_rs->id; + accept_rs->id = srv_rs->id; + srv_rs->id = new_listen_id; + + return accept_rs; } -static rfc_slot_t* alloc_rfc_slot(const bt_bdaddr_t *addr, const char* name, const uint8_t* uuid, int channel, int flags, BOOLEAN 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* rs = find_free_slot(); - if(rs) - { - int fds[2] = {-1, -1}; - if(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds)) - { - APPL_TRACE_ERROR("socketpair failed, errno:%d", errno); - return NULL; - } - rs->fd = fds[0]; - rs->app_fd = fds[1]; - rs->security = security; - rs->scn = channel; - if(uuid) - memcpy(rs->service_uuid, uuid, sizeof(rs->service_uuid)); - else memset(rs->service_uuid, 0, sizeof(rs->service_uuid)); - if(name && *name) - strncpy(rs->service_name, name, sizeof(rs->service_name) -1); - if(addr) - rs->addr = *addr; - ++rfc_slot_id; - if(rfc_slot_id == 0) - rfc_slot_id = 1; //skip 0 when wrapped - rs->id = rfc_slot_id; - rs->f.server = server; - } - return rs; -} -// rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, p_open->rem_bda,p_opne->handle, p_open->new_listen_handle); -static inline rfc_slot_t* create_srv_accept_rfc_slot(rfc_slot_t* srv_rs, const bt_bdaddr_t* addr, - int open_handle, int new_listen_handle) -{ - rfc_slot_t *accept_rs = alloc_rfc_slot(addr, srv_rs->service_name, srv_rs->service_uuid, srv_rs->scn, 0, FALSE); - if( accept_rs) - { - clear_slot_flag(&accept_rs->f); - accept_rs->f.server = FALSE; - accept_rs->f.connected = TRUE; - accept_rs->security = srv_rs->security; - accept_rs->mtu = srv_rs->mtu; - accept_rs->role = srv_rs->role; - accept_rs->rfc_handle = open_handle; - accept_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(open_handle); - //now update listen rfc_handle of server slot - srv_rs->rfc_handle = new_listen_handle; - srv_rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(new_listen_handle); - BTIF_TRACE_DEBUG("create_srv_accept__rfc_slot(open_handle: 0x%x, new_listen_handle:" - "0x%x) accept_rs->rfc_handle:0x%x, srv_rs_listen->rfc_handle:0x%x" - ,open_handle, new_listen_handle, accept_rs->rfc_port_handle, srv_rs->rfc_port_handle); - asrt(accept_rs->rfc_port_handle != srv_rs->rfc_port_handle); - //now swap the slot id - uint32_t new_listen_id = accept_rs->id; - accept_rs->id = srv_rs->id; - srv_rs->id = new_listen_id; - - return accept_rs; - } - else - { - APPL_TRACE_ERROR(" accept_rs is NULL %s", __FUNCTION__); - return NULL; - } + +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)); + + *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 (!is_uuid_empty(service_uuid)) { + // Use a pre-defined channel # if the UUID is reserved. + int reserved_channel = get_reserved_rfc_channel(service_uuid); + if (reserved_channel != -1) + channel = reserved_channel; + } else { + service_uuid = UUID_SPP; // Use serial port profile to listen to specified channel + } + + int status = BT_STATUS_FAIL; + lock_slot(&slot_lock); + + rfc_slot_t *slot = alloc_rfc_slot(NULL, service_name, service_uuid, channel, flags, true); + if (!slot) { + ALOGE("%s unable to allocate RFCOMM slot.", __func__); + goto out; + } + + BTA_JvCreateRecordByUser((void *)(uintptr_t)slot->id); + *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_EXCEPTION, slot->id); + + status = BT_STATUS_SUCCESS; + +out:; + unlock_slot(&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) -{ - - APPL_TRACE_DEBUG("btsock_rfc_listen, service_name:%s", service_name); - if(sock_fd == NULL || (service_uuid == NULL && (channel < 1 || channel > MAX_RFC_CHANNEL))) - { - APPL_TRACE_ERROR("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_DEBUG("BTA_JvCreateRecordByUser:%s", service_name); - BTA_JvCreateRecordByUser((void *)(intptr_t)rs->id); - *sock_fd = rs->app_fd; - rs->app_fd = -1; //the fd ownership is transferred to app - if (btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, rs->id)) { - status = BT_STATUS_SUCCESS; - } - else - { - cleanup_rfc_slot(rs); - } + +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; + lock_slot(&slot_lock); + + rfc_slot_t *slot = alloc_rfc_slot(bd_addr, NULL, service_uuid, channel, flags, false); + if (!slot) { + ALOGE("%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) { + ALOGE("%s unable to initiate RFCOMM connection: %d", __func__, ret); + cleanup_rfc_slot(slot); + goto out; } - 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 > MAX_RFC_CHANNEL))) - { - APPL_TRACE_ERROR("invalid rfc channel:%d or sock_fd:%p, uuid:%p", channel, sock_fd, - service_uuid); - return BT_STATUS_PARM_INVALID; + + if (!send_app_scn(slot)) { + ALOGE("%s unable to send channel number.", __func__); + cleanup_rfc_slot(slot); + goto out; } - *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_DEBUG("connecting to rfcomm channel:%d without service discovery", channel); - if(BTA_JvRfcommConnect(rs->security, rs->role, rs->scn, rs->addr.address, - rfcomm_cback, (void*)(intptr_t)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*)(intptr_t)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); - } + } 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; } - unlock_slot(&slot_lock); - return status; + } + + *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:; + unlock_slot(&slot_lock); + return status; } -static int create_server_sdp_record(rfc_slot_t* rs) -{ - int scn = rs->scn; - if(rs->scn > 0) - { - if(BTM_TryAllocateSCN(rs->scn) == FALSE) - { - APPL_TRACE_ERROR("rfc channel:%d already in use", scn); - return FALSE; - } - } - else if((rs->scn = BTM_AllocateSCN()) == 0) - { - APPL_TRACE_ERROR("run out of rfc channels"); - return FALSE; - } - if((rs->sdp_handle = add_rfc_sdp_rec(rs->service_name, rs->service_uuid, rs->scn)) <= 0) - { - return FALSE; +static int create_server_sdp_record(rfc_slot_t *slot) { + if (slot->scn > 0) { + if (!BTM_TryAllocateSCN(slot->scn)) { + ALOGE("%s attempting to allocate fixed channel %d which is already in use.", __func__, slot->scn); + return false; } - return TRUE; + } else if ((slot->scn = BTM_AllocateSCN()) == 0) { + ALOGE("%s unable to allocate RFCOMM server channel.", __func__); + return false; + } + + slot->sdp_handle = add_rfc_sdp_rec(slot->service_name, slot->service_uuid, slot->scn); + return (slot->sdp_handle > 0); } -const char * jv_evt[] = { - "BTA_JV_ENABLE_EVT", - "BTA_JV_SET_DISCOVER_EVT", - "BTA_JV_LOCAL_ADDR_EVT", - "BTA_JV_LOCAL_NAME_EVT", - "BTA_JV_REMOTE_NAME_EVT", - "BTA_JV_SET_ENCRYPTION_EVT", - "BTA_JV_GET_SCN_EVT", - "BTA_JV_GET_PSM_EVT", - "BTA_JV_DISCOVERY_COMP_EVT", - "BTA_JV_SERVICES_LEN_EVT", - "BTA_JV_SERVICE_SEL_EVT", - "BTA_JV_CREATE_RECORD_EVT", - "BTA_JV_UPDATE_RECORD_EVT", - "BTA_JV_ADD_ATTR_EVT", - "BTA_JV_DELETE_ATTR_EVT", - "BTA_JV_CANCEL_DISCVRY_EVT", - - "BTA_JV_L2CAP_OPEN_EVT", - "BTA_JV_L2CAP_CLOSE_EVT", - "BTA_JV_L2CAP_START_EVT", - "BTA_JV_L2CAP_CL_INIT_EVT", - "BTA_JV_L2CAP_DATA_IND_EVT", - "BTA_JV_L2CAP_CONG_EVT", - "BTA_JV_L2CAP_READ_EVT", - "BTA_JV_L2CAP_RECEIVE_EVT", - "BTA_JV_L2CAP_WRITE_EVT", - - "BTA_JV_RFCOMM_OPEN_EVT", - "BTA_JV_RFCOMM_CLOSE_EVT", - "BTA_JV_RFCOMM_START_EVT", - "BTA_JV_RFCOMM_CL_INIT_EVT", - "BTA_JV_RFCOMM_DATA_IND_EVT", - "BTA_JV_RFCOMM_CONG_EVT", - "BTA_JV_RFCOMM_READ_EVT", - "BTA_JV_RFCOMM_WRITE_EVT", - "BTA_JV_RFCOMM_SRV_OPEN_EVT", // 33 /* open status of Server RFCOMM connection */ - "BTA_JV_MAX_EVT" -}; -static inline void free_rfc_slot_scn(rfc_slot_t* rs) -{ - if(rs->scn > 0) - { - if(rs->f.server && !rs->f.closing && rs->rfc_handle) - { - BTA_JvRfcommStopServer(rs->rfc_handle, (void*)(uintptr_t)rs->id); - rs->rfc_handle = 0; - } - if(rs->f.server) - BTM_FreeSCN(rs->scn); - rs->scn = 0; - } + +static void free_rfc_slot_scn(rfc_slot_t *slot) { + if (slot->scn <= 0) + return; + + if(slot->f.server && !slot->f.closing && slot->rfc_handle) { + BTA_JvRfcommStopServer(slot->rfc_handle, (void *)(uintptr_t)slot->id); + slot->rfc_handle = 0; + } + + if (slot->f.server) + BTM_FreeSCN(slot->scn); + slot->scn = 0; } -static void cleanup_rfc_slot(rfc_slot_t* rs) -{ - APPL_TRACE_DEBUG("cleanup slot:%d, fd:%d, scn:%d, sdp_handle:0x%x", rs->id, rs->fd, rs->scn, rs->sdp_handle); - if(rs->fd != -1) - { - shutdown(rs->fd, 2); - close(rs->fd); - rs->fd = -1; - } - if(rs->app_fd != -1) - { - close(rs->app_fd); - rs->app_fd = -1; - } - if(rs->sdp_handle > 0) - { - del_rfc_sdp_rec(rs->sdp_handle); - rs->sdp_handle = 0; - } - if(rs->rfc_handle && !rs->f.closing && !rs->f.server) - { - APPL_TRACE_DEBUG("closing rfcomm connection, rfc_handle:0x%x", rs->rfc_handle); - BTA_JvRfcommClose(rs->rfc_handle, (void*)(uintptr_t)rs->id); - rs->rfc_handle = 0; - } - free_rfc_slot_scn(rs); - list_clear(rs->incoming_queue); - rs->rfc_port_handle = 0; - //cleanup the flag - memset(&rs->f, 0, sizeof(rs->f)); - rs->id = 0; +static void cleanup_rfc_slot(rfc_slot_t *slot) { + if (slot->fd != INVALID_FD) { + shutdown(slot->fd, SHUT_RDWR); + close(slot->fd); + slot->fd = INVALID_FD; + } + + if (slot->app_fd != INVALID_FD) { + close(slot->app_fd); + slot->app_fd = INVALID_FD; + } + + if (slot->sdp_handle > 0) { + del_rfc_sdp_rec(slot->sdp_handle); + slot->sdp_handle = 0; + } + + if (slot->rfc_handle && !slot->f.closing && !slot->f.server) { + BTA_JvRfcommClose(slot->rfc_handle, (void *)(uintptr_t)slot->id); + slot->rfc_handle = 0; + } + + free_rfc_slot_scn(slot); + list_clear(slot->incoming_queue); + + slot->rfc_port_handle = 0; + memset(&slot->f, 0, sizeof(slot->f)); + slot->id = 0; } -static inline BOOLEAN send_app_scn(rfc_slot_t* rs) -{ - if(sock_send_all(rs->fd, (const uint8_t*)&rs->scn, sizeof(rs->scn)) == sizeof(rs->scn)) - { - return TRUE; - } - return FALSE; +static bool send_app_scn(const rfc_slot_t *slot) { + return sock_send_all(slot->fd, (const uint8_t*)&slot->scn, sizeof(slot->scn)) == sizeof(slot->scn); } -static BOOLEAN send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd) -{ -/* - typedef struct { - short size; - bt_bdaddr_t bd_addr; - int channel; - int status; -} __attribute__((packed)) sock_connect_signal_t; -*/ - sock_connect_signal_t cs; - cs.size = sizeof(cs); - cs.bd_addr = *addr; - cs.channel = channel; - cs.status = status; - if(send_fd != -1) - { - if(sock_send_fd(fd, (const uint8_t*)&cs, sizeof(cs), send_fd) == sizeof(cs)) - return TRUE; - else APPL_TRACE_ERROR("sock_send_fd failed, fd:%d, send_fd:%d", fd, send_fd); - } - else if(sock_send_all(fd, (const uint8_t*)&cs, sizeof(cs)) == sizeof(cs)) - { - return TRUE; - } - return FALSE; + +static bool send_app_connect_signal(int fd, const bt_bdaddr_t* addr, int channel, int status, int send_fd) { + sock_connect_signal_t cs; + cs.size = sizeof(cs); + cs.bd_addr = *addr; + cs.channel = channel; + cs.status = status; + + if (send_fd == INVALID_FD) + return sock_send_all(fd, (const uint8_t *)&cs, sizeof(cs)) == sizeof(cs); + + return sock_send_fd(fd, (const uint8_t *)&cs, sizeof(cs), send_fd) == sizeof(cs); } -static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id) -{ - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - if (p_init->status != BTA_JV_SUCCESS) - cleanup_rfc_slot(rs); - else - { - rs->rfc_handle = p_init->handle; - } - } - unlock_slot(&slot_lock); + +static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + if (p_init->status == BTA_JV_SUCCESS) + slot->rfc_handle = p_init->handle; + else + cleanup_rfc_slot(slot); + +out:; + unlock_slot(&slot_lock); } -static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id) -{ - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - if (p_start->status != BTA_JV_SUCCESS) - cleanup_rfc_slot(rs); - else - { - rs->rfc_handle = p_start->handle; - - if(!send_app_scn(rs)) - { - //closed - APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id); - cleanup_rfc_slot(rs); - } - } + +static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + if (p_start->status == BTA_JV_SUCCESS) { + slot->rfc_handle = p_start->handle; + + if (!send_app_scn(slot)) { + ALOGE("%s unable to send server channel number for slot %d.", __func__, slot->id); + cleanup_rfc_slot(slot); } - unlock_slot(&slot_lock); + } else + cleanup_rfc_slot(slot); + +out:; + unlock_slot(&slot_lock); } -static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id) -{ - uint32_t new_listen_slot_id = 0; - lock_slot(&slot_lock); - rfc_slot_t* srv_rs = find_rfc_slot_by_id(id); - if(srv_rs) - { - rfc_slot_t* accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t*)p_open->rem_bda, - p_open->handle, p_open->new_listen_handle); - if(accept_rs) - { - //start monitor the socket - btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id); - btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id); - APPL_TRACE_DEBUG("sending connect signal & app fd:%dto app server to accept() the connection", - accept_rs->app_fd); - APPL_TRACE_DEBUG("server fd:%d, scn:%d", srv_rs->fd, srv_rs->scn); - send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd); - accept_rs->app_fd = -1; //the fd is closed after sent to app - new_listen_slot_id = srv_rs->id; - } - } - unlock_slot(&slot_lock); - return new_listen_slot_id; + +static uint32_t on_srv_rfc_connect(tBTA_JV_RFCOMM_SRV_OPEN *p_open, uint32_t id) { + uint32_t new_listen_slot_id = 0; + lock_slot(&slot_lock); + + rfc_slot_t *srv_rs = find_rfc_slot_by_id(id); + if (!srv_rs) + goto out; + + rfc_slot_t *accept_rs = create_srv_accept_rfc_slot(srv_rs, (const bt_bdaddr_t *)p_open->rem_bda, p_open->handle, p_open->new_listen_handle); + if (!accept_rs) + goto out; + + // Start monitoring the socket. + btsock_thread_add_fd(pth, srv_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_EXCEPTION, srv_rs->id); + btsock_thread_add_fd(pth, accept_rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, accept_rs->id); + send_app_connect_signal(srv_rs->fd, &accept_rs->addr, srv_rs->scn, 0, accept_rs->app_fd); + accept_rs->app_fd = INVALID_FD; // Ownership of the application fd has been transferred. + new_listen_slot_id = srv_rs->id; + +out:; + unlock_slot(&slot_lock); + return new_listen_slot_id; } -static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id) -{ - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs && p_open->status == BTA_JV_SUCCESS) - { - rs->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle); - bd_copy(rs->addr.address, p_open->rem_bda, 0); - //notify app rfc is connected - APPL_TRACE_DEBUG("call send_app_connect_signal, slot id:%d, fd:%d, rfc scn:%d, server:%d", - rs->id, rs->fd, rs->scn, rs->f.server); - if(send_app_connect_signal(rs->fd, &rs->addr, rs->scn, 0, -1)) - { - //start monitoring the socketpair to get call back when app writing data - APPL_TRACE_DEBUG("on_rfc_connect_ind, connect signal sent, slot id:%d, rfc scn:%d, server:%d", - rs->id, rs->scn, rs->f.server); - rs->f.connected = TRUE; - } - else APPL_TRACE_ERROR("send_app_connect_signal failed"); - } - else if(rs) - cleanup_rfc_slot(rs); - unlock_slot(&slot_lock); + +static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + if (p_open->status != BTA_JV_SUCCESS) { + cleanup_rfc_slot(slot); + goto out; + } + + slot->rfc_port_handle = BTA_JvRfcommGetPortHdl(p_open->handle); + memcpy(slot->addr.address, p_open->rem_bda, 6); + + if (send_app_connect_signal(slot->fd, &slot->addr, slot->scn, 0, -1)) + slot->f.connected = true; + else + ALOGE("%s unable to send connect completion signal to caller.", __func__); + +out:; + unlock_slot(&slot_lock); } -static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id) -{ - UNUSED(p_close); - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - APPL_TRACE_DEBUG("on_rfc_close, slot id:%d, fd:%d, rfc scn:%d, server:%d", - rs->id, rs->fd, rs->scn, rs->f.server); - free_rfc_slot_scn(rs); - // rfc_handle already closed when receiving rfcomm close event from stack. - rs->f.connected = FALSE; - cleanup_rfc_slot(rs); - } - unlock_slot(&slot_lock); + +static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE *p_close, uint32_t id) { + lock_slot(&slot_lock); + + // rfc_handle already closed when receiving rfcomm close event from stack. + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (slot) + cleanup_rfc_slot(slot); + + unlock_slot(&slot_lock); } -static void on_rfc_write_done(tBTA_JV_RFCOMM_WRITE *p, uint32_t id) -{ - UNUSED(p); - - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs && !rs->f.outgoing_congest) - { - //mointer the fd for any outgoing data - btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); - } - unlock_slot(&slot_lock); + +static void on_rfc_write_done(UNUSED_ATTR tBTA_JV_RFCOMM_WRITE *p, uint32_t id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (slot && !slot->f.outgoing_congest) + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); + + unlock_slot(&slot_lock); } -static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id) -{ - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - rs->f.outgoing_congest = p->cong ? 1 : 0; - //mointer the fd for any outgoing data - if(!rs->f.outgoing_congest) - btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, rs->id); - } - unlock_slot(&slot_lock); + +static void on_rfc_outgoing_congest(tBTA_JV_RFCOMM_CONG *p, uint32_t id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (slot) { + slot->f.outgoing_congest = p->cong ? 1 : 0; + if (!slot->f.outgoing_congest) + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_RD, slot->id); + } + + unlock_slot(&slot_lock); } -static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) -{ - int rc; - void* new_user_data = NULL; - APPL_TRACE_DEBUG("event=%s", jv_evt[event]); +static void *rfcomm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) { + void *new_user_data = NULL; - switch (event) - { + switch (event) { case BTA_JV_RFCOMM_START_EVT: - on_srv_rfc_listen_started(&p_data->rfc_start, (uintptr_t)user_data); - break; + on_srv_rfc_listen_started(&p_data->rfc_start, (uintptr_t)user_data); + break; case BTA_JV_RFCOMM_CL_INIT_EVT: - on_cl_rfc_init(&p_data->rfc_cl_init, (uintptr_t)user_data); - break; + on_cl_rfc_init(&p_data->rfc_cl_init, (uintptr_t)user_data); + break; case BTA_JV_RFCOMM_OPEN_EVT: - BTA_JvSetPmProfile(p_data->rfc_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN); - on_cli_rfc_connect(&p_data->rfc_open, (uintptr_t)user_data); - break; + BTA_JvSetPmProfile(p_data->rfc_open.handle,BTA_JV_PM_ID_1,BTA_JV_CONN_OPEN); + on_cli_rfc_connect(&p_data->rfc_open, (uintptr_t)user_data); + break; + case BTA_JV_RFCOMM_SRV_OPEN_EVT: - BTA_JvSetPmProfile(p_data->rfc_srv_open.handle,BTA_JV_PM_ALL,BTA_JV_CONN_OPEN); - new_user_data = (void*)(intptr_t)on_srv_rfc_connect(&p_data->rfc_srv_open, (uintptr_t)user_data); - break; + BTA_JvSetPmProfile(p_data->rfc_srv_open.handle,BTA_JV_PM_ALL,BTA_JV_CONN_OPEN); + new_user_data = (void *)(uintptr_t)on_srv_rfc_connect(&p_data->rfc_srv_open, (uintptr_t)user_data); + break; case BTA_JV_RFCOMM_CLOSE_EVT: - APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: user_data:%d", (uintptr_t)user_data); - on_rfc_close(&p_data->rfc_close, (uintptr_t)user_data); - break; - - case BTA_JV_RFCOMM_READ_EVT: - APPL_TRACE_DEBUG("BTA_JV_RFCOMM_READ_EVT not used"); - break; + APPL_TRACE_DEBUG("BTA_JV_RFCOMM_CLOSE_EVT: user_data:%d", (uintptr_t)user_data); + on_rfc_close(&p_data->rfc_close, (uintptr_t)user_data); + break; case BTA_JV_RFCOMM_WRITE_EVT: - on_rfc_write_done(&p_data->rfc_write, (uintptr_t)user_data); - break; + on_rfc_write_done(&p_data->rfc_write, (uintptr_t)user_data); + break; + + case BTA_JV_RFCOMM_CONG_EVT: + on_rfc_outgoing_congest(&p_data->rfc_cong, (uintptr_t)user_data); + break; + case BTA_JV_RFCOMM_READ_EVT: case BTA_JV_RFCOMM_DATA_IND_EVT: - APPL_TRACE_DEBUG("BTA_JV_RFCOMM_DATA_IND_EVT not used"); - break; + // Unused. + break; - case BTA_JV_RFCOMM_CONG_EVT: - //on_rfc_cong(&p_data->rfc_cong); - on_rfc_outgoing_congest(&p_data->rfc_cong, (uintptr_t)user_data); - break; default: - APPL_TRACE_ERROR("unhandled event %d, slot id:%d", event, (uintptr_t)user_data); - break; - } - return new_user_data; -} + ALOGE("%s unhandled event %d, slot id: %d", __func__, event, (uintptr_t)user_data); + break; + } + return new_user_data; +} + +static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) { + uint32_t id = (uintptr_t)user_data; + switch(event) { + case BTA_JV_CREATE_RECORD_EVT: { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (slot && create_server_sdp_record(slot)) { + // Start the rfcomm server after sdp & channel # assigned. + BTA_JvRfcommStartServer(slot->security, slot->role, slot->scn, MAX_RFC_SESSION, rfcomm_cback, (void *)(uintptr_t)slot->id); + } else if(slot) { + APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p", slot); + cleanup_rfc_slot(slot); + } + + unlock_slot(&slot_lock); + break; + } + + case BTA_JV_DISCOVERY_COMP_EVT: { + lock_slot(&slot_lock); + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) { + if (slot && slot->f.doing_sdp_request) { + // Establish the connection if we successfully looked up a channel number to connect to. + if (BTA_JvRfcommConnect(slot->security, slot->role, p_data->disc_comp.scn, slot->addr.address, rfcomm_cback, (void *)(uintptr_t)slot->id) == BTA_JV_SUCCESS) { + slot->scn = p_data->disc_comp.scn; + slot->f.doing_sdp_request = false; + if (!send_app_scn(slot)) + cleanup_rfc_slot(slot); + } else { + cleanup_rfc_slot(slot); + } + } else if (slot) { + // TODO(sharvil): this is really a logic error and we should probably assert. + ALOGE("%s SDP response returned but RFCOMM slot %d did not request SDP record.", __func__, id); + } + } else if (slot) { + cleanup_rfc_slot(slot); + } + + // Find the next slot that needs to perform an SDP request and service it. + slot = find_rfc_slot_by_pending_sdp(); + if (slot) { + tSDP_UUID sdp_uuid; + sdp_uuid.len = 16; + memcpy(sdp_uuid.uu.uuid128, slot->service_uuid, sizeof(sdp_uuid.uu.uuid128)); + BTA_JvStartDiscovery((uint8_t *)slot->addr.address, 1, &sdp_uuid, (void *)(uintptr_t)slot->id); + slot->f.pending_sdp_request = false; + slot->f.doing_sdp_request = true; + } -static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) -{ - uint32_t id = (uintptr_t)user_data; - APPL_TRACE_DEBUG("jv_dm_cback: event:%d, slot id:%d", event, id); - switch(event) - { - case BTA_JV_CREATE_RECORD_EVT: - { - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs && create_server_sdp_record(rs)) - { - //now start the rfcomm server after sdp & channel # assigned - BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION, rfcomm_cback, - (void*)(uintptr_t)rs->id); - } - else if(rs) - { - APPL_TRACE_ERROR("jv_dm_cback: cannot start server, slot found:%p", rs); - cleanup_rfc_slot(rs); - } - unlock_slot(&slot_lock); - break; - } - case BTA_JV_DISCOVERY_COMP_EVT: - { - rfc_slot_t* rs = NULL; - lock_slot(&slot_lock); - if(p_data->disc_comp.status == BTA_JV_SUCCESS && p_data->disc_comp.scn) - { - APPL_TRACE_DEBUG("BTA_JV_DISCOVERY_COMP_EVT, slot id:%d, status:%d, scn:%d", - id, p_data->disc_comp.status, p_data->disc_comp.scn); - - rs = find_rfc_slot_by_id(id); - if(rs && rs->f.doing_sdp_request) - { - if(BTA_JvRfcommConnect(rs->security, rs->role, p_data->disc_comp.scn, rs->addr.address, - rfcomm_cback, (void*)(uintptr_t)rs->id) == BTA_JV_SUCCESS) - { - rs->scn = p_data->disc_comp.scn; - rs->f.doing_sdp_request = FALSE; - if(!send_app_scn(rs)) - cleanup_rfc_slot(rs); - } - else cleanup_rfc_slot(rs); - } - else if(rs) - { - APPL_TRACE_ERROR("DISCOVERY_COMP_EVT no pending sdp request, slot id:%d, \ - flag sdp pending:%d, flag sdp doing:%d", - id, rs->f.pending_sdp_request, rs->f.doing_sdp_request); - } - } - else - { - APPL_TRACE_ERROR("DISCOVERY_COMP_EVT slot id:%d, failed to find channle, \ - status:%d, scn:%d", id, p_data->disc_comp.status, - p_data->disc_comp.scn); - rs = find_rfc_slot_by_id(id); - if(rs) - cleanup_rfc_slot(rs); - } - rs = find_rfc_slot_by_pending_sdp(); - if(rs) - { - APPL_TRACE_DEBUG("BTA_JV_DISCOVERY_COMP_EVT, start another pending scn sdp request"); - tSDP_UUID sdp_uuid; - sdp_uuid.len = 16; - memcpy(sdp_uuid.uu.uuid128, rs->service_uuid, sizeof(sdp_uuid.uu.uuid128)); - BTA_JvStartDiscovery((UINT8*)rs->addr.address, 1, &sdp_uuid, (void*)(uintptr_t)rs->id); - rs->f.pending_sdp_request = FALSE; - rs->f.doing_sdp_request = TRUE; - } - unlock_slot(&slot_lock); - break; - } - default: - APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id); - break; + unlock_slot(&slot_lock); + break; } + default: + APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id); + break; + } } -#define SENT_ALL 2 -#define SENT_PARTIAL 1 -#define SENT_NONE 0 -#define SENT_FAILED (-1) -static int send_data_to_app(int fd, BT_HDR *p_buf) -{ - if(p_buf->len == 0) - return SENT_ALL; - int sent = send(fd, (UINT8 *)(p_buf + 1) + p_buf->offset, p_buf->len, MSG_DONTWAIT); - if(sent == p_buf->len) - return SENT_ALL; - - if(sent > 0 && sent < p_buf->len) - { - //sent partial - APPL_TRACE_ERROR("send partial, sent:%d, p_buf->len:%d", sent, p_buf->len); - p_buf->offset += sent; - p_buf->len -= sent; - return SENT_PARTIAL; - } - if(sent < 0 && - (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) - { - APPL_TRACE_ERROR("send none, EAGAIN or EWOULDBLOCK, errno:%d", errno); - return SENT_NONE; - } - APPL_TRACE_ERROR("unknown send() error, sent:%d, p_buf->len:%d, errno:%d", sent, p_buf->len, errno); +typedef enum { + SENT_FAILED, + SENT_NONE, + SENT_PARTIAL, + SENT_ALL, +} sent_status_t; + +static sent_status_t send_data_to_app(int fd, BT_HDR *p_buf) { + if (p_buf->len == 0) + return SENT_ALL; + + ssize_t sent = send(fd, p_buf->data + p_buf->offset, p_buf->len, MSG_DONTWAIT); + + if (sent == -1) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + return SENT_NONE; + ALOGE("%s error writing RFCOMM data back to app: %s", __func__, strerror(errno)); return SENT_FAILED; -} -static BOOLEAN flush_incoming_que_on_wr_signal(rfc_slot_t* rs) -{ - while(!list_is_empty(rs->incoming_queue)) - { - BT_HDR *p_buf = list_front(rs->incoming_queue); - int sent = send_data_to_app(rs->fd, p_buf); - switch(sent) - { - case SENT_NONE: - case SENT_PARTIAL: - //monitor the fd to get callback when app is ready to receive data - btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id); - return TRUE; - case SENT_ALL: - list_remove(rs->incoming_queue, p_buf); - break; - case SENT_FAILED: - list_remove(rs->incoming_queue, p_buf); - return FALSE; - } - } + } - //app is ready to receive data, tell stack to start the data flow - //fix me: need a jv flow control api to serialize the call in stack - APPL_TRACE_DEBUG("enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d", - rs->rfc_handle, rs->rfc_port_handle, rs->id); - extern int PORT_FlowControl_MaxCredit(UINT16 handle, BOOLEAN enable); - PORT_FlowControl_MaxCredit(rs->rfc_port_handle, TRUE); - return TRUE; -} -void btsock_rfc_signaled(int fd, int flags, uint32_t user_id) -{ - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(user_id); - if(rs) - { - APPL_TRACE_DEBUG("rfc slot id:%d, fd:%d, flags:%x", rs->id, fd, flags); - BOOLEAN need_close = FALSE; - if(flags & SOCK_THREAD_FD_RD) - { - //data available from app, tell stack we have outgoing data - if(!rs->f.server) - { - if(rs->f.connected) - { - int size = 0; - //make sure there's data pending in case the peer closed the socket - if(!(flags & SOCK_THREAD_FD_EXCEPTION) || - (ioctl(rs->fd, FIONREAD, &size) == 0 && size)) - { - int rfc_handle = rs->rfc_handle; - UINT32 rs_id = rs->id; - //unlock before BTA_JvRfcommWrite to avoid deadlock on concurrnet multi rfcomm connectoins - unlock_slot(&slot_lock); - BTA_JvRfcommWrite(rfc_handle, rs_id); - return; - } - } - else - { - APPL_TRACE_ERROR("SOCK_THREAD_FD_RD signaled when rfc is not connected, \ - slot id:%d, channel:%d", rs->id, rs->scn); - need_close = TRUE; - } - } - } - if(flags & SOCK_THREAD_FD_WR) - { - //app is ready to receive more data, tell stack to enable the data flow - if(!rs->f.connected || !flush_incoming_que_on_wr_signal(rs)) - { - need_close = TRUE; - APPL_TRACE_ERROR("SOCK_THREAD_FD_WR signaled when rfc is not connected \ - or app closed fd, slot id:%d, channel:%d", rs->id, rs->scn); - } + if (sent == 0) + return SENT_FAILED; - } - if(need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) - { - int size = 0; - if(need_close || ioctl(rs->fd, FIONREAD, &size) != 0 || size == 0 ) - { - //cleanup when no data pending - APPL_TRACE_DEBUG("SOCK_THREAD_FD_EXCEPTION, cleanup, flags:%x, need_close:%d, pending size:%d", - flags, need_close, size); - cleanup_rfc_slot(rs); - } - else - APPL_TRACE_DEBUG("SOCK_THREAD_FD_EXCEPTION, cleanup pending, flags:%x, need_close:%d, pending size:%d", - flags, need_close, size); - } - } - unlock_slot(&slot_lock); -} + if (sent == p_buf->len) + return SENT_ALL; -int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) -{ - uint32_t id = (uintptr_t)user_data; - int ret = 0; - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - if(!list_is_empty(rs->incoming_queue)) - list_append(rs->incoming_queue, p_buf); - else - { - int sent = send_data_to_app(rs->fd, p_buf); - switch(sent) - { - case SENT_NONE: - case SENT_PARTIAL: - //add it to the end of the queue - list_append(rs->incoming_queue, p_buf); - //monitor the fd to get callback when app is ready to receive data - btsock_thread_add_fd(pth, rs->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, rs->id); - break; - case SENT_ALL: - GKI_freebuf(p_buf); - ret = 1;//enable the data flow - break; - case SENT_FAILED: - GKI_freebuf(p_buf); - cleanup_rfc_slot(rs); - break; - } - } - } - unlock_slot(&slot_lock); - return ret;//return 0 to disable data flow + p_buf->offset += sent; + p_buf->len -= sent; + return SENT_PARTIAL; } -int bta_co_rfc_data_outgoing_size(void *user_data, int *size) -{ - uint32_t id = (uintptr_t)user_data; - int ret = FALSE; - *size = 0; - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - if(ioctl(rs->fd, FIONREAD, size) == 0) - { - APPL_TRACE_DEBUG("ioctl read avaiable size:%d, fd:%d", *size, rs->fd); - ret = TRUE; - } - else - { - APPL_TRACE_ERROR("ioctl FIONREAD error, errno:%d, fd:%d", errno, rs->fd); - cleanup_rfc_slot(rs); - } + +static bool flush_incoming_que_on_wr_signal(rfc_slot_t *slot) { + while (!list_is_empty(slot->incoming_queue)) { + BT_HDR *p_buf = list_front(slot->incoming_queue); + switch (send_data_to_app(slot->fd, p_buf)) { + case SENT_NONE: + case SENT_PARTIAL: + //monitor the fd to get callback when app is ready to receive data + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, slot->id); + return true; + + case SENT_ALL: + list_remove(slot->incoming_queue, p_buf); + break; + + case SENT_FAILED: + list_remove(slot->incoming_queue, p_buf); + return false; + } + } + + //app is ready to receive data, tell stack to start the data flow + //fix me: need a jv flow control api to serialize the call in stack + APPL_TRACE_DEBUG("enable data flow, rfc_handle:0x%x, rfc_port_handle:0x%x, user_id:%d", + slot->rfc_handle, slot->rfc_port_handle, slot->id); + extern int PORT_FlowControl_MaxCredit(uint16_t handle, bool enable); + PORT_FlowControl_MaxCredit(slot->rfc_port_handle, true); + return true; +} + +void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) { + lock_slot(&slot_lock); + + rfc_slot_t *slot = find_rfc_slot_by_id(user_id); + if (!slot) + goto out; + + bool need_close = false; + + // Data available from app, tell stack we have outgoing data. + if (flags & SOCK_THREAD_FD_RD && !slot->f.server) { + if (slot->f.connected) { + // Make sure there's data pending in case the peer closed the socket. + int size = 0; + if (!(flags & SOCK_THREAD_FD_EXCEPTION) || (ioctl(slot->fd, FIONREAD, &size) == 0 && size)) + BTA_JvRfcommWrite(slot->rfc_handle, slot->id); + } else { + ALOGE("%s socket signaled for read while disconnected, slot: %d, channel: %d", __func__, slot->id, slot->scn); + need_close = true; + } + } + + if (flags & SOCK_THREAD_FD_WR) { + // App is ready to receive more data, tell stack to enable data flow. + if (!slot->f.connected || !flush_incoming_que_on_wr_signal(slot)) { + ALOGE("%s socket signaled for write while disconnected (or write failure), slot: %d, channel: %d", __func__, slot->id, slot->scn); + need_close = true; + } + } + + if (need_close || (flags & SOCK_THREAD_FD_EXCEPTION)) { + // Clean up if there's no data pending. + int size = 0; + if (need_close || ioctl(slot->fd, FIONREAD, &size) != 0 || !size) + cleanup_rfc_slot(slot); + } + +out:; + unlock_slot(&slot_lock); +} + +int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) { + lock_slot(&slot_lock); + + int ret = 0; + uint32_t id = (uintptr_t)user_data; + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + if (list_is_empty(slot->incoming_queue)) { + switch (send_data_to_app(slot->fd, p_buf)) { + case SENT_NONE: + case SENT_PARTIAL: + list_append(slot->incoming_queue, p_buf); + btsock_thread_add_fd(pth, slot->fd, BTSOCK_RFCOMM, SOCK_THREAD_FD_WR, slot->id); + break; + + case SENT_ALL: + GKI_freebuf(p_buf); + ret = 1; // Enable data flow. + break; + + case SENT_FAILED: + GKI_freebuf(p_buf); + cleanup_rfc_slot(slot); + break; } - else APPL_TRACE_ERROR("bta_co_rfc_data_outgoing_size, invalid slot id:%d", id); - unlock_slot(&slot_lock); - return ret; + } else { + list_append(slot->incoming_queue, p_buf); + } + +out:; + unlock_slot(&slot_lock); + return ret; // Return 0 to disable data flow. } -int bta_co_rfc_data_outgoing(void *user_data, UINT8* buf, UINT16 size) -{ - uint32_t id = (uintptr_t)user_data; - int ret = FALSE; - lock_slot(&slot_lock); - rfc_slot_t* rs = find_rfc_slot_by_id(id); - if(rs) - { - int received = recv(rs->fd, buf, size, 0); - if(received == size) - ret = TRUE; - else - { - APPL_TRACE_ERROR("recv error, errno:%d, fd:%d, size:%d, received:%d", - errno, rs->fd, size, received); - cleanup_rfc_slot(rs); - } - } - else APPL_TRACE_ERROR("bta_co_rfc_data_outgoing, invalid slot id:%d", id); - unlock_slot(&slot_lock); - return ret; + +int bta_co_rfc_data_outgoing_size(void *user_data, int *size) { + lock_slot(&slot_lock); + + uint32_t id = (uintptr_t)user_data; + int ret = false; + *size = 0; + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + if (ioctl(slot->fd, FIONREAD, size) == 0) { + ret = true; + } else { + ALOGE("%s unable to determine bytes remaining to be read on fd %d: %s", __func__, slot->fd, strerror(errno)); + cleanup_rfc_slot(slot); + } + +out:; + unlock_slot(&slot_lock); + return ret; } +int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size) { + lock_slot(&slot_lock); + + uint32_t id = (uintptr_t)user_data; + int ret = false; + rfc_slot_t *slot = find_rfc_slot_by_id(id); + if (!slot) + goto out; + + int received = recv(slot->fd, buf, size, 0); + if(received == size) { + ret = true; + } else { + ALOGE("%s error receiving RFCOMM data from app: %s", __func__, strerror(errno)); + cleanup_rfc_slot(slot); + } + +out:; + unlock_slot(&slot_lock); + return ret; +} |