Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf) {
  pthread_mutex_lock(&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 {
    list_append(slot->incoming_queue, p_buf);
  }

out:;
  pthread_mutex_unlock(&slot_lock);
  return ret;  // Return 0 to disable data flow.
}
Ejemplo n.º 3
0
static void on_rfc_close(UNUSED_ATTR tBTA_JV_RFCOMM_CLOSE *p_close, uint32_t id) {
  pthread_mutex_lock(&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);

  pthread_mutex_unlock(&slot_lock);
}
Ejemplo n.º 4
0
void btsock_rfc_cleanup(void) {
  pth = -1;

  pthread_mutex_lock(&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);
  }
  pthread_mutex_unlock(&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_DEBUG1("send_app_scn() failed, close rs->id:%d", rs->id);
                cleanup_rfc_slot(rs);
            }
        }
    }
    unlock_slot(&slot_lock);
}
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]);
    }
    unlock_slot(&slot_lock);
}
static void on_rfc_close(tBTA_JV_RFCOMM_CLOSE * p_close, uint32_t id)
{
    lock_slot(&slot_lock);
    rfc_slot_t* rs = find_rfc_slot_by_id(id);
    if(rs)
    {
        APPL_TRACE_DEBUG4("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);
}
Ejemplo n.º 8
0
static void on_srv_rfc_listen_started(tBTA_JV_RFCOMM_START *p_start, uint32_t id) {
  pthread_mutex_lock(&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;
  } else
    cleanup_rfc_slot(slot);

out:;
  pthread_mutex_unlock(&slot_lock);
}
Ejemplo n.º 9
0
static void on_cl_rfc_init(tBTA_JV_RFCOMM_CL_INIT *p_init, uint32_t id) {
  pthread_mutex_lock(&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:;
  pthread_mutex_unlock(&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* 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);
}
Ejemplo n.º 11
0
void btsock_rfc_signaled(UNUSED_ATTR int fd, int flags, uint32_t user_id) {
  pthread_mutex_lock(&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))
        //unlock before BTA_JvRfcommWrite to avoid deadlock on concurrnet multi rfcomm connectoins
        //concurrnet multi rfcomm connectoins
        pthread_mutex_unlock(&slot_lock);
        BTA_JvRfcommWrite(slot->rfc_handle, slot->id);
    } else {
      LOG_ERROR(LOG_TAG, "%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)) {
      LOG_ERROR(LOG_TAG, "%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:;
  pthread_mutex_unlock(&slot_lock);
}
Ejemplo n.º 12
0
int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size) {
  pthread_mutex_lock(&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 {
    LOG_ERROR(LOG_TAG, "%s error receiving RFCOMM data from app: %s", __func__, strerror(errno));
    cleanup_rfc_slot(slot);
  }

out:;
  pthread_mutex_unlock(&slot_lock);
  return ret;
}
Ejemplo n.º 13
0
int bta_co_rfc_data_outgoing_size(void *user_data, int *size) {
  pthread_mutex_lock(&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 {
    LOG_ERROR(LOG_TAG, "%s unable to determine bytes remaining to be read on fd %d: %s", __func__, slot->fd, strerror(errno));
    cleanup_rfc_slot(slot);
  }

out:;
  pthread_mutex_unlock(&slot_lock);
  return ret;
}
Ejemplo n.º 14
0
static void on_cli_rfc_connect(tBTA_JV_RFCOMM_OPEN *p_open, uint32_t id) {
  pthread_mutex_lock(&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
    LOG_ERROR(LOG_TAG, "%s unable to send connect completion signal to caller.", __func__);

out:;
  pthread_mutex_unlock(&slot_lock);
}
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_DEBUG4("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_DEBUG3("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_ERROR0("send_app_connect_signal failed");
    }
    else if(rs)
        cleanup_rfc_slot(rs);
    unlock_slot(&slot_lock);
}
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data)
{
    uint32_t id = (uint32_t)user_data;
    APPL_TRACE_DEBUG2("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*)rs->id);
                }
                else if(rs)
                {
                    APPL_TRACE_ERROR1("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_DEBUG3("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*)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_ERROR3("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_ERROR3("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_DEBUG0("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*)rs->id);
                    rs->f.pending_sdp_request = FALSE;
                    rs->f.doing_sdp_request = TRUE;
                }
                unlock_slot(&slot_lock);
                break;
            }
Ejemplo n.º 17
0
static void jv_dm_cback(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_data) {
  uint32_t id = PTR_TO_UINT(user_data);
  switch(event) {
    case BTA_JV_GET_SCN_EVT:
    {
      pthread_mutex_lock(&slot_lock);
      rfc_slot_t* rs = find_rfc_slot_by_id(id);
      int new_scn = p_data->scn;

      if(rs && (new_scn != 0))
      {
        rs->scn = new_scn;
        /* BTA_JvCreateRecordByUser will only create a record if a UUID is specified,
         * else it just allocate a RFC channel and start the RFCOMM thread - needed
         * for the java
         * layer to get a RFCOMM channel.
         * If uuid is null the create_sdp_record() will be called from Java when it
         * has received the RFCOMM and L2CAP channel numbers through the sockets.*/

        // Send channel ID to java layer
        if(!send_app_scn(rs)){
          //closed
          APPL_TRACE_DEBUG("send_app_scn() failed, close rs->id:%d", rs->id);
          cleanup_rfc_slot(rs);
        } else {
          if(rs->is_service_uuid_valid == true) {
            // We already have data for SDP record, create it (RFC-only profiles)
            BTA_JvCreateRecordByUser(UINT_TO_PTR(rs->id));
          } else {
            APPL_TRACE_DEBUG("is_service_uuid_valid==false - don't set SDP-record, "
                    "just start the RFCOMM server", rs->id);
            //now start the rfcomm server after sdp & channel # assigned
            BTA_JvRfcommStartServer(rs->security, rs->role, rs->scn, MAX_RFC_SESSION,
                    rfcomm_cback, UINT_TO_PTR(rs->id));
          }
        }
      } else if(rs) {
        APPL_TRACE_ERROR("jv_dm_cback: Error: allocate channel %d, slot found:%p", rs->scn, rs);
        cleanup_rfc_slot(rs);
      }
      pthread_mutex_unlock(&slot_lock);
      break;
    }
    case BTA_JV_GET_PSM_EVT:
    {
      APPL_TRACE_DEBUG("Received PSM: 0x%04x", p_data->psm);
      on_l2cap_psm_assigned(id, p_data->psm);
      break;
    }
    case BTA_JV_CREATE_RECORD_EVT: {
      pthread_mutex_lock(&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);
      }

      pthread_mutex_unlock(&slot_lock);
      break;
    }

    case BTA_JV_DISCOVERY_COMP_EVT: {
      pthread_mutex_lock(&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.
          LOG_ERROR(LOG_TAG, "%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;
      }

      pthread_mutex_unlock(&slot_lock);
      break;
    }

    default:
      APPL_TRACE_DEBUG("unhandled event:%d, slot id:%d", event, id);
      break;
  }
}
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;
}