*/
#include <bluetooth.h>
+#include <map>
#include "vine-data-path-plugin.h"
#include "vine-log.h"
VINE_GATT_ROLE_CLIENT,
} vine_gatt_role_e;
+typedef struct vine_gatt_s vine_gatt_s;
+
typedef struct {
char *buf;
size_t len;
} gatt_data_s;
typedef struct {
+ bt_gatt_server_h server;
+ std::map<std::string, vine_gatt_s *> *client_list;
+} gatt_server_s;
+
+typedef struct {
+ bt_gatt_client_h client;
+ bool is_accepted;
+} gatt_client_s;
+
+struct vine_gatt_s {
bt_gatt_h service;
bt_gatt_h characteristic;
bt_gatt_h descriptor;
vine_gatt_role_e type;
union {
- bt_gatt_server_h server;
- bt_gatt_client_h client;
+ gatt_server_s *server;
+ gatt_client_s *client;
} role;
VineQueue<gatt_data_s *> *recv_buffer;
-
- char *remote_address; // this is used for VINE_GATT_ROLE_CLIENT only.
- bool is_accepted;
+ char *remote_address;
void *user; // vine_data_path_h
-} vine_gatt_s;
+};
static vine_dp_plugin_callbacks g_callbacks = {
.pollfd_cb = NULL,
free(data);
}
-static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data)
+static gatt_server_s *_create_gatt_server(bt_gatt_server_h gatt_server)
{
- if (!g_callbacks.accepted_cb)
- return;
+ RET_VAL_IF(gatt_server == NULL, NULL, "Invalid parameter.");
- vine_gatt_s *accepted_gatt = _create_gatt();
- RET_IF(accepted_gatt == NULL, "Failed to create accepted_gatt.");
+ gatt_server_s *server = (gatt_server_s *)calloc(1, sizeof(gatt_server_s));
+ RET_VAL_IF(server == NULL, NULL, "Out of memory.");
- accepted_gatt->type = VINE_GATT_ROLE_CLIENT;
- accepted_gatt->remote_address = STRDUP(remote_address);
+ server->server = gatt_server;
+ server->client_list = new std::map<std::string, vine_gatt_s *>;
+ return server;
+}
- // refer to server's gatt handles.
- accepted_gatt->service = gatt->service;
- accepted_gatt->characteristic = gatt->characteristic;
- accepted_gatt->descriptor = gatt->descriptor;
+static void _destroy_gatt_server(gatt_server_s *server)
+{
+ RET_IF(server == NULL, "Invalid parameter.");
+ bt_gatt_server_destroy(server->server);
+ server->server = NULL;
+ delete server->client_list;
+}
- accepted_gatt->is_accepted = true;
- accepted_gatt->user = user_data;
+static gatt_client_s *_create_gatt_client(bt_gatt_client_h gatt_client, bool is_accepted)
+{
+ gatt_client_s *client = (gatt_client_s *)calloc(1, sizeof(gatt_client_s));
+ RET_VAL_IF(client == NULL, NULL, "Out of memory.");
- g_callbacks.accepted_cb(VINE_DP_NOT_IP, accepted_gatt->remote_address, 0, accepted_gatt, user_data);
+ client->client = gatt_client; // gatt_client can be NULL.
+ client->is_accepted = is_accepted;
+ return client;
+}
+
+static void _destroy_gatt_client(gatt_client_s *client)
+{
+ RET_IF(client == NULL, "Invalid parameter.");
+ bt_gatt_client_destroy(client->client);
+ client->client = NULL;
+}
+
+static vine_gatt_s *__find_client_gatt(vine_gatt_s *gatt, const char *address)
+{
+ RET_VAL_IF(gatt == NULL, NULL, "Invalid parameter.");
+ RET_VAL_IF(address == NULL, NULL, "Invalid parameter.");
+ RET_VAL_IF(gatt->role.server == NULL, NULL, "Invalid parameter.");
+ RET_VAL_IF(gatt->role.server->client_list == NULL, NULL, "Invalid parameter.");
+
+ std::map<std::string, vine_gatt_s *>::iterator it;
+
+ it = gatt->role.server->client_list->find(address);
+ if (it == gatt->role.server->client_list->end())
+ return NULL;
+
+ return (vine_gatt_s *)it->second;
+}
+
+static void __invoke_accepted_cb(vine_gatt_s *gatt, void *user_data)
+{
+ if (!g_callbacks.accepted_cb)
+ return;
+ g_callbacks.accepted_cb(VINE_DP_NOT_IP, gatt->remote_address, 0, gatt, user_data);
}
static void __invoke_connected_cb(int result, void *user_data)
VINE_LOGI("Got write value requestment from %s.", remote_address);
vine_gatt_s *gatt = (vine_gatt_s *)user_data;
+ vine_gatt_s *client_gatt = __find_client_gatt(gatt, remote_address);
+ RET_IF(client_gatt == NULL, "Cannot find a client[%s].", remote_address);
// TODO: Need to handle splited data using offset.
gatt_data_s *recv_data = __create_gatt_data(value, len, true);
RET_IF(recv_data == NULL, "recv_data is NULL");
- gatt->recv_buffer->push(recv_data);
+ client_gatt->recv_buffer->push(recv_data);
VINE_LOGI("Write value requested. offset[%d] len[%d] reponse_needed[%d]",
offset, len, response_needed);
VINE_LOGE("bt_gatt_server_send_response() is failed.");
if (g_callbacks.received_cb)
- g_callbacks.received_cb(len, gatt->user);
+ g_callbacks.received_cb(len, client_gatt->user);
}
void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server,
bt_gatt_client_h client = NULL;
bt_gatt_h service = NULL;
bt_gatt_h characteristic = NULL;
- int ret;
+ int ret = BT_ERROR_OPERATION_FAILED;
ret = bt_gatt_client_create(remote_address, &client);
if (ret != BT_ERROR_NONE || !client)
if (ret != BT_ERROR_NONE)
goto ERR;
- gatt->role.client = client;
+ gatt->role.client = _create_gatt_client(client, false);
+ if (!gatt->role.client)
+ goto ERR;
+
gatt->service = service;
gatt->characteristic = characteristic;
+ gatt->remote_address = STRDUP(remote_address);
- VINE_LOGE("Succeeded to update GATT service info.");
+ VINE_LOGI("Succeeded to update GATT service info.");
return VINE_DATA_PATH_ERROR_NONE;
ERR:
return __convert_bt_error_to_data_path_error(ret);
}
+static vine_gatt_s *__create_accepted_gatt(const char *remote_address, vine_gatt_s *gatt, void *user)
+{
+ vine_gatt_s *accepted_gatt = _create_gatt();
+ RET_VAL_IF(accepted_gatt == NULL, NULL, "Failed to create accepted_gatt.");
+
+ accepted_gatt->type = VINE_GATT_ROLE_CLIENT;
+ accepted_gatt->role.client = _create_gatt_client(NULL, true);
+ if (!accepted_gatt->role.client) {
+ VINE_LOGE("Failed to create accepted_gatt.");
+ free(accepted_gatt);
+ return NULL;
+ }
+
+ accepted_gatt->remote_address = STRDUP(remote_address);
+ // refer to server's gatt handles.
+ accepted_gatt->service = gatt->service;
+ accepted_gatt->characteristic = gatt->characteristic;
+ accepted_gatt->descriptor = gatt->descriptor;
+
+ accepted_gatt->user = user;
+ return accepted_gatt;
+}
+
+static void __handle_connected_client(vine_gatt_s *gatt, const char *address)
+{
+ RET_IF(gatt == NULL, "Invalid parameter.");
+ RET_IF(address == NULL, "Invalid parameter.");
+ RET_IF(gatt->role.server == NULL || gatt->role.server->client_list == NULL, "Invalid parameter.");
+
+ vine_gatt_s *accepted_gatt = __create_accepted_gatt(address, gatt, gatt->user);
+ RET_IF(accepted_gatt == NULL, "Failed to create accepted gatt.");
+
+ gatt->role.server->client_list->insert(std::make_pair(string(address), accepted_gatt));
+ __invoke_accepted_cb(accepted_gatt, accepted_gatt->user);
+ VINE_LOGI("%s is connected.", address);
+}
+
+static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address)
+{
+ RET_IF(gatt == NULL, "Invalid parameter.");
+ RET_IF(address == NULL, "Invalid parameter.");
+ RET_IF(gatt->role.server == NULL || gatt->role.server->client_list, "Invalid parameter.");
+
+ vine_gatt_s *client_gatt = __find_client_gatt(gatt, address);
+ RET_IF(client_gatt == NULL, "Cannot find a client[%s].", address);
+
+ gatt->role.server->client_list->erase(address);
+ __invoke_terminated_cb(client_gatt->user);
+ VINE_LOGI("%s is disconnected.", address);
+}
+
static void __gatt_connection_state_changed_cb(int result, bool connected,
const char *remote_address, void *user_data)
{
vine_gatt_s *gatt = (vine_gatt_s *)user_data;
- VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s]",
- gatt, result, connected, remote_address);
+ VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s] role[%d]",
+ gatt, result, connected, remote_address, gatt->type);
if (!connected) {
- __invoke_terminated_cb(gatt->user);
+ if (gatt->type == VINE_GATT_ROLE_SERVER)
+ __handle_disconnected_client(gatt, remote_address);
+ else
+ __invoke_terminated_cb(gatt->user);
return;
}
- if (gatt->type == VINE_GATT_ROLE_SERVER) {
- __invoke_accepted_cb(remote_address, gatt, gatt->user);
+ if (gatt->type == VINE_GATT_ROLE_SERVER && gatt->role.server) {
+ __handle_connected_client(gatt, remote_address);
} else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) {
bt_gatt_disconnect(remote_address);
vine_gatt_s *gatt = (vine_gatt_s *)handle;
if (gatt->type == VINE_GATT_ROLE_SERVER) {
- bt_gatt_server_destroy(gatt->role.server);
+ _destroy_gatt_server(gatt->role.server);
gatt->role.server = NULL;
bt_gatt_service_destroy(gatt->service);
bt_gatt_characteristic_destroy(gatt->characteristic);
bt_gatt_descriptor_destroy(gatt->descriptor);
} else if (gatt->type == VINE_GATT_ROLE_CLIENT) {
// bt_gatt_h handles will be freed during bt_gatt_client_destroy().
- bt_gatt_client_destroy(gatt->role.client);
+ _destroy_gatt_client(gatt->role.client);
gatt->role.client = NULL;
}
}
gatt->type = VINE_GATT_ROLE_SERVER;
- gatt->role.server = server;
+ gatt->role.server = _create_gatt_server(server);
+ if (gatt->role.server == NULL)
+ goto ERR;
+
gatt->service = service;
gatt->characteristic = characteristic;
gatt->descriptor = descriptor;
RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL");
vine_gatt_s *gatt = (vine_gatt_s *)handle;
- bt_gatt_client_h client = NULL;
int ret;
+ gatt->type = VINE_GATT_ROLE_CLIENT;
ret = bt_gatt_connect(addr, false);
if (ret != BT_ERROR_NONE) {
VINE_LOGE("Failed to connect remote LE based service.");
+ gatt->type = VINE_GATT_ROLE_UNKNOWN;
return __convert_bt_error_to_data_path_error(ret);
}
- gatt->type = VINE_GATT_ROLE_CLIENT;
- gatt->role.client = client;
- gatt->remote_address = STRDUP(addr);
-
VINE_LOGI("Succeed to request to GATT connect.");
return VINE_DATA_PATH_ERROR_NONE;
}
ret =_gatt_write_to_client(gatt, buf, len);
break;
case VINE_GATT_ROLE_CLIENT:
- ret = gatt->is_accepted ? _gatt_write_to_client(gatt, buf, len)
+ if (!gatt->role.client) {
+ ret = VINE_DATA_PATH_ERROR_OPERATION_FAILED;
+ break;
+ }
+ ret = gatt->role.client->is_accepted ? _gatt_write_to_client(gatt, buf, len)
: _gatt_write_to_server(gatt, buf, len);
break;
case VINE_GATT_ROLE_UNKNOWN: