From 6156563dfaeb364b80e67a95fd9afbb772a7553d Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Wed, 21 Jul 2021 17:21:04 +0900 Subject: [PATCH 01/16] Increate the max length of topic to 1023 Change-Id: I628d3110de89276344a38ecb3d1705f569175bab Signed-off-by: Cheoleun Moon --- include/vine.h | 2 +- src/include/vine-constants.h | 3 ++- src/include/vine-dp.h | 10 +++++--- src/vine-dp.cpp | 60 ++++++++++++++++++++++++++++++++++++++++--- src/vine-service.cpp | 11 ++++---- tests/vine-test/vine-test.cpp | 4 +-- 6 files changed, 74 insertions(+), 16 deletions(-) mode change 100644 => 100755 src/include/vine-constants.h mode change 100644 => 100755 src/include/vine-dp.h mode change 100644 => 100755 src/vine-dp.cpp mode change 100644 => 100755 tests/vine-test/vine-test.cpp diff --git a/include/vine.h b/include/vine.h index 0931fd1..ce20e08 100755 --- a/include/vine.h +++ b/include/vine.h @@ -1078,7 +1078,7 @@ int vine_dp_get_port(vine_dp_h dp, int *port); /** * @brief Sets the topic. Only for Publish-Subscribe type. - * @remarks The length of @a topic should be less than 63 characters. + * @remarks The length of @a topic should be less than 1023 characters. * @since_tizen 6.5 * @param[in] dp The data path handle * @param[in] topic The topic diff --git a/src/include/vine-constants.h b/src/include/vine-constants.h old mode 100644 new mode 100755 index 0f570eb..206f28d --- a/src/include/vine-constants.h +++ b/src/include/vine-constants.h @@ -26,8 +26,9 @@ #define VINE_MAX_HOST_NAME_LEN 255 #define VINE_MAX_IP_LEN 39 // for IPv6 #define VINE_MAX_KEY_LEN 9 +#define VINE_MAX_ATTRIBUTE_LEN 252 -#define VINE_MAX_TOPIC_LEN 63 +#define VINE_MAX_TOPIC_LEN 1023 // Actually, max length of service_type and service_name for ble cannot be restricted strictly. // Even though the constraits is met, the operation can be failed. diff --git a/src/include/vine-dp.h b/src/include/vine-dp.h old mode 100644 new mode 100755 index b389085..06c2aa2 --- a/src/include/vine-dp.h +++ b/src/include/vine-dp.h @@ -98,7 +98,7 @@ protected: void *mTerminatedCbData; }; -class DPServer : DataPath +class DPServer : public DataPath { public: DPServer(void *event_queue); @@ -145,7 +145,7 @@ private: void *mAcceptedCbData; }; -class DPClient : DataPath +class DPClient : public DataPath { public: DPClient(void *event_queue); @@ -204,7 +204,7 @@ enum { #define VINE_DP_PUBSUB_RANK_LEN 6 #define VINE_DP_PUBSUB_OPEN_TIMEOUT_MS 2000 -class DPPubSub : DataPath +class DPPubSub : public DataPath { public: DPPubSub(void *event_queue); @@ -226,9 +226,10 @@ public: virtual int get_remote_port(); virtual int get_ip(vine_address_family_e *addr_family, char **ip); virtual int set_port(int port); - virtual int get_port(){ return mListenPort; }; + virtual int get_port() { return mListenPort; } virtual int update_local_address_info(); virtual int set_topic(std::string topic); + virtual std::string get_topic() { return mTopic; } virtual int set_max_connections(int max_conn); virtual int set_accepted_cb(vine_dp_accepted_cb callback, void *user_data); virtual int unset_accepted_cb(); @@ -285,6 +286,7 @@ private: int create_rank(); int compare_ip_priority(const char *peer_ip); void create_id(char id[]); + std::string get_service_type(const std::string &topic); }; diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp old mode 100644 new mode 100755 index 6ab8e65..250ce19 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -307,6 +307,24 @@ static void _ip_resolved_cb(vine_disc_h disc, vine_service_h service, bool add, } } +static std::string __get_full_topic(const map &attr) +{ + std::string topic; + + for (int i = 0; i < 5; ++i) { + char key[3]; + key[0] = 'T'; + key[1] = '0' + i; + key[2] = 0; + + auto val = attr.find(key); + if (val == attr.end()) + break; + topic += val->second; + } + return topic; +} + static void _service_discovered_cb(vine_disc_h disc, bool available, const char *service_type, const char *service_name, const char *host_name, int port, const map &attr, @@ -318,6 +336,16 @@ static void _service_discovered_cb(vine_disc_h disc, bool available, if (!user_data || !available) return; + DPPubSub *dp = static_cast(user_data); + + std::string discovered_topic = __get_full_topic(attr); + VINE_LOGD("Topic[%s] from attributes", discovered_topic.c_str()); + std::string topic = dp->get_topic(); + if (discovered_topic != topic) { + VINE_LOGD("Topic is not matched [%s] -- [%s]", discovered_topic.c_str(), topic.c_str()); + return; + } + vine_disc_h disc_handle; int ret = vine_disc_create(VINE_DISCOVERY_METHOD_DNS_SD, &disc_handle); RET_IF(ret != VINE_ERROR_NONE, "Fail to create a disc"); @@ -356,7 +384,7 @@ static void _service_discovered_cb(vine_disc_h disc, bool available, ret = vine_disc_resolve_ip(disc_handle, service, _ip_resolved_cb, user_data, - (vine_event_queue_h)static_cast(user_data)->get_eventfd()); + (vine_event_queue_h)static_cast(dp)->get_eventfd()); if (ret != VINE_ERROR_NONE) { VINE_LOGE("Fail to resolve IP. error(%d)", ret); _vine_service_destroy(service); @@ -1126,6 +1154,11 @@ void DPPubSub::create_id(char id[]) VINE_DP_PUBSUB_SERVICE_NAME_PREFIX, rand_str.c_str()); } +std::string DPPubSub::get_service_type(const std::string &topic) +{ + return topic.substr(0, VINE_MAX_SERVICE_TYPE_LEN); +} + int DPPubSub::publish_service() { vine_service_h service; @@ -1136,7 +1169,27 @@ int DPPubSub::publish_service() if (ret != VINE_ERROR_NONE) return ret; - vine_service_set_type(service, mTopic.c_str()); + std::string type = get_service_type(mTopic); + vine_service_set_type(service, type.c_str()); + + int attr_num = 0; + int pos = 0; + + // The maximum length of topic is 1024. + // The length of value is at most (VINE_MAX_ATTRIBUTE_LEN(252) - key length(2) - 1 = 249) + // Therefore, at most five attributes can be added for a topic. + VINE_LOGD("Topic[%s] is added as attributes", mTopic); + while (pos < mTopic.size()) { + std::string val = mTopic.substr(pos, VINE_MAX_ATTRIBUTE_LEN - 1 - 2); + char key[3]; + key[0] = 'T'; + key[1] = '0' + attr_num++; + key[2] = 0; + + vine_service_add_attribute(service, key, val.c_str()); + pos += val.size(); + } + vine_service_set_port(service, mListenPort); mRank = create_rank(); @@ -1177,8 +1230,9 @@ int DPPubSub::subscribe_service() RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_create"); } + std::string type = get_service_type(mTopic); ret = vine_disc_subscribe(mSdSub, - mTopic.c_str(), NULL, + type.c_str(), NULL, _service_discovered_cb, static_cast(this), mEventQueue); if (ret != VINE_ERROR_NONE) { diff --git a/src/vine-service.cpp b/src/vine-service.cpp index cf7832c..1cc3849 100755 --- a/src/vine-service.cpp +++ b/src/vine-service.cpp @@ -215,19 +215,20 @@ vine_address_family_e _vine_service_get_address_family(vine_service_h service) return s->family; } -static bool __check_len_key(const char *key) +static bool __check_len_key_val(const char *key, const char *value) { RET_VAL_IF(key == NULL, false, "key is NULL"); - int len = strlen(key); - return len > 0 && len <= VINE_MAX_KEY_LEN; + int key_len = strlen(key); + int val_len = strlen(value); + return key_len > 0 && key_len <= VINE_MAX_KEY_LEN && key_len + val_len + 1 <= VINE_MAX_ATTRIBUTE_LEN; } int _vine_service_add_attribute(vine_service_h service, const char *key, const char *value) { RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is NULL"); - RET_VAL_IF(__check_len_key(key) == false, - VINE_ERROR_INVALID_PARAMETER, "invalid length of key"); + RET_VAL_IF(__check_len_key_val(key, value) == false, + VINE_ERROR_INVALID_PARAMETER, "invalid length of key or value"); VINE_LOGD("Key[%s] value[%s]", key, value); diff --git a/tests/vine-test/vine-test.cpp b/tests/vine-test/vine-test.cpp old mode 100644 new mode 100755 index 1319481..4e62d7f --- a/tests/vine-test/vine-test.cpp +++ b/tests/vine-test/vine-test.cpp @@ -619,7 +619,7 @@ static void __join_service() CHECK_SESSION; int port = 0; int addr_family = 0; - char topic[64]; + char topic[1024]; printf(" >> Address type(0-default, 1-IPv4, 2-IPv6): "); if (scanf(" %d", &addr_family) < 1) { @@ -634,7 +634,7 @@ static void __join_service() } printf(" >> Set topic: "); - if (scanf(" %63s", topic) < 1) { + if (scanf(" %1023s", topic) < 1) { _test_print_error("Scan failed"); return; } -- 2.7.4 From 42ee4a293d6cc1ec397bb9f0e4c76fdefb489f00 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Thu, 22 Jul 2021 09:29:42 +0900 Subject: [PATCH 02/16] Remove dead code Change-Id: Ib80b8e0f1fbc5b07fc58ec158c313b1a47fbbfeb Signed-off-by: Cheoleun Moon --- src/vine-dp.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index 250ce19..0d31a63 100755 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -505,9 +505,6 @@ DPServer::~DPServer() int DPServer::set_method(vine_dp_method_e method) { - if (method < VINE_DP_METHOD_DEFAULT || method >= VINE_DP_METHOD_UNKNOWN) - return VINE_ERROR_INVALID_PARAMETER; - switch (method) { case VINE_DP_METHOD_DEFAULT: mMethod = VINE_DATA_PATH_METHOD_LWS; @@ -515,8 +512,9 @@ int DPServer::set_method(vine_dp_method_e method) case VINE_DP_METHOD_BLE_GATT: mMethod = VINE_DATA_PATH_METHOD_BLE_GATT; break; + case VINE_DP_METHOD_UNKNOWN: default: - mMethod = VINE_DATA_PATH_METHOD_LWS; + return VINE_ERROR_INVALID_PARAMETER; } return VINE_ERROR_NONE; } @@ -737,9 +735,6 @@ DPClient::~DPClient() int DPClient::set_method(vine_dp_method_e method) { - if (method < VINE_DP_METHOD_DEFAULT || method >= VINE_DP_METHOD_UNKNOWN) - return VINE_ERROR_INVALID_PARAMETER; - switch (method) { case VINE_DP_METHOD_DEFAULT: mMethod = VINE_DATA_PATH_METHOD_LWS; @@ -747,8 +742,9 @@ int DPClient::set_method(vine_dp_method_e method) case VINE_DP_METHOD_BLE_GATT: mMethod = VINE_DATA_PATH_METHOD_BLE_GATT; break; + case VINE_DP_METHOD_UNKNOWN: default: - mMethod = VINE_DATA_PATH_METHOD_LWS; + return VINE_ERROR_INVALID_PARAMETER; } return VINE_ERROR_NONE; } -- 2.7.4 From 993dcc88b5b1d61e0c18d677b76e7620cb657eb7 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Thu, 22 Jul 2021 17:11:58 +0900 Subject: [PATCH 03/16] Fix a use-after-free Change-Id: I1219de07f4039b3ca3c1e6e43232ed1cfa9823b0 --- plugins/ble-gatt/ble-gatt-plugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index 70d48ed..b9f3667 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -785,11 +785,11 @@ int gatt_close(vine_dp_plugin_h handle) int ret = BT_ERROR_NONE; if (gatt->type == VINE_GATT_ROLE_SERVER && gatt->role.server) { - ret = bt_gatt_server_unregister_service(gatt->role.server->server, gatt->service); VINE_LOGI("Unregister service[%p]", gatt->service); + ret = bt_gatt_server_unregister_service(gatt->role.server->server, gatt->service); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { - ret = bt_gatt_disconnect(gatt->remote_address); VINE_LOGI("Disconnect from %s", gatt->remote_address); + ret = bt_gatt_disconnect(gatt->remote_address); } return __convert_bt_error_to_data_path_error(ret); } -- 2.7.4 From 35dcfc47f651249089a056186158f7d85b906fb9 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Wed, 21 Jul 2021 16:49:51 +0900 Subject: [PATCH 04/16] ble-gatt: Add eventfd to handle pending write data Change-Id: I1c799fe039a7c6545326e29ce921cd4edb10a58e --- plugins/ble-gatt/ble-gatt-plugin.cpp | 31 ++++++++++++++++++++++++-- plugins/libwebsockets/libwebsockets-plugin.cpp | 8 +++---- src/include/vine-data-path-plugin.h | 2 +- src/vine-data-path.cpp | 14 +++++++----- 4 files changed, 42 insertions(+), 13 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index b9f3667..2fea5e3 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include "vine-data-path-plugin.h" #include "vine-log.h" @@ -58,6 +60,8 @@ typedef struct { } gatt_client_s; struct vine_gatt_s { + int eventfd; + bt_gatt_h service; bt_gatt_h characteristic; bt_gatt_h descriptor; @@ -83,6 +87,8 @@ static vine_dp_plugin_callbacks g_callbacks = { .terminated_cb = NULL, }; +static map g_eventfds; + static vine_gatt_s *_create_gatt(void); static vine_data_path_error __convert_bt_error_to_data_path_error(int error) @@ -246,6 +252,16 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, bt_gatt_h gatt_handle, void *user_data) { + RET_IF(user_data == NULL, "user_data is NULL."); + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + + if (notify) { + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_OP, gatt->eventfd, POLLOUT, gatt->user); + + uint64_t v = 1; + if (write(gatt->eventfd, &v, sizeof(v)) == -1) + VINE_LOGE("Write error(%d)", errno); + } VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle); } @@ -447,6 +463,7 @@ static vine_gatt_s *_create_gatt(void) return NULL; } + gatt->eventfd = eventfd(0, 0); gatt->recv_buffer = new VineQueue; return gatt; } @@ -551,9 +568,18 @@ void gatt_register_callbacks(vine_dp_plugin_callbacks callbacks) g_callbacks = callbacks; } -void gatt_process_event(int gatt_fd, int events) +void gatt_process_event(int fd, int events) { - // Do nothing. use g_main_loop. + auto it = g_eventfds.find(fd); + if (it == g_eventfds.end()) { + VINE_LOGE("There is no matched gatt handle."); + close(fd); + return; + } + + // TODO: handle pending write events. + vine_gatt_s *gatt = it->second; + VINE_LOGI("found gatt[%p]", gatt); } int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user) @@ -588,6 +614,7 @@ int gatt_destroy(vine_dp_plugin_h handle) gatt->role.client = NULL; } + close(gatt->eventfd); gatt->service = NULL; gatt->characteristic = NULL; gatt->descriptor = NULL; diff --git a/plugins/libwebsockets/libwebsockets-plugin.cpp b/plugins/libwebsockets/libwebsockets-plugin.cpp index c901e51..f9a5112 100755 --- a/plugins/libwebsockets/libwebsockets-plugin.cpp +++ b/plugins/libwebsockets/libwebsockets-plugin.cpp @@ -221,7 +221,7 @@ static void _notify_websocket_op_request() uint64_t v = 1; int _eventfd = eventfd(0, 0); - g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_OP, _eventfd, LWS_POLLOUT); + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_OP, _eventfd, LWS_POLLOUT, NULL); if (write(_eventfd, &v, sizeof(v)) == -1) VINE_LOGE("Write error(%d)", errno); } @@ -347,7 +347,7 @@ static void _add_websocket_poll_fd(struct lws_pollargs *args) VINE_LOGI("websocket pollfd[%p] fd[%d] is added.", pollfd, args->fd); if (g_callbacks.pollfd_cb) - g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_ADD, pollfd->fd, pollfd->events); + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_ADD, pollfd->fd, pollfd->events, NULL); } static void _delete_websocket_poll_fd(struct lws_pollargs *args) @@ -364,7 +364,7 @@ static void _delete_websocket_poll_fd(struct lws_pollargs *args) } if (g_callbacks.pollfd_cb) - g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_DEL, args->fd, args->events); + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_DEL, args->fd, args->events, NULL); } static void _change_websocket_poll_fd(struct lws_pollargs *args) @@ -378,7 +378,7 @@ static void _change_websocket_poll_fd(struct lws_pollargs *args) pollfd->events = args->events; if (g_callbacks.pollfd_cb) - g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_MOD, pollfd->fd, pollfd->events); + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_MOD, pollfd->fd, pollfd->events, NULL); } static void _invoke_connected_cb(struct lws *wsi, bool connected, void *user_data) diff --git a/src/include/vine-data-path-plugin.h b/src/include/vine-data-path-plugin.h index e74ad5c..55b21a9 100755 --- a/src/include/vine-data-path-plugin.h +++ b/src/include/vine-data-path-plugin.h @@ -73,7 +73,7 @@ typedef struct { } vine_dp_ssl; typedef struct { - void (*pollfd_cb)(vine_data_path_pollfd_op_e op, int fd, int event); + void (*pollfd_cb)(vine_data_path_pollfd_op_e op, int fd, int event, void *user_data); void (*opened_cb)(int result, int port, void *user_data); void (*accepted_cb)(vine_dp_addr_family_e addr_family, char *addr, int port, void *plugin_data, void *user_data); void (*connected_cb)(int result, void *user_data); diff --git a/src/vine-data-path.cpp b/src/vine-data-path.cpp index 0458549..a723849 100755 --- a/src/vine-data-path.cpp +++ b/src/vine-data-path.cpp @@ -155,13 +155,15 @@ void __vine_dp_op_handler(int fd, int events, void *user_data) VINE_LOGE("Read error(%d)", errno); return; } - // TODO: Only LWS plugin supports polling functions. - // But, we need to modify pollfd_cb to pass datapath handle as the user_data - if (__vine_data_path_plugins[VINE_DATA_PATH_METHOD_LWS].fn.process_event) - __vine_data_path_plugins[VINE_DATA_PATH_METHOD_LWS].fn.process_event(fd, events); + + vine_data_path_s *datapath = (vine_data_path_s *)user_data; + vine_data_path_method_e method = datapath ? datapath->method : VINE_DATA_PATH_METHOD_LWS; + + if (__vine_data_path_plugins[method].fn.process_event) + __vine_data_path_plugins[method].fn.process_event(fd, events); } -static void __pollfd_cb(vine_data_path_pollfd_op_e op, int fd, int events) +static void __pollfd_cb(vine_data_path_pollfd_op_e op, int fd, int events, void *user_data) { switch (op) { case VINE_DATA_PATH_POLLFD_ADD: @@ -174,7 +176,7 @@ static void __pollfd_cb(vine_data_path_pollfd_op_e op, int fd, int events) vine_event_loop_mod_io_handler(fd, events, __vine_dp_poll_handler, NULL); break; case VINE_DATA_PATH_POLLFD_OP: - vine_event_loop_add_io_handler(fd, events, __vine_dp_op_handler, NULL); + vine_event_loop_add_io_handler(fd, events, __vine_dp_op_handler, user_data); break; case VINE_DATA_PATH_POLLFD_LOCK_UNLOCK: // Do not anything. -- 2.7.4 From 742d79dc9a2f19d3ebf7d245276e7f2839f89646 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Thu, 22 Jul 2021 11:23:14 +0900 Subject: [PATCH 05/16] ble-gatt: handle pending write data and MTU Change-Id: I92647460355a7f71900a010e8aa377204c301646 --- packaging/capi-network-vine.spec | 2 +- plugins/ble-gatt/ble-gatt-plugin.cpp | 196 +++++++++++++++++++++++++++++++---- src/include/vine-data-path-plugin.h | 3 +- src/vine-data-path-state.cpp | 3 +- tool/tool_run.cpp | 23 ++-- 5 files changed, 192 insertions(+), 35 deletions(-) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index ddff2eb..abef79b 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -3,7 +3,7 @@ %bcond_without use_glib_event_loop Name: capi-network-vine Summary: An service discovery framework -Version: 1.1.5 +Version: 1.1.6 Release: 0 Group: Network & Connectivity/API License: Apache-2.0 diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index 2fea5e3..af7dbc5 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -33,6 +33,7 @@ using namespace std; #define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66" #define BT_ADDRESS_LEN 17 +#define BT_GATT_ATT_DATA_LEN_MAX 512 typedef enum { VINE_GATT_ROLE_UNKNOWN = 0, @@ -47,6 +48,7 @@ typedef struct { size_t len; //size_t accumulating; bool last; // true, single message or last fragment of a message. + vine_gatt_s *gatt; } gatt_data_s; typedef struct { @@ -73,6 +75,8 @@ struct vine_gatt_s { } role; VineQueue *recv_buffer; + VineQueue *write_buffer; + bool ready_to_write; char *remote_address; void *user; // vine_data_path_h }; @@ -90,6 +94,8 @@ static vine_dp_plugin_callbacks g_callbacks = { static map g_eventfds; static vine_gatt_s *_create_gatt(void); +static int __write_to_client(vine_gatt_s *gatt); +static int __write_to_server(vine_gatt_s *gatt); static vine_data_path_error __convert_bt_error_to_data_path_error(int error) { @@ -106,7 +112,7 @@ static vine_data_path_error __convert_bt_error_to_data_path_error(int error) } } -static gatt_data_s *__create_gatt_data(const char *buf, size_t len, bool last) +static gatt_data_s *__create_gatt_data(vine_gatt_s *gatt, const char *buf, size_t len, bool last) { gatt_data_s *gd = (gatt_data_s *)calloc(1, sizeof(gatt_data_s)); RET_VAL_IF(!gd, NULL, "Out of memory."); @@ -122,6 +128,7 @@ static gatt_data_s *__create_gatt_data(const char *buf, size_t len, bool last) gd->buf = data; gd->len = len; gd->last = last; + gd->gatt = gatt; return gd; } @@ -131,6 +138,8 @@ static void __destroy_gatt_data(gatt_data_s *data) if (data->buf) free(data->buf); + data->buf = NULL; + data->gatt = NULL; free(data); } @@ -226,14 +235,14 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, { RET_IF(user_data == NULL, "user_data is NULL"); - VINE_LOGI("Got write value requestment from %s.", remote_address); + VINE_LOGI("Got write value request 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); + gatt_data_s *recv_data = __create_gatt_data(gatt, value, len, true); RET_IF(recv_data == NULL, "recv_data is NULL"); client_gatt->recv_buffer->push(recv_data); @@ -249,20 +258,41 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, g_callbacks.received_cb(len, client_gatt->user); } +static void __notify_write_event(vine_gatt_s *gatt) +{ + g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_OP, gatt->eventfd, POLLOUT, gatt->user); + + uint64_t v = 1; + if (write(gatt->eventfd, &v, sizeof(v)) == -1) + VINE_LOGE("Write error(%d)", errno); +} + void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, bt_gatt_h gatt_handle, void *user_data) { RET_IF(user_data == NULL, "user_data is NULL."); vine_gatt_s *gatt = (vine_gatt_s *)user_data; - if (notify) { - g_callbacks.pollfd_cb(VINE_DATA_PATH_POLLFD_OP, gatt->eventfd, POLLOUT, gatt->user); + auto iter = gatt->role.server->client_list->begin(); + if (iter == gatt->role.server->client_list->end()) { + VINE_LOGE("Cannot find accepted client."); + return; + } - uint64_t v = 1; - if (write(gatt->eventfd, &v, sizeof(v)) == -1) - VINE_LOGE("Write error(%d)", errno); + vine_gatt_s *accepted_client = iter->second; + if (!accepted_client) { + VINE_LOGE("Cannot find accepted client."); + return; } + + gatt->ready_to_write = notify; + accepted_client->ready_to_write = notify; + VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle); + if (notify) { + // TODO: This will be changed if BT API supports a remote address here. + __notify_write_event(accepted_client); + } } void __gatt_server_noti_sent_cb(int result, @@ -275,11 +305,25 @@ void __gatt_server_noti_sent_cb(int result, VINE_LOGI("Send data to %s is %s. server[%p] completed[%d]", remote_address, result == 0 ? "success" : "failed", server, completed); - vine_gatt_s *gatt = (vine_gatt_s *)user_data; + gatt_data_s *data = (gatt_data_s *)user_data; + if (!data->gatt) + return; + + vine_gatt_s *gatt = data->gatt; g_callbacks.written_cb(1, gatt->user); // bytes will be ignored. + __destroy_gatt_data(data); + + gatt->ready_to_write = true; + __notify_write_event(gatt); } // Client Callbacks +static void __gatt_client_mtu_changed_cb(bt_gatt_client_h client, + const bt_gatt_client_att_mtu_info_s *mtu_info, void *user_data) +{ + VINE_LOGI("MTU is changed. %u", mtu_info->mtu); +} + static void __gatt_client_service_changed_cb(bt_gatt_client_h client, bt_gatt_client_service_change_type_e type, const char *uuid, void *user_data) { @@ -301,17 +345,27 @@ void __gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *us VINE_LOGI("gatt[%p] completed to send data. result[%d]", gatt_handle, result); - vine_gatt_s *gatt = (vine_gatt_s *)user_data; + gatt_data_s *data = (gatt_data_s *)user_data; + if (!data->gatt) + return; + + vine_gatt_s *gatt = data->gatt; + g_callbacks.written_cb(1, gatt->user); // bytes will be ignored. + __destroy_gatt_data(data); + + gatt->ready_to_write = true; + __notify_write_event(gatt); } void __gatt_client_characteristic_value_changed_cb(bt_gatt_h characteristic, char *value, int len, void *user_data) { + VINE_LOGD("+"); RET_IF(user_data == NULL, "user_data is NULL"); vine_gatt_s *gatt = (vine_gatt_s *)user_data; - gatt_data_s *recv_data = __create_gatt_data(value, len, true); + gatt_data_s *recv_data =__create_gatt_data(gatt, value, len, true); RET_IF(recv_data == NULL, "recv_data is NULL"); gatt->recv_buffer->push(recv_data); @@ -336,6 +390,14 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g if (ret != BT_ERROR_NONE || !client) return __convert_bt_error_to_data_path_error(ret); + ret = bt_gatt_client_set_att_mtu_changed_cb(client, __gatt_client_mtu_changed_cb, gatt); + if (ret != BT_ERROR_NONE) + goto ERR; + + ret = bt_gatt_client_request_att_mtu_change(client, BT_GATT_ATT_DATA_LEN_MAX); + if (ret != BT_ERROR_NONE) + goto ERR; + ret = bt_gatt_client_set_service_changed_cb(client, __gatt_client_service_changed_cb, gatt); if (ret != BT_ERROR_NONE) goto ERR; @@ -403,8 +465,8 @@ static void __handle_connected_client(vine_gatt_s *gatt, const char *address) 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); + __invoke_accepted_cb(accepted_gatt, accepted_gatt->user); } static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address) @@ -447,6 +509,7 @@ static void __gatt_connection_state_changed_cb(int result, bool connected, bt_gatt_disconnect(remote_address); result = -1; } + gatt->ready_to_write = true; __invoke_connected_cb(result, gatt->user); } } @@ -456,6 +519,13 @@ static vine_gatt_s *_create_gatt(void) vine_gatt_s *gatt = (vine_gatt_s *)calloc(1, sizeof(vine_gatt_s)); RET_VAL_IF(gatt == NULL, NULL, "Out of memory"); + int fd = eventfd(0, 0); + if (fd < 0) { + VINE_LOGE("cannot get fd for handling event. errno: %d", errno); + free(gatt); + return NULL; + } + if (bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb, (void *)gatt) != BT_ERROR_NONE) { VINE_LOGE("Failed to register GATT connection state changed callback"); @@ -463,8 +533,10 @@ static vine_gatt_s *_create_gatt(void) return NULL; } - gatt->eventfd = eventfd(0, 0); + gatt->eventfd = fd; + g_eventfds[gatt->eventfd] = gatt; gatt->recv_buffer = new VineQueue; + gatt->write_buffer = new VineQueue; return gatt; } @@ -474,7 +546,8 @@ static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, vine_dp_plugin_h ha char initial_value[1] = {'0'}; // TODO: will be changed. int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE; int properties = BT_GATT_PROPERTY_BROADCAST | BT_GATT_PROPERTY_READ | - BT_GATT_PROPERTY_WRITE | BT_GATT_PROPERTY_NOTIFY; + BT_GATT_PROPERTY_WRITE + | BT_GATT_PROPERTY_INDICATE; if (bt_gatt_characteristic_create(VINE_GATT_CHAR_UUID, permissions, properties, @@ -522,34 +595,105 @@ static bt_gatt_h _add_gatt_descriptor(bt_gatt_h characteristic) return descriptor; } -static int _gatt_write_to_server(vine_gatt_s *gatt, unsigned char *buf, size_t len) +static gatt_data_s *__get_pending_write_data(vine_gatt_s *gatt) { - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)buf, len); + if (gatt->write_buffer->empty()) { + VINE_LOGI("gatt[%p] write_buffer is empty.", gatt); + return NULL; + } + + gatt_data_s *data = NULL; + + do { + data = gatt->write_buffer->front(); + gatt->write_buffer->pop(); + } while(data == nullptr); // TODO: handle infinite loop. + + return data; +} + +static int __write_to_server(vine_gatt_s *gatt) +{ + RET_VAL_IF(!gatt->ready_to_write, VINE_DATA_PATH_ERROR_NONE, + "Cannot write yet. The request will be operated later."); + + gatt_data_s *data = __get_pending_write_data(gatt); + RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); + + int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); ret = bt_gatt_client_write_value(gatt->characteristic, - __gatt_client_write_complete_cb, (void *)gatt); + __gatt_client_write_complete_cb, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_client_write_value() failed."); + gatt->ready_to_write = false; + VINE_LOGI("Succeed to send data to server"); + return VINE_DATA_PATH_ERROR_NONE; +} + +static int __push_write_data(vine_gatt_s *gatt, char *buf, size_t len) +{ + + gatt_data_s *data = __create_gatt_data(gatt, buf, len, true); + RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "out of memory."); + + gatt->write_buffer->push(data); + VINE_LOGI("gatt[%p] data[%p]", gatt, data); return VINE_DATA_PATH_ERROR_NONE; } -static int _gatt_write_to_client(vine_gatt_s *gatt, unsigned char *buf, size_t len) +static int _gatt_write_to_server(vine_gatt_s *gatt, unsigned char *buf, size_t len) { - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)buf, len); + int ret = __push_write_data(gatt, (char *)buf, len); + if (ret != VINE_DATA_PATH_ERROR_NONE) + return ret; + + ret = __write_to_server(gatt); + if (ret != VINE_DATA_PATH_ERROR_NONE) + return ret; + + return VINE_DATA_PATH_ERROR_NONE; +} + +static int __write_to_client(vine_gatt_s *gatt) +{ + RET_VAL_IF(!gatt->ready_to_write, VINE_DATA_PATH_ERROR_NONE, + "Cannot write yet. The request will be operated later."); + + gatt_data_s *data = __get_pending_write_data(gatt); + RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); + + int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); ret = bt_gatt_server_notify_characteristic_changed_value(gatt->characteristic, - __gatt_server_noti_sent_cb, gatt->remote_address, (void *)gatt); + __gatt_server_noti_sent_cb, gatt->remote_address, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_server_notify_characteristic_changed_value() failed."); - VINE_LOGI("Succeed to send data to %s", gatt->remote_address ? gatt->remote_address : "all"); + gatt->ready_to_write = false; + + VINE_LOGI("Succeed to send data to %s", + gatt->remote_address ? gatt->remote_address : "all"); + + return VINE_DATA_PATH_ERROR_NONE; +} + +static int _gatt_write_to_client(vine_gatt_s *gatt, unsigned char *buf, size_t len) +{ + int ret = __push_write_data(gatt, (char *)buf, len); + if (ret != VINE_DATA_PATH_ERROR_NONE) + return ret; + + ret = __write_to_client(gatt); + if (ret != VINE_DATA_PATH_ERROR_NONE) + return ret; return VINE_DATA_PATH_ERROR_NONE; } @@ -580,6 +724,13 @@ void gatt_process_event(int fd, int events) // TODO: handle pending write events. vine_gatt_s *gatt = it->second; VINE_LOGI("found gatt[%p]", gatt); + + if (gatt->type == VINE_GATT_ROLE_SERVER + || (gatt->type == VINE_GATT_ROLE_CLIENT + && gatt->role.client && gatt->role.client->is_accepted)) + __write_to_client(gatt); + else if (gatt->type == VINE_GATT_ROLE_CLIENT) + __write_to_server(gatt); } int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user) @@ -778,7 +929,8 @@ int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len) { RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); RET_VAL_IF(buf == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "buf is NULL"); - RET_VAL_IF(len <= 0, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "len is less than 0"); + RET_VAL_IF(len <= 0 || len >= BT_GATT_ATT_DATA_LEN_MAX, + VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "invalid length."); vine_gatt_s *gatt = (vine_gatt_s *)handle; int ret; diff --git a/src/include/vine-data-path-plugin.h b/src/include/vine-data-path-plugin.h index 55b21a9..24a6a23 100755 --- a/src/include/vine-data-path-plugin.h +++ b/src/include/vine-data-path-plugin.h @@ -29,7 +29,8 @@ typedef enum { VINE_DATA_PATH_ERROR_INVALID_PARAMETER, VINE_DATA_PATH_ERROR_INVALID_OPERATION, VINE_DATA_PATH_ERROR_OPERATION_FAILED, - VINE_DATA_PATH_ERROR_OUT_OF_MEMORY + VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, + VINE_DATA_PATH_ERROR_NO_DATA, } vine_data_path_error; typedef enum { diff --git a/src/vine-data-path-state.cpp b/src/vine-data-path-state.cpp index c7f1bf7..21907c1 100644 --- a/src/vine-data-path-state.cpp +++ b/src/vine-data-path-state.cpp @@ -721,8 +721,7 @@ int VineEstablishedState::read(unsigned char *buf, size_t buf_len, size_t *read_ int VineEstablishedState::write(unsigned char *buf, size_t len) { - __fn.write(__plugin, buf, len); - return VINE_ERROR_NONE; + return __fn.write(__plugin, buf, len); } void VineEstablishedState::received_cb(size_t bytes) diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index 12df100..e8d800f 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -24,6 +24,7 @@ #define MAX_EVENTS 10 #define MAX_READ_LEN 1024 +#define MAX_WRITE_LEN 300 int interrupt_flag; @@ -373,7 +374,7 @@ static int _send_message_from_file(vine_dp_h dp) unsigned char *buf; long size; size_t count; - int ret; + int ret = VINE_ERROR_NONE; FILE *file = fopen(vine_configs.file, "r"); if (file == NULL) @@ -392,15 +393,19 @@ static int _send_message_from_file(vine_dp_h dp) count = fread(buf, sizeof(unsigned char), size, file); fclose(file); - ret = vine_dp_send(dp, buf, count); - const char *ret_str; - if (ret == VINE_ERROR_NONE) { - printf("Sent total %zd bytes.\n", count); - ret_str = "Succeeded"; - } else { - ret_str = "Failed"; + int idx = 0; + while (count) { + size_t len = count <= MAX_WRITE_LEN ? count : MAX_WRITE_LEN; + ret = vine_dp_send(dp, buf + idx, len); + if (ret == VINE_ERROR_NONE) { + printf("Sent total %zd bytes.\n", len); + } else { + printf("Failed to send a message.\n"); + break; + } + count -= len; + idx += len; } - printf("%s to send a message.\n", ret_str); free(buf); return ret; -- 2.7.4 From 6cafdf29cf5ff3199ab3e2d10a2cd0bd4f8b5db7 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 6 Aug 2021 15:49:29 +0900 Subject: [PATCH 06/16] Check if value is null Change-Id: If46b8f5fe09828089c0b2025d0600ea1fcb619a7 --- src/vine-service.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/vine-service.cpp b/src/vine-service.cpp index 1cc3849..9d3a5e5 100755 --- a/src/vine-service.cpp +++ b/src/vine-service.cpp @@ -219,7 +219,9 @@ static bool __check_len_key_val(const char *key, const char *value) { RET_VAL_IF(key == NULL, false, "key is NULL"); int key_len = strlen(key); - int val_len = strlen(value); + int val_len = 0; + if (value) + val_len = strlen(value); return key_len > 0 && key_len <= VINE_MAX_KEY_LEN && key_len + val_len + 1 <= VINE_MAX_ATTRIBUTE_LEN; } -- 2.7.4 From e209aff79d69b7ff882cf16ac37042fea8389e5a Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Mon, 9 Aug 2021 14:02:27 +0900 Subject: [PATCH 07/16] Fix build failure Change-Id: I27d0199562a30959074e7a66e5a9a405a7f6d234 --- src/vine-dp.cpp | 2 +- tests/vine-test/CMakeLists.txt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index 0d31a63..e66715f 100755 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -1174,7 +1174,7 @@ int DPPubSub::publish_service() // The maximum length of topic is 1024. // The length of value is at most (VINE_MAX_ATTRIBUTE_LEN(252) - key length(2) - 1 = 249) // Therefore, at most five attributes can be added for a topic. - VINE_LOGD("Topic[%s] is added as attributes", mTopic); + VINE_LOGD("Topic[%s] is added as attributes", mTopic.c_str()); while (pos < mTopic.size()) { std::string val = mTopic.substr(pos, VINE_MAX_ATTRIBUTE_LEN - 1 - 2); char key[3]; diff --git a/tests/vine-test/CMakeLists.txt b/tests/vine-test/CMakeLists.txt index 9398103..da8cb8f 100755 --- a/tests/vine-test/CMakeLists.txt +++ b/tests/vine-test/CMakeLists.txt @@ -27,7 +27,11 @@ INCLUDE_DIRECTORIES( FILE(GLOB VINE_TEST_SRCS *.cpp) FILE(GLOB VINE_TEST_UTILS_SRC *utils*.cpp) +FILE(GLOB VINE_TEST_BLE_SRC vine-ble-test.cpp) LIST(REMOVE_ITEM VINE_TEST_SRCS ${VINE_TEST_UTILS_SRC}) +IF(NOT BT_SUPPORT) +LIST(REMOVE_ITEM VINE_TEST_SRCS ${VINE_TEST_BLE_SRC}) +ENDIF() foreach(file ${VINE_TEST_SRCS}) GET_FILENAME_COMPONENT(name ${file} NAME_WE) -- 2.7.4 From 5d4c53f16c3a5423064ae700f37a3c96c96b88f7 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Thu, 29 Jul 2021 18:49:48 +0900 Subject: [PATCH 08/16] Modify the initiation logic for GATT connection - Manage connection state callbacks globally - Add the new characteristic used in initiation phase - Do not call bt_gatt_disconnect() Change-Id: Id5fbacd2f8e19ab46c901795e3c82d30bf597f39 --- plugins/ble-gatt/ble-gatt-plugin.cpp | 456 +++++++++++++++++++++++++++-------- 1 file changed, 356 insertions(+), 100 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index af7dbc5..b3a0d5b 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -29,9 +29,15 @@ using namespace std; // TODO: change UUIDs #define VINE_GATT_SERVICE_UUID "000018f2-0000-1000-8000-00805f9b34fb" -#define VINE_GATT_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb" +#define VINE_GATT_CONNECTION_CHAR_UUID "5fbfd598-ab0f-4c20-9966-60a11a41e974" +#define VINE_GATT_READ_WRITE_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb" #define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66" +// 2-way handshake for VINE GATT connection +#define VINE_GATT_CONNECTION_SYN "VINE_GATT_CONNECTION_SYN" +#define VINE_GATT_CONNECTION_ACK "VINE_GATT_CONNECTION_ACK" +#define VINE_GATT_CONNECTION_FIN "VINE_GATT_CONNECTION_FIN" + #define BT_ADDRESS_LEN 17 #define BT_GATT_ATT_DATA_LEN_MAX 512 @@ -65,8 +71,10 @@ struct vine_gatt_s { int eventfd; bt_gatt_h service; - bt_gatt_h characteristic; - bt_gatt_h descriptor; + bt_gatt_h connection_char; + bt_gatt_h connection_desc; + bt_gatt_h read_write_char; + bt_gatt_h read_write_desc; vine_gatt_role_e type; union { @@ -93,9 +101,25 @@ static vine_dp_plugin_callbacks g_callbacks = { static map g_eventfds; +// Wrapper for bt_gatt_connection_state_changed_cb() +typedef void (*gatt_connection_state_cb)(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data); +typedef struct { + vine_gatt_s *gatt; + gatt_connection_state_cb func; + void *user_data; +} conn_state_cb_data; +static multimap g_conn_state_cbs; + static vine_gatt_s *_create_gatt(void); static int __write_to_client(vine_gatt_s *gatt); static int __write_to_server(vine_gatt_s *gatt); +static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt); +static void __handle_connected_client(vine_gatt_s *gatt, const char *address); +static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address); +static void __send_conn_syn(vine_gatt_s *gatt, const char *remote_address); +static void __send_conn_ack(vine_gatt_s *gatt, const char *remote_address); +static void __send_conn_fin(vine_gatt_s *gatt, const char *remote_address); static vine_data_path_error __convert_bt_error_to_data_path_error(int error) { @@ -218,14 +242,53 @@ static void __invoke_terminated_cb(void *user_data) } // Server Callbacks +static void __gatt_server_read_connection_value_requested_cb( + const char *remote_address, int request_id, + bt_gatt_server_h server, bt_gatt_h gatt_handle, + int offset, void *user_data) +{ + // Do nothing. +} + +static void __gatt_server_write_connection_value_requested_cb(const char *remote_address, + int request_id, bt_gatt_server_h server, + bt_gatt_h gatt_handle, bool response_needed, int offset, + const char *value, int len, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + VINE_LOGI("Got write init value[%s] request from %s.", value, remote_address); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + + if (bt_gatt_server_send_response(request_id, BT_GATT_REQUEST_TYPE_WRITE, + offset, BT_ERROR_NONE, "", 0) != BT_ERROR_NONE) { + VINE_LOGE("Failed to send initiation message"); + return; + } + + if (strncmp(value, VINE_GATT_CONNECTION_SYN, len) == 0) { + VINE_LOGI("Got SYN mesage from %s", remote_address); + __send_conn_ack(gatt, remote_address); + __handle_connected_client(gatt, remote_address); + } else if (strncmp(value, VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN) == 0)) { + VINE_LOGI("Got FIN message from %s", remote_address); + __handle_disconnected_client(gatt, remote_address); + } +} + +void __gatt_server_noti_connection_state_changed_cb(bool notify, bt_gatt_server_h server, + bt_gatt_h gatt_handle, void *user_data) +{ + // Do nothing. + VINE_LOGI("+"); +} + static void __gatt_server_read_value_requested_cb( const char *remote_address, int request_id, bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset, void *user_data) { - // TODO: Send response. - // TODO: Save data - // Is this function needed for VINE? + // Do nothing. } static void __gatt_server_write_value_requested_cb(const char *remote_address, @@ -318,6 +381,148 @@ void __gatt_server_noti_sent_cb(int result, } // Client Callbacks +void __gatt_client_read_write_char_changed_cb(bt_gatt_h characteristic, + char *value, int len, void *user_data) +{ + VINE_LOGD("+"); + RET_IF(user_data == NULL, "user_data is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + gatt_data_s *recv_data =__create_gatt_data(gatt, value, len, true); + RET_IF(recv_data == NULL, "recv_data is NULL"); + + gatt->recv_buffer->push(recv_data); + + VINE_LOGD("recv_data[%p] is pushed to recv_buffer. length[%zd]", recv_data, len); + if (g_callbacks.received_cb) + g_callbacks.received_cb(len, gatt->user); +} + +void __gatt_client_connection_char_changed_cb(bt_gatt_h characteristic, + char *value, int len, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + if (strncmp(value, VINE_GATT_CONNECTION_ACK, strlen(VINE_GATT_CONNECTION_ACK)) == 0) { + VINE_LOGI("Got ACK message."); + if (bt_gatt_client_set_characteristic_value_changed_cb(gatt->read_write_char, + __gatt_client_read_write_char_changed_cb, gatt) != BT_ERROR_NONE) { + VINE_LOGE("Failed to set characteristic_value_changed_cb"); + // TODO: disconnect. + return; + } + gatt->ready_to_write = true; + __invoke_connected_cb(0, gatt->user); + } else if (strncmp(value, VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN) == 0)) { + VINE_LOGI("Got FIN message."); + __invoke_terminated_cb(gatt->user); + } else { + VINE_LOGI("Unknown message. [%s]", value); + } +} + +void __send_conn_syn_completed_cb(int result, bt_gatt_h gatt_handle, void *user_data) +{ + // Do nothing. +} + +static void __send_conn_syn(vine_gatt_s *gatt, const char *remote_address) +{ + // Only the client can send a SYN. + RET_IF(gatt->type != VINE_GATT_ROLE_CLIENT, "gatt isn't a client"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_SYN, strlen(VINE_GATT_CONNECTION_SYN)); + bt_gatt_client_write_value(gatt->connection_char, + __send_conn_syn_completed_cb, (void *)gatt); +} + +static void __send_conn_ack_completed_cb(int result, + const char *remote_address, bt_gatt_server_h server, bt_gatt_h characteristic, + bool completed, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_ack(vine_gatt_s *gatt, const char *remote_address) +{ + VINE_LOGI("+"); + // Only the server can send a ACK. + RET_IF(gatt->type != VINE_GATT_ROLE_SERVER, "gatt isn't a server"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_ACK, strlen(VINE_GATT_CONNECTION_ACK)); + bt_gatt_server_notify_characteristic_changed_value(gatt->connection_char, + __send_conn_ack_completed_cb, gatt->remote_address, (void *)gatt); +} + +void __send_conn_fin_to_server_completed_cb(int result, bt_gatt_h gatt_handle, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_fin_to_client_completed_cb(int result, + const char *remote_address, bt_gatt_server_h server, bt_gatt_h characteristic, + bool completed, void *user_data) +{ + VINE_LOGD("+"); +} + +static void __send_conn_fin(vine_gatt_s *gatt, const char *remote_address) +{ + VINE_LOGI("+"); + RET_IF(gatt->type == VINE_GATT_ROLE_UNKNOWN, "Unknown type"); + RET_IF(remote_address == NULL, "remote_address is NULL"); + + bt_gatt_set_value(gatt->connection_char, + VINE_GATT_CONNECTION_FIN, strlen(VINE_GATT_CONNECTION_FIN)); + + if (gatt->type == VINE_GATT_ROLE_SERVER) { + bt_gatt_server_notify_characteristic_changed_value(gatt->connection_char, + __send_conn_fin_to_client_completed_cb, gatt->remote_address, (void *)gatt); + } else if (gatt->type = VINE_GATT_ROLE_CLIENT) { + bt_gatt_client_write_value(gatt->connection_char, + __send_conn_fin_to_server_completed_cb, (void *)gatt); + } +} + +static void __gatt_client_state_changed_cb(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data) +{ + RET_IF(gatt == NULL, "gatt is NULL"); + VINE_LOGI("gatt[%p] connected[%d] remote address[%s]", gatt, connected, remote_address); + + if (!connected) { + // TODO: unregister here? + __invoke_terminated_cb(gatt->user); + return; + } + + if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) { + __send_conn_fin(gatt, remote_address); + return; + } + + __send_conn_syn(gatt, remote_address); +} + +static void __gatt_accepted_client_state_changed_cb(vine_gatt_s *gatt, + bool connected, const char *remote_address, void *user_data) +{ + RET_IF(gatt == NULL, "gatt is NULL"); + VINE_LOGI("gatt[%p] connected[%d] remote address[%s]", gatt, connected, remote_address); + + if (connected) { // Do nothing. + VINE_LOGI("[%p] is already connected.", user_data); + return; + } + + __handle_disconnected_client(gatt, remote_address); +} + static void __gatt_client_mtu_changed_cb(bt_gatt_client_h client, const bt_gatt_client_att_mtu_info_s *mtu_info, void *user_data) { @@ -358,23 +563,6 @@ void __gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *us __notify_write_event(gatt); } -void __gatt_client_characteristic_value_changed_cb(bt_gatt_h characteristic, - char *value, int len, void *user_data) -{ - VINE_LOGD("+"); - RET_IF(user_data == NULL, "user_data is NULL"); - - vine_gatt_s *gatt = (vine_gatt_s *)user_data; - gatt_data_s *recv_data =__create_gatt_data(gatt, value, len, true); - RET_IF(recv_data == NULL, "recv_data is NULL"); - - gatt->recv_buffer->push(recv_data); - - VINE_LOGD("recv_data[%p] is pushed to recv_buffer. length[%zd]", recv_data, len); - if (g_callbacks.received_cb) - g_callbacks.received_cb(len, gatt->user); -} - static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *gatt) { RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "gatt is NULL"); @@ -383,6 +571,7 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g bt_gatt_client_h client = NULL; bt_gatt_h service = NULL; + bt_gatt_h connection_char = NULL; bt_gatt_h characteristic = NULL; int ret = BT_ERROR_OPERATION_FAILED; @@ -406,12 +595,20 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g if (ret != BT_ERROR_NONE) goto ERR; - ret = bt_gatt_service_get_characteristic(service, VINE_GATT_CHAR_UUID, &characteristic); + ret = bt_gatt_service_get_characteristic(service, + VINE_GATT_CONNECTION_CHAR_UUID, &connection_char); if (ret != BT_ERROR_NONE) goto ERR; - ret = bt_gatt_client_set_characteristic_value_changed_cb(characteristic, - __gatt_client_characteristic_value_changed_cb, gatt); + ret = bt_gatt_client_set_characteristic_value_changed_cb(connection_char, + __gatt_client_connection_char_changed_cb, gatt); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to set characteristic_value_changed_cb"); + goto ERR; + } + + ret = bt_gatt_service_get_characteristic(service, + VINE_GATT_READ_WRITE_CHAR_UUID, &characteristic); if (ret != BT_ERROR_NONE) goto ERR; @@ -420,7 +617,8 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g goto ERR; gatt->service = service; - gatt->characteristic = characteristic; + gatt->connection_char = connection_char; + gatt->read_write_char = characteristic; gatt->remote_address = STRDUP(remote_address); VINE_LOGI("Succeeded to update GATT service info."); @@ -448,13 +646,65 @@ static vine_gatt_s *__create_accepted_gatt(const char *remote_address, vine_gatt 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->connection_char = gatt->connection_char; + accepted_gatt->connection_desc = gatt->connection_desc; + accepted_gatt->read_write_char = gatt->read_write_char; + accepted_gatt->read_write_desc = gatt->read_write_desc; accepted_gatt->user = user; return accepted_gatt; } +static void __gatt_connection_state_changed_cb(int result, bool connected, + const char *remote_address, void *user_data) +{ + VINE_LOGI("result[%d] connected[%d] remote address[%s]", result, connected, remote_address); + + typedef multimap::iterator iterator; + pair iter_pair = g_conn_state_cbs.equal_range(remote_address); + + for (iterator it = iter_pair.first; it != iter_pair.second; ++it) { + conn_state_cb_data *cb_data = it->second; + if (cb_data && cb_data->func) + cb_data->func(cb_data->gatt, connected, remote_address, cb_data->user_data); + } +} + +static int _register_conn_state_changed_cb(vine_gatt_s *gatt, + const char *addr, gatt_connection_state_cb func, void *user_data) +{ + conn_state_cb_data *cb_data = (conn_state_cb_data *)calloc(1, sizeof(conn_state_cb_data)); + RET_VAL_IF(cb_data == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "cb_data is NULL"); + + cb_data->gatt = gatt; + cb_data->func = func; + cb_data->user_data = user_data; + g_conn_state_cbs.insert(pair(addr, cb_data)); + VINE_LOGD("cb_data[%p] is registered.", cb_data); + + return VINE_DATA_PATH_ERROR_NONE; +} + +static int _unregister_conn_state_changed_cb(vine_gatt_s *gatt, const char *addr, void *user_data) +{ + typedef multimap::iterator iterator; + pair iter_pair = g_conn_state_cbs.equal_range(addr); + + for (iterator it = iter_pair.first; it != iter_pair.second; ++it) { + conn_state_cb_data *cb_data = it->second; + if (cb_data && cb_data->gatt == gatt && cb_data->user_data == user_data) { + VINE_LOGD("cb_data[%p] is unregistered.", cb_data); + g_conn_state_cbs.erase(it); + cb_data->gatt = NULL; + cb_data->func = NULL; + cb_data->user_data = NULL; + free(cb_data); + break; + } + } + return VINE_DATA_PATH_ERROR_NONE; +} + static void __handle_connected_client(vine_gatt_s *gatt, const char *address) { RET_IF(gatt == NULL, "Invalid parameter."); @@ -465,6 +715,9 @@ static void __handle_connected_client(vine_gatt_s *gatt, const char *address) RET_IF(accepted_gatt == NULL, "Failed to create accepted gatt."); gatt->role.server->client_list->insert(std::make_pair(string(address), accepted_gatt)); + _register_conn_state_changed_cb(gatt, address, + __gatt_accepted_client_state_changed_cb, (void *)accepted_gatt); + VINE_LOGI("%s is connected.", address); __invoke_accepted_cb(accepted_gatt, accepted_gatt->user); } @@ -476,44 +729,16 @@ static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address) RET_IF(gatt->role.server == NULL || gatt->role.server->client_list == NULL, "Invalid parameter."); + // TODO: Get client gatt from 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); + _unregister_conn_state_changed_cb(gatt, address, (void *)client_gatt); __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) -{ - RET_IF(user_data == NULL, "user_data is NULL"); - - vine_gatt_s *gatt = (vine_gatt_s *)user_data; - - VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s] role[%d]", - gatt, result, connected, remote_address, gatt->type); - - if (!connected) { - 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 && 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); - result = -1; - } - gatt->ready_to_write = true; - __invoke_connected_cb(result, gatt->user); - } -} - static vine_gatt_s *_create_gatt(void) { vine_gatt_s *gatt = (vine_gatt_s *)calloc(1, sizeof(vine_gatt_s)); @@ -526,13 +751,6 @@ static vine_gatt_s *_create_gatt(void) return NULL; } - if (bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb, - (void *)gatt) != BT_ERROR_NONE) { - VINE_LOGE("Failed to register GATT connection state changed callback"); - free(gatt); - return NULL; - } - gatt->eventfd = fd; g_eventfds[gatt->eventfd] = gatt; gatt->recv_buffer = new VineQueue; @@ -540,30 +758,33 @@ static vine_gatt_s *_create_gatt(void) return gatt; } -static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, vine_dp_plugin_h handle) +static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, + const char *uuid, + bt_gatt_server_read_value_requested_cb read_requested_cb, + bt_gatt_server_write_value_requested_cb write_requested_cb, + bt_gatt_server_characteristic_notification_state_changed_cb noti_changed_cb, + vine_dp_plugin_h handle) { bt_gatt_h characteristic = NULL; char initial_value[1] = {'0'}; // TODO: will be changed. int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE; int properties = BT_GATT_PROPERTY_BROADCAST | BT_GATT_PROPERTY_READ | - BT_GATT_PROPERTY_WRITE - | BT_GATT_PROPERTY_INDICATE; + BT_GATT_PROPERTY_WRITE | BT_GATT_PROPERTY_INDICATE; - if (bt_gatt_characteristic_create(VINE_GATT_CHAR_UUID, - permissions, properties, + if (bt_gatt_characteristic_create(uuid, permissions, properties, initial_value, sizeof(initial_value), &characteristic) != BT_ERROR_NONE) return NULL; if (bt_gatt_server_set_read_value_requested_cb(characteristic, - __gatt_server_read_value_requested_cb, handle) != BT_ERROR_NONE) + read_requested_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_server_set_write_value_requested_cb(characteristic, - __gatt_server_write_value_requested_cb, handle) != BT_ERROR_NONE) + write_requested_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_server_set_characteristic_notification_state_change_cb(characteristic, - __gatt_server_noti_state_changed_cb, handle) != BT_ERROR_NONE) + noti_changed_cb, handle) != BT_ERROR_NONE) goto ERR; if (bt_gatt_service_add_characteristic(service, characteristic) != BT_ERROR_NONE) @@ -620,11 +841,11 @@ static int __write_to_server(vine_gatt_s *gatt) gatt_data_s *data = __get_pending_write_data(gatt); RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); + int ret = bt_gatt_set_value(gatt->read_write_char, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); - ret = bt_gatt_client_write_value(gatt->characteristic, + ret = bt_gatt_client_write_value(gatt->read_write_char, __gatt_client_write_complete_cb, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_client_write_value() failed."); @@ -668,11 +889,11 @@ static int __write_to_client(vine_gatt_s *gatt) gatt_data_s *data = __get_pending_write_data(gatt); RET_VAL_IF(data == NULL, VINE_DATA_PATH_ERROR_NO_DATA, "There is no pending data."); - int ret = bt_gatt_set_value(gatt->characteristic, (const char *)data->buf, data->len); + int ret = bt_gatt_set_value(gatt->read_write_char, (const char *)data->buf, data->len); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_set_value() failed."); - ret = bt_gatt_server_notify_characteristic_changed_value(gatt->characteristic, + ret = bt_gatt_server_notify_characteristic_changed_value(gatt->read_write_char, __gatt_server_noti_sent_cb, gatt->remote_address, (void *)data); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), "bt_gatt_server_notify_characteristic_changed_value() failed."); @@ -721,7 +942,7 @@ void gatt_process_event(int fd, int events) return; } - // TODO: handle pending write events. + // Handle pending write events. vine_gatt_s *gatt = it->second; VINE_LOGI("found gatt[%p]", gatt); @@ -738,6 +959,13 @@ int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user) RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); RET_VAL_IF(user == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "user is NULL"); + // TODO: need to find proper point to register callback. + int ret = bt_gatt_set_connection_state_changed_cb(__gatt_connection_state_changed_cb, NULL); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to register GATT connection state changed callback"); + return __convert_bt_error_to_data_path_error(ret); + } + vine_gatt_s *gatt = plugin_data ? (vine_gatt_s *)plugin_data :_create_gatt(); RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OPERATION_FAILED, "Failed to create GATT handle"); @@ -757,8 +985,10 @@ int gatt_destroy(vine_dp_plugin_h handle) _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); + bt_gatt_characteristic_destroy(gatt->connection_char); + bt_gatt_descriptor_destroy(gatt->connection_desc); + bt_gatt_characteristic_destroy(gatt->read_write_char); + bt_gatt_descriptor_destroy(gatt->read_write_desc); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { // bt_gatt_h handles will be freed during bt_gatt_client_destroy(). _destroy_gatt_client(gatt->role.client); @@ -767,8 +997,10 @@ int gatt_destroy(vine_dp_plugin_h handle) close(gatt->eventfd); gatt->service = NULL; - gatt->characteristic = NULL; - gatt->descriptor = NULL; + gatt->connection_char = NULL; + gatt->connection_desc = NULL; + gatt->read_write_char = NULL; + gatt->read_write_desc = NULL; free(gatt->remote_address); gatt->remote_address = NULL; free(gatt); @@ -785,8 +1017,10 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, vine_gatt_s *gatt = (vine_gatt_s *)handle; bt_gatt_server_h server = NULL; bt_gatt_h service = NULL; - bt_gatt_h characteristic = NULL; - bt_gatt_h descriptor = NULL; + bt_gatt_h connection_char = NULL; + bt_gatt_h connection_desc = NULL; + bt_gatt_h read_write_char = NULL; + bt_gatt_h read_write_desc = NULL; int ret = BT_ERROR_OPERATION_FAILED; // This returns OPERATION_FAILED when already initialized. ignore it. @@ -799,30 +1033,44 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, } ret = bt_gatt_service_create(VINE_GATT_SERVICE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &service); - if (ret != BT_ERROR_NONE) { + if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to create service."); goto ERR; } - characteristic = _add_gatt_characteristic(service, handle); - if (!characteristic) { + connection_char = _add_gatt_characteristic(service, VINE_GATT_CONNECTION_CHAR_UUID, + __gatt_server_read_connection_value_requested_cb, + __gatt_server_write_connection_value_requested_cb, + __gatt_server_noti_connection_state_changed_cb, handle); + + connection_desc = _add_gatt_descriptor(connection_char); + if (!connection_desc) { + VINE_LOGE("Failed to add descriptor."); + goto ERR; + } + + read_write_char = _add_gatt_characteristic(service, VINE_GATT_READ_WRITE_CHAR_UUID, + __gatt_server_read_value_requested_cb, + __gatt_server_write_value_requested_cb, + __gatt_server_noti_state_changed_cb, handle); + if (!read_write_char) { VINE_LOGE("Failed to add characteristc."); goto ERR; } - descriptor = _add_gatt_descriptor(characteristic); - if (!descriptor) { + read_write_desc = _add_gatt_descriptor(read_write_char); + if (!read_write_desc) { VINE_LOGE("Failed to add descriptor."); goto ERR; } - ret = bt_gatt_server_register_service(server, service); + ret = bt_gatt_server_register_service(server, service); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to register service."); goto ERR; } - ret = bt_gatt_server_start(); + ret = bt_gatt_server_start(); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to start GATT server."); goto ERR; @@ -834,8 +1082,10 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, goto ERR; gatt->service = service; - gatt->characteristic = characteristic; - gatt->descriptor = descriptor; + gatt->connection_char = connection_char; + gatt->connection_desc = connection_desc; + gatt->read_write_char = read_write_char; + gatt->read_write_desc = read_write_desc; VINE_LOGI("Succeeded to start GATT server."); @@ -848,16 +1098,20 @@ ERR: bt_gatt_server_destroy(server); if (service) bt_gatt_service_destroy(service); - if (characteristic) - bt_gatt_characteristic_destroy(characteristic); - if (descriptor) - bt_gatt_descriptor_destroy(descriptor); + if (connection_char) + bt_gatt_characteristic_destroy(connection_char); + if (connection_desc) + bt_gatt_descriptor_destroy(connection_desc); + if (read_write_char) + bt_gatt_characteristic_destroy(read_write_char); + if (read_write_desc) + bt_gatt_descriptor_destroy(read_write_desc); return ret; } // All parameters except handle and addr are not used in BT GATT. int gatt_connect(vine_dp_plugin_h handle, int addr_family, - const char *addr, int gatt_port, const char *iface_name, vine_dp_ssl ssl) + const char *addr, int port, const char *iface_name, vine_dp_ssl ssl) { RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL"); @@ -865,11 +1119,13 @@ int gatt_connect(vine_dp_plugin_h handle, int addr_family, vine_gatt_s *gatt = (vine_gatt_s *)handle; int ret; + _register_conn_state_changed_cb(gatt, addr, __gatt_client_state_changed_cb, NULL); 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; + _unregister_conn_state_changed_cb(gatt, addr, NULL); return __convert_bt_error_to_data_path_error(ret); } @@ -968,7 +1224,7 @@ int gatt_close(vine_dp_plugin_h handle) ret = bt_gatt_server_unregister_service(gatt->role.server->server, gatt->service); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { VINE_LOGI("Disconnect from %s", gatt->remote_address); - ret = bt_gatt_disconnect(gatt->remote_address); + // TODO: Send disconnect message. } return __convert_bt_error_to_data_path_error(ret); } -- 2.7.4 From 42fc50baeef6bf1cf6b4ed083440f7dc6bf0e47f Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Tue, 10 Aug 2021 14:00:30 +0900 Subject: [PATCH 09/16] Use long type for timeout_ms Change-Id: I019f58896cd02ba27dc317e79535f4f5f068ee5b Signed-off-by: Cheoleun Moon --- src/include/vine-timer.h | 2 +- src/vine-timer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/vine-timer.h b/src/include/vine-timer.h index ec4cac0..676324c 100644 --- a/src/include/vine-timer.h +++ b/src/include/vine-timer.h @@ -28,7 +28,7 @@ public: VineTimer(); ~VineTimer(); - void start(unsigned int timeout_ms, + void start(long timeout_ms, std::function callback, void *user_data); void stop(); void expired(); diff --git a/src/vine-timer.cpp b/src/vine-timer.cpp index 4877fd7..588de4d 100644 --- a/src/vine-timer.cpp +++ b/src/vine-timer.cpp @@ -38,7 +38,7 @@ VineTimer::~VineTimer() stop(); } -void VineTimer::start(unsigned int timeout_ms, +void VineTimer::start(long timeout_ms, std::function callback, void *user_data) { __timer_fd = timerfd_create(CLOCK_MONOTONIC, 0); -- 2.7.4 From e77aa104219957704808f2435a637de2216d34d4 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Tue, 24 Aug 2021 13:29:27 +0900 Subject: [PATCH 10/16] Use gmock instead of gtest Change-Id: I7814d172cc944f32abed117c179be76ef58763af Signed-off-by: Cheoleun Moon --- packaging/capi-network-vine.spec | 4 ++-- tests/unittest/CMakeLists.txt | 44 ++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index abef79b..7a1051a 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -3,7 +3,7 @@ %bcond_without use_glib_event_loop Name: capi-network-vine Summary: An service discovery framework -Version: 1.1.6 +Version: 1.1.7 Release: 0 Group: Network & Connectivity/API License: Apache-2.0 @@ -31,7 +31,7 @@ BuildRequires: pkgconfig(capi-network-bluetooth) BuildRequires: pkgconfig(glib-2.0) %endif -BuildRequires: pkgconfig(gtest) +BuildRequires: pkgconfig(gmock) %if 0%{?gcov:1} BuildRequires: lcov diff --git a/tests/unittest/CMakeLists.txt b/tests/unittest/CMakeLists.txt index 0ed0eb5..06cbd4a 100755 --- a/tests/unittest/CMakeLists.txt +++ b/tests/unittest/CMakeLists.txt @@ -27,25 +27,35 @@ INCLUDE_DIRECTORIES( ${fw_name_deps_INCLUDE_DIRS} ) -IF(ANDROID) - SET(GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest/) - ADD_LIBRARY(gtest STATIC ${GOOGLETEST_ROOT}/src/gtest_main.cc ${GOOGLETEST_ROOT}/src/gtest-all.cc) - TARGET_INCLUDE_DIRECTORIES(gtest PRIVATE ${GOOGLETEST_ROOT}) - TARGET_INCLUDE_DIRECTORIES(gtest PUBLIC ${GOOGLETEST_ROOT}/include) - SET(GTEST gtest) -ELSE(ANDROID) - SET(GTEST gtest) -ENDIF(ANDROID) - FILE(GLOB UNITTEST_SRCS *.cpp mocks/*.cpp ${CMAKE_SOURCE_DIR}/src/*.cpp) ADD_EXECUTABLE(${VINE_UNITTEST} ${UNITTEST_SRCS}) -TARGET_LINK_LIBRARIES(${VINE_UNITTEST} - ${VINE_LOGGER} - ${VINE_DEPS_LIB} - ${fw_name_deps_LIBRARIES} - ${GTEST} - dl -) + +IF(TIZEN_OS) + pkg_check_modules(unittest_deps REQUIRED gmock) + TARGET_LINK_LIBRARIES(${VINE_UNITTEST} + ${VINE_LOGGER} + ${VINE_DEPS_LIB} + ${fw_name_deps_LIBRARIES} + ${unittest_deps_LIBRARIES} + dl + ) +ELSE(TIZEN_OS) + IF(ANDROID) + SET(GOOGLETEST_ROOT ${ANDROID_NDK}/sources/third_party/googletest/) + ADD_LIBRARY(gtest STATIC ${GOOGLETEST_ROOT}/src/gtest_main.cc ${GOOGLETEST_ROOT}/src/gtest-all.cc) + TARGET_INCLUDE_DIRECTORIES(gtest PRIVATE ${GOOGLETEST_ROOT}) + TARGET_INCLUDE_DIRECTORIES(gtest PUBLIC ${GOOGLETEST_ROOT}/include) + ENDIF(ANDROID) + SET(GTEST gtest) + TARGET_LINK_LIBRARIES(${VINE_UNITTEST} + ${VINE_LOGGER} + ${VINE_DEPS_LIB} + ${fw_name_deps_LIBRARIES} + ${GTEST} + dl + ) +ENDIF(TIZEN_OS) + SET_TARGET_PROPERTIES(${VINE_UNITTEST} PROPERTIES COMPILE_FLAGS "-fPIE" -- 2.7.4 From b543f236889512e4b49dc5aaba598508f6ad4923 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 23 Jul 2021 12:11:37 +0900 Subject: [PATCH 11/16] nan plugin: add publish and subscribe Change-Id: I891c5e17cd87909b6fabbffec45509610a20f69f Signed-off-by: Cheoleun Moon --- CMakeLists.txt | 12 ++ packaging/capi-network-vine.spec | 2 + plugins/nan/CMakeLists.txt | 51 ++++++ plugins/nan/nan-plugin.cpp | 380 +++++++++++++++++++++++++++++++++++++++ plugins/nan/nan-plugin.h | 20 +++ src/include/vine-constants.h | 3 + 6 files changed, 468 insertions(+) create mode 100755 plugins/nan/CMakeLists.txt create mode 100755 plugins/nan/nan-plugin.cpp create mode 100755 plugins/nan/nan-plugin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a6834a7..c9dfd61 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,8 @@ OPTION(WITH_VINE_TEST "With vine command-line test tools" OFF) OPTION(ENABLE_INSTRUMENTATION_MODE "Enable instrumentation mode" OFF) OPTION(ENABLE_DATAPATH_PLUGIN_DEBUG "Enable debug mode for data path plugin" OFF) +OPTION(NAN_SUPPORT "Support NAN" OFF) + INCLUDE(FindPkgConfig) SET(BUILD_OS "default") @@ -90,6 +92,13 @@ IF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) SET(BT_SUPPORT ON) ENDIF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) +IF(NAN_SUPPORT) + IF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB) + MESSAGE("NAN is supported in Tizen with external glib loop") + SET(NAN_SUPPORT OFF) + ENDIF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB) +ENDIF(NAN_SUPPORT) + IF(ENABLE_INSTRUMENTATION_MODE) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -finstrument-functions -finstrument-functions-exclude-file-list=src/logger") ADD_DEFINITIONS("-DENABLE_INSTRUMENTATION_MODE") @@ -129,6 +138,9 @@ IF(BT_SUPPORT) ADD_SUBDIRECTORY(plugins/ble) ADD_SUBDIRECTORY(plugins/ble-gatt) ENDIF(BT_SUPPORT) +IF(NAN_SUPPORT) + ADD_SUBDIRECTORY(plugins/nan) +ENDIF(NAN_SUPPORT) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(src/logger) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index ddff2eb..0f7b057 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -24,6 +24,7 @@ BuildRequires: pkgconfig(capi-base-common) BuildRequires: pkgconfig(capi-system-info) BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(capi-network-wifi-aware) BuildRequires: pkgconfig(capi-network-bluetooth) %endif @@ -103,6 +104,7 @@ export LDFLAGS+=" -lgcov" %else -DUSE_LIBWEBSOCKETS_STATIC=OFF \ %endif + -DNAN_SUPPORT=ON \ %if %{with lws_static_prebuilt} -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=ON \ %else diff --git a/plugins/nan/CMakeLists.txt b/plugins/nan/CMakeLists.txt new file mode 100755 index 0000000..9367cb5 --- /dev/null +++ b/plugins/nan/CMakeLists.txt @@ -0,0 +1,51 @@ +# Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicanan law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +SET(NAN_PLUGIN "vine-plugin-nan") + +SET(NAN_PLUGIN_VERSION_MAJOR "1") +SET(NAN_PLUGIN_VERSION_MINOR "0") +SET(NAN_PLUGIN_VERSION_PATCH "0") +SET(NAN_PLUGIN_VERSION ${NAN_PLUGIN_VERSION_MAJOR}.${NAN_PLUGIN_VERSION_MINOR}.${NAN_PLUGIN_VERSION_PATCH}) + +PKG_CHECK_MODULES(NAN_DEPS REQUIRED "capi-network-wifi-aware") + +INCLUDE_DIRECTORIES( + ${VINE_PATH}/include + ${VINE_LOGGER_PATH} + ${CMAKE_CURRENT_SOURCE_DIR} + ${${fw_name}_INCLUDE_DIRS} + ${NAN_DEPS_INCLUDE_DIRS} +) + +FILE(GLOB VINE_NAN_PLUGIN_SOURCES *.cpp) + +ADD_DEFINITIONS("-fvisibility=default") +ADD_LIBRARY(${NAN_PLUGIN} SHARED ${VINE_NAN_PLUGIN_SOURCES}) + +SET_TARGET_PROPERTIES( + ${NAN_PLUGIN} + PROPERTIES + SOVERSION ${NAN_PLUGIN_VERSION_MAJOR} +) + +TARGET_LINK_LIBRARIES(${NAN_PLUGIN} + ${VINE_LOGGER} + ${NAN_DEPS_LIBRARIES} + ${fw_name_deps_LIBRARIES} + dl +) + +INSTALL(TARGETS ${NAN_PLUGIN} DESTINATION "${LIB_DIR}") diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp new file mode 100755 index 0000000..0739860 --- /dev/null +++ b/plugins/nan/nan-plugin.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include + +#include +#include +#include +#include +#include + +#include "vine-constants.h" +#include "vine-disc-plugin.h" +#include "vine-log.h" +#include "vine-utils.h" +#include "nan-plugin.h" + +typedef struct { + void *disc_handle; // vine_disc handle + wifi_aware_publish_h publish_config; + wifi_aware_subscribe_h subscribe_config; + wifi_aware_session_h session; + //char service_type[NAN_SERVICE_TYPE_LEN + 1]; + char service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1]; +} vine_nan_s; + +static bool __is_nan_enabled = false; +static vine_disc_plugin_callbacks event_callbacks; + +static vine_disc_error __convert_nan_error_to_vine_disc_error(int error) +{ + return VINE_DISC_ERROR_NONE; +} + + +vine_disc_error nan_resolve_ip(void *plugin_handle, + const char *service_type, const char *service_name, + const char *host_name, const char *iface_name, int family) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); + RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL"); + // Ignore host_name and iface_name + + RET_VAL_IF(family == VINE_DISC_ADDR_FAMILY_IPV4, VINE_DISC_ERROR_NOT_SUPPORTED, + "Only IPv6 is allowed for NAN"); + + VINE_LOGD("Start to resolve IP. plugin_handle[%p]\n", plugin_handle); + VINE_LOGD("type[%s] name[%s]", service_type, service_name); + + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + return VINE_DISC_ERROR_NONE; +} + +vine_disc_error nan_cancel_resolve_ip(void *plugin_handle) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + VINE_LOGD("Cancel resolving IP. plugin_handle[%p]\n", plugin_handle); + + return VINE_DISC_ERROR_NONE; +} + + +vine_disc_error nan_init(void **plugin_handle, void *disc_handle) +{ + vine_nan_s *handle = new vine_nan_s; + + handle->disc_handle = disc_handle; + handle->publish_config = nullptr; + handle->subscribe_config = nullptr; + handle->session = nullptr; + + // NAN will be enabled when publish() or subscribe() + // because enable function works asynchronously. + + return VINE_DISC_ERROR_NONE; +} + +void nan_deinit(void *plugin_handle) +{ + RET_IF(plugin_handle == NULL, "Plugin handle is null"); + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + + // TODO + // Disable NAN here. + // However, we have to check if NAN is used for data path + + delete nan_handle; +} + +static void __published_cb(wifi_aware_session_h session, + wifi_aware_error_e error, void *user_data) +{ + VINE_LOGD("Service is published"); + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + + if (event_callbacks.published_cb) + event_callbacks.published_cb(nan_handle, + nan_handle->service_name, __convert_nan_error_to_vine_disc_error(error), + nan_handle->disc_handle); +} + +static void __publish(vine_nan_s *nan_handle) +{ + wifi_aware_session_h session; + int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_PUBLISH, &session); + RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails"); + + ret = wifi_aware_session_publish(session, nan_handle->publish_config, + __published_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_session_publish() fails"); + wifi_aware_session_destroy(session); + } + + nan_handle->session = session; +} + +static void __subscribed_cb(wifi_aware_session_h session, + wifi_aware_error_e error, void *user_data) +{ + RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error"); + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + + VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error)); + if (event_callbacks.discovered_cb) { + std::map empty_map; + event_callbacks.discovered_cb(nan_handle, false, + nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle); + } +} + +static void __subscribe(vine_nan_s *nan_handle) +{ + wifi_aware_session_h session; + int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_SUBSCRIBE, &session); + RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails"); + + ret = wifi_aware_session_subscribe(session, nan_handle->subscribe_config, + __subscribed_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_session_publish() fails"); + wifi_aware_session_destroy(session); + } + + nan_handle->session = session; +} + +static void __start_session(vine_nan_s *nan_handle) +{ + if (nan_handle->publish_config) + __publish(nan_handle); + else if (nan_handle->subscribe_config) + __subscribe(nan_handle); + else + VINE_LOGE("Invalid operation"); +} + +static void __stop_session(vine_nan_s *nan_handle) +{ + if (nan_handle->session) { + wifi_aware_session_stop(nan_handle->session); + wifi_aware_session_destroy(nan_handle->session); + } +} + +static void __enabled_cb(wifi_aware_error_e error, void *user_data) +{ + RET_IF(!user_data, "nan_handle is NULL"); + __start_session((vine_nan_s *)user_data); +} + +static bool __check_attr_len(const map &attributes) +{ + int info_len = VINE_MAX_NAN_SERVICE_NAME_LEN; + for (const auto &kv : attributes) { + auto key = kv.first; + auto val = kv.second; + info_len += key.size() + val.size() + 1; + if (info_len > MAX_SPECIFIC_INFO_LEN) + return false; + } + return true; +} + +static void __fill_specific_info(unsigned char *info, const char *service_name, + const map &attributes) +{ + int service_name_len = strlen(service_name); + memcpy(info, service_name, service_name_len); + info[service_name_len] = 0; + + unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN]; + for (const auto &kv : attributes) { + auto key = kv.first; + auto val = kv.second; + int key_len = key.size(); + int val_len = val.size(); + *ptr = (unsigned char)(key_len + val_len + 1); + ptr++; + memcpy(ptr, key.c_str(), key_len); + ptr += key_len; + *ptr++ = '='; + memcpy(ptr, val.c_str(), val_len); + ptr += val_len; + } +} + +vine_disc_error nan_publish(void *plugin_handle, const char *service_type, + const char *service_name, int port, const map &attributes, + const char *iface_name) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); + RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL"); + RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER, + "Too long service type"); + RET_VAL_IF(strlen(service_name) > VINE_MAX_NAN_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER, + "Too long service name"); + RET_VAL_IF(__check_attr_len(attributes) == false, VINE_DISC_ERROR_INVALID_PARAMETER, + "Too long attributes"); + for (const auto &kv : attributes) { + auto key = kv.first.c_str(); + auto val = kv.second.c_str(); + } + + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle); + + strncpy(nan_handle->service_name, service_name, VINE_MAX_NAN_SERVICE_NAME_LEN); + + wifi_aware_publish_h config = nullptr; + int ret = wifi_aware_publish_create(&config); + RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret), + "wifi_aware_publish_create() fails"); + + unsigned char info[MAX_SPECIFIC_INFO_LEN + 1] = {0, }; + + ret = wifi_aware_publish_set_type(config, WIFI_AWARE_PUBLISH_TYPE_UNSOLICITED); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_publish_set_type() fails"); + goto ERR; + } + + ret = wifi_aware_publish_set_service_name(config, service_type); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_publish_set_service_name() fails"); + goto ERR; + } + + __fill_specific_info(info, service_name, attributes); + + nan_handle->publish_config = config; + + ret = wifi_aware_enable(__enabled_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_enable() fails"); + goto ERR; + } + + return VINE_DISC_ERROR_NONE; + +ERR: + wifi_aware_publish_destroy(config); + return __convert_nan_error_to_vine_disc_error(ret); +} + +vine_disc_error nan_stop_publish(void *plugin_handle) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + __stop_session(nan_handle); + + if (nan_handle->publish_config) + wifi_aware_publish_destroy(nan_handle->publish_config); + + return VINE_DISC_ERROR_NONE; +} + +vine_disc_error nan_subscribe(void *plugin_handle, + const char *service_type, const char *iface_name) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); + RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER, + "Too long service type"); + + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle); + + wifi_aware_subscribe_h config = nullptr; + int ret = wifi_aware_subscribe_create(&config); + RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret), + "wifi_aware_subscribe_create() fails"); + + ret = wifi_aware_subscribe_set_type(config, WIFI_AWARE_SUBSCRIBE_TYPE_ACTIVE); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_subscribe_set_type() fails"); + goto ERR; + } + + ret = wifi_aware_subscribe_set_service_name(config, service_type); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_subscribe_set_service_name() fails"); + goto ERR; + } + + nan_handle->subscribe_config = config; + + ret = wifi_aware_enable(__enabled_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_enable() fails"); + goto ERR; + } + + return VINE_DISC_ERROR_NONE; + +ERR: + wifi_aware_subscribe_destroy(config); + return __convert_nan_error_to_vine_disc_error(ret); +} + +vine_disc_error nan_stop_subscribe(void *plugin_handle) +{ + RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + __stop_session(nan_handle); + + if (nan_handle->subscribe_config) + wifi_aware_subscribe_destroy(nan_handle->subscribe_config); + + return VINE_DISC_ERROR_NONE; +} + + +void nan_register_callbacks(vine_disc_plugin_callbacks callbacks) +{ + event_callbacks.published_cb = callbacks.published_cb; + event_callbacks.discovered_cb = callbacks.discovered_cb; + event_callbacks.ip_resolved_cb = callbacks.ip_resolved_cb; + event_callbacks.fd_added_cb = nullptr; + event_callbacks.fd_removed_cb = nullptr; + event_callbacks.ble_discovered_cb = nullptr; +} + +vine_disc_error nan_process_event(void *plugin_handle, int fd) +{ + VINE_LOGE("Not supported function"); + return VINE_DISC_ERROR_NOT_SUPPORTED; +} + +void vine_disc_plugin_init(vine_disc_plugin_fn *fn) +{ + fn->init = nan_init; + fn->deinit = nan_deinit; + fn->publish = nan_publish; + fn->stop_publish = nan_stop_publish; + fn->subscribe = nan_subscribe; + fn->stop_subscribe = nan_stop_subscribe; + fn->resolve_ip = nan_resolve_ip; + fn->cancel_resolve_ip = nan_cancel_resolve_ip; + fn->register_callbacks = nan_register_callbacks; + fn->process_event = nan_process_event; +} diff --git a/plugins/nan/nan-plugin.h b/plugins/nan/nan-plugin.h new file mode 100755 index 0000000..890b51e --- /dev/null +++ b/plugins/nan/nan-plugin.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ +#pragma once + +#define NAN_MAX_SERVICE_NAME_LEN 255 +#define MAX_SPECIFIC_INFO_LEN 1024 diff --git a/src/include/vine-constants.h b/src/include/vine-constants.h index 206f28d..6ca58e1 100755 --- a/src/include/vine-constants.h +++ b/src/include/vine-constants.h @@ -36,4 +36,7 @@ #define VINE_MAX_BLE_SERVICE_NAME_LEN 15 #define VINE_MAC_LEN 17 +#define VINE_MAX_NAN_SERVICE_TYPE_LEN 63 +#define VINE_MAX_NAN_SERVICE_NAME_LEN 63 + #endif /* __VINE_SERV__VINE_CONSTANTS_H__ICE_H__ */ -- 2.7.4 From 176f50b6bace73ba225011e4ce3f23bb0aedb989 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 23 Jul 2021 13:08:35 +0900 Subject: [PATCH 12/16] Support NAN discovery Change-Id: Id4d0fed38d50ec94206d59a47322af7d1c8e09e5 --- CMakeLists.txt | 2 + include/vine.h | 1 + plugins/nan/nan-plugin.cpp | 80 +++++++++++++++++++++++++++++++++----- src/include/vine-disc-plugin.h | 1 + src/vine-disc.cpp | 6 ++- src/vine-session.cpp | 3 ++ tests/vine-test/vine-test-glib.cpp | 35 +++++++++++++++++ 7 files changed, 117 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9dfd61..60f50de 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,6 +96,8 @@ IF(NAN_SUPPORT) IF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB) MESSAGE("NAN is supported in Tizen with external glib loop") SET(NAN_SUPPORT OFF) + ELSE(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB) + ADD_DEFINITIONS("-DNAN_SUPPORT") ENDIF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB) ENDIF(NAN_SUPPORT) diff --git a/include/vine.h b/include/vine.h index 0544f77..e68d347 100755 --- a/include/vine.h +++ b/include/vine.h @@ -268,6 +268,7 @@ typedef void *vine_security_h; typedef enum { VINE_DISCOVERY_METHOD_DNS_SD = 0, VINE_DISCOVERY_METHOD_BLE, + VINE_DISCOVERY_METHOD_NAN, } vine_discovery_method_e; /** diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp index 0739860..9f2f9a6 100755 --- a/plugins/nan/nan-plugin.cpp +++ b/plugins/nan/nan-plugin.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -34,8 +35,10 @@ typedef struct { wifi_aware_publish_h publish_config; wifi_aware_subscribe_h subscribe_config; wifi_aware_session_h session; - //char service_type[NAN_SERVICE_TYPE_LEN + 1]; + std::map peer_map; // + char service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1]; + int port; } vine_nan_s; static bool __is_nan_enabled = false; @@ -63,6 +66,7 @@ vine_disc_error nan_resolve_ip(void *plugin_handle, VINE_LOGD("type[%s] name[%s]", service_type, service_name); vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + return VINE_DISC_ERROR_NONE; } @@ -84,6 +88,8 @@ vine_disc_error nan_init(void **plugin_handle, void *disc_handle) handle->subscribe_config = nullptr; handle->session = nullptr; + handle->port = -1; + // NAN will be enabled when publish() or subscribe() // because enable function works asynchronously. @@ -97,11 +103,49 @@ void nan_deinit(void *plugin_handle) // TODO // Disable NAN here. - // However, we have to check if NAN is used for data path + // However, we have to check if NAN is used for data path or not + // , and if NAN data path is broken or not when NAN is disabled. delete nan_handle; } +static bool __is_interest_message(const unsigned char *message, size_t len) +{ + // TODO: We have to determine message format. + return true; +} + +static void __open_nan_data_path(wifi_aware_session_h session, + wifi_aware_peer_h peer, vine_nan_s *nan_handle) +{ + VINE_LOGD("Open NAN data path. session[%p]", session); + + wifi_aware_data_path_h ndp; + int ret = wifi_aware_data_path_create(session, peer, &ndp); + + // TODO + // Need to keep ndp +} + +static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer, + const unsigned char *message, size_t len, void *user_data) +{ + RET_IF(!user_data, "user_data is NULL"); + VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]", + session, peer, user_data); + + if (!__is_interest_message(message, len)) { + VINE_LOGD("This message will be not used"); + return; + } + + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + __open_nan_data_path(session, peer, nan_handle); + + // TODO + // Need to keep peer +} + static void __published_cb(wifi_aware_session_h session, wifi_aware_error_e error, void *user_data) { @@ -120,14 +164,25 @@ static void __publish(vine_nan_s *nan_handle) int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_PUBLISH, &session); RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails"); + ret = wifi_aware_session_set_message_received_cb(session, __received_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_session_publish() fails"); + goto ERR; + } + + VINE_LOGD("Publish a NAN service"); + ret = wifi_aware_session_publish(session, nan_handle->publish_config, __published_cb, nan_handle); if (ret != WIFI_AWARE_ERROR_NONE) { VINE_LOGE("wifi_aware_session_publish() fails"); - wifi_aware_session_destroy(session); + goto ERR; } nan_handle->session = session; + return; +ERR: + wifi_aware_session_destroy(session); } static void __subscribed_cb(wifi_aware_session_h session, @@ -150,6 +205,8 @@ static void __subscribe(vine_nan_s *nan_handle) int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_SUBSCRIBE, &session); RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails"); + VINE_LOGD("Subscribe a NAN service"); + ret = wifi_aware_session_subscribe(session, nan_handle->subscribe_config, __subscribed_cb, nan_handle); if (ret != WIFI_AWARE_ERROR_NONE) { @@ -173,6 +230,7 @@ static void __start_session(vine_nan_s *nan_handle) static void __stop_session(vine_nan_s *nan_handle) { if (nan_handle->session) { + VINE_LOGD("Stop NAN session"); wifi_aware_session_stop(nan_handle->session); wifi_aware_session_destroy(nan_handle->session); } @@ -181,6 +239,8 @@ static void __stop_session(vine_nan_s *nan_handle) static void __enabled_cb(wifi_aware_error_e error, void *user_data) { RET_IF(!user_data, "nan_handle is NULL"); + + VINE_LOGD("NAN is enabled. nan_handle[%p]", user_data); __start_session((vine_nan_s *)user_data); } @@ -233,13 +293,10 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type, "Too long service name"); RET_VAL_IF(__check_attr_len(attributes) == false, VINE_DISC_ERROR_INVALID_PARAMETER, "Too long attributes"); - for (const auto &kv : attributes) { - auto key = kv.first.c_str(); - auto val = kv.second.c_str(); - } vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; - VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle); + VINE_LOGD("Publish. plugin_handle[%p], service_type[%s], service_name[%s], port[%d]", + plugin_handle, service_type, service_name, port); strncpy(nan_handle->service_name, service_name, VINE_MAX_NAN_SERVICE_NAME_LEN); @@ -263,8 +320,8 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type, } __fill_specific_info(info, service_name, attributes); - nan_handle->publish_config = config; + nan_handle->port = port; // port will be set for NAN data path ret = wifi_aware_enable(__enabled_cb, nan_handle); if (ret != WIFI_AWARE_ERROR_NONE) { @@ -283,6 +340,7 @@ vine_disc_error nan_stop_publish(void *plugin_handle) { RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + VINE_LOGD("Stop publish. plugin_handle[%p]", plugin_handle); vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; __stop_session(nan_handle); @@ -301,7 +359,8 @@ vine_disc_error nan_subscribe(void *plugin_handle, "Too long service type"); vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; - VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle); + VINE_LOGD("Subscribe. plugin_handle[%p], service_type[%s]", + plugin_handle, service_type); wifi_aware_subscribe_h config = nullptr; int ret = wifi_aware_subscribe_create(&config); @@ -339,6 +398,7 @@ vine_disc_error nan_stop_subscribe(void *plugin_handle) { RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); + VINE_LOGD("Stop subscribe. plugin_handle[%p]", plugin_handle); vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; __stop_session(nan_handle); diff --git a/src/include/vine-disc-plugin.h b/src/include/vine-disc-plugin.h index fd8330e..cf36d20 100755 --- a/src/include/vine-disc-plugin.h +++ b/src/include/vine-disc-plugin.h @@ -23,6 +23,7 @@ #define DNS_SD_PLUGIN_PATH "libvine-plugin-dns-sd.so" #define BLE_PLUGIN_PATH "libvine-plugin-ble.so" +#define NAN_PLUGIN_PATH "libvine-plugin-nan.so" using namespace std; diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index b6ddf24..77083a2 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -34,6 +34,9 @@ static struct { #ifdef BT_SUPPORT [VINE_DISCOVERY_METHOD_BLE] = {"BLE", BLE_PLUGIN_PATH}, #endif +#ifdef NAN_SUPPORT + [VINE_DISCOVERY_METHOD_NAN] = {"NAN", NAN_PLUGIN_PATH}, +#endif {NULL, NULL}, }; @@ -48,6 +51,8 @@ static struct { {NULL, NULL, NULL, NULL, NULL}, NULL}, {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {NULL, NULL, NULL, NULL, NULL}, NULL}, + {{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL}, NULL}, }; typedef struct { @@ -168,7 +173,6 @@ static void __invoke_ip_resolved_user_cb(void *event, void *user_data) disc_handle->ip_resolved_cb_data); } - static void __free_pub_event(void *data) { VINE_LOGD("Free pub_event[%p]", data); diff --git a/src/vine-session.cpp b/src/vine-session.cpp index 6ca5d53..8652e96 100755 --- a/src/vine-session.cpp +++ b/src/vine-session.cpp @@ -170,6 +170,9 @@ static bool __check_disc_method(vine_discovery_method_e method) #ifdef BT_SUPPORT ret = ret || (method == VINE_DISCOVERY_METHOD_BLE); #endif +#ifdef NAN_SUPPORT + ret = ret || (method == VINE_DISCOVERY_METHOD_NAN); +#endif return ret; } diff --git a/tests/vine-test/vine-test-glib.cpp b/tests/vine-test/vine-test-glib.cpp index bfb0deb..b973466 100755 --- a/tests/vine-test/vine-test-glib.cpp +++ b/tests/vine-test/vine-test-glib.cpp @@ -55,6 +55,8 @@ static vine_dp_h g_client_dp = NULL; static vine_dp_h g_pubsub_dp = NULL; static std::list g_datapath_list; static std::list g_service_list; +static int g_disc_method = 0; +static int g_dp_method = 0; static bool test_get_user_string(const char *msg, char *buf, int buf_size) { @@ -83,6 +85,29 @@ static void __quit() exit(1); } +static void __select_method() +{ + if (g_session) { + _test_print_error("Session is already running"); + return; + } + + printf(" >> Select method (0-Default, 1-BLE, 2-NAN): "); + if (scanf(" %d", &g_disc_method) < 1) { + _test_print_error("Scan failed"); + return; + } + + if (g_disc_method < 0 || g_disc_method > 2) { + _test_print_error("Invalid method"); + g_disc_method = 0; + return; + } + + if (g_disc_method == 2) + g_dp_method = 0; +} + static void __init() { PRINT_IF_ERROR(vine_initialize(), "vine_initialize()"); @@ -236,6 +261,11 @@ static void __create_session() return; } + ret = vine_session_set_discovery_method(g_session, (vine_discovery_method_e)g_disc_method); + if (ret != VINE_ERROR_NONE) { + PRINT_IF_ERROR(ret, "vine_session_set_discovery_method"); + return; + } __set_callbacks(); printf("Session Created\n"); } @@ -538,6 +568,7 @@ static void __open_server() } vine_dp_create(g_session, VINE_DP_TYPE_SERVER, &g_server_dp); + vine_dp_set_method(g_server_dp, (vine_dp_method_e)g_dp_method); vine_dp_set_accepted_cb(g_server_dp, __accepted_cb, NULL); vine_dp_set_terminated_cb(g_server_dp, __terminated_cb, NULL); vine_dp_set_address_family(g_server_dp, (vine_address_family_e)addr_family); @@ -581,6 +612,7 @@ static void __connect_server() } vine_dp_create(g_session, VINE_DP_TYPE_CLIENT, &g_client_dp); + vine_dp_set_method(g_client_dp, (vine_dp_method_e)g_dp_method); vine_dp_set_remote_ip(g_client_dp, addr_type ? VINE_ADDRESS_FAMILY_IPV6 : VINE_ADDRESS_FAMILY_IPV4, ip); PRINT_RESULT(vine_dp_set_remote_port(g_client_dp, port), "vine_dp_set_remote_port"); @@ -616,6 +648,7 @@ static void __join_service() } vine_dp_create(g_session, VINE_DP_TYPE_PUBSUB, &g_pubsub_dp); + vine_dp_set_method(g_pubsub_dp, (vine_dp_method_e)g_dp_method); vine_dp_set_address_family(g_pubsub_dp, (vine_address_family_e)addr_family); vine_dp_set_port(g_pubsub_dp, port); vine_dp_set_topic(g_pubsub_dp, topic); @@ -685,6 +718,7 @@ static void __close_data_path() enum { CMD_QUIT = 0, + CMD_SELECT_METHOD, CMD_CREATE_SESSION, CMD_DESTROY_SESSION, CMD_CREATE_SERVICE, @@ -709,6 +743,7 @@ static struct { void (*func)(void); } __menus[] = { [CMD_QUIT] = {"quit", __quit}, + [CMD_SELECT_METHOD] = {"Select method", __select_method}, [CMD_CREATE_SESSION] = {"Create session", __create_session}, [CMD_DESTROY_SESSION] = {"Destroy session", __destroy_session}, [CMD_CREATE_SERVICE] = {"Create service", __create_service}, -- 2.7.4 From c6a0e2b2475337ded684ae1a7c2f15c0ed975cca Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Mon, 26 Jul 2021 21:09:13 +0900 Subject: [PATCH 13/16] Integrate ble_discovered_cb with discovered_cb To identify peer device, host name or MAC address may be used. DNS-SD uses host name while BLE and NAN use MAC address. Change-Id: I4ac6deaea26ed4551c3b7dd1de65a3d5719d0a8f Signed-off-by: Cheoleun Moon --- plugins/ble/ble-plugin.cpp | 13 +++++---- plugins/dns-sd/dns-sd-plugin.cpp | 6 ++-- plugins/nan/nan-plugin.cpp | 5 ++-- src/include/vine-disc-plugin.h | 7 ++--- src/include/vine-disc.h | 4 +-- src/vine-disc.cpp | 48 +++++++------------------------ src/vine-dp.cpp | 4 +-- src/vine-session.cpp | 14 ++++----- tests/unittest/mocks/vine-mock-dns-sd.cpp | 2 +- 9 files changed, 37 insertions(+), 66 deletions(-) mode change 100644 => 100755 tests/unittest/mocks/vine-mock-dns-sd.cpp diff --git a/plugins/ble/ble-plugin.cpp b/plugins/ble/ble-plugin.cpp index 4388042..3896483 100755 --- a/plugins/ble/ble-plugin.cpp +++ b/plugins/ble/ble-plugin.cpp @@ -149,7 +149,7 @@ static vine_disc_error __convert_ble_error_to_vine_disc_error(int error) vine_disc_error ble_resolve_ip(void *plugin_handle, const char *service_type, const char *service_name, - const char *host_name, const char *iface_name, int family) + const char *host_name, const char *mac, const char *iface_name, int family) { VINE_LOGE("Not supported function"); return VINE_DISC_ERROR_NOT_SUPPORTED; @@ -348,10 +348,12 @@ static void __le_scan_result_cb(int result, bt_adapter_le_device_scan_result_inf char mac[VINE_MAC_LEN + 1] = {0, }; strncpy(mac, info->remote_address, VINE_MAC_LEN); - if (event_callbacks.ble_discovered_cb) { + if (event_callbacks.discovered_cb) { std::map empty_map; - event_callbacks.ble_discovered_cb(ble_handle, true, - ble_handle->service_type, service_name, mac, ble_handle->disc_handle); + event_callbacks.discovered_cb(ble_handle, true, + ble_handle->service_type, service_name, + nullptr, mac, -1, empty_map, + nullptr, 0, ble_handle->disc_handle); } } @@ -423,11 +425,10 @@ vine_disc_error ble_process_event(void *plugin_handle, int fd) void ble_register_callbacks(vine_disc_plugin_callbacks callbacks) { event_callbacks.published_cb = callbacks.published_cb; - event_callbacks.discovered_cb = NULL; + event_callbacks.discovered_cb = callbacks.discovered_cb; event_callbacks.ip_resolved_cb = NULL; event_callbacks.fd_added_cb = NULL; event_callbacks.fd_removed_cb = NULL; - event_callbacks.ble_discovered_cb = callbacks.ble_discovered_cb; } void vine_disc_plugin_init(vine_disc_plugin_fn *fn) diff --git a/plugins/dns-sd/dns-sd-plugin.cpp b/plugins/dns-sd/dns-sd-plugin.cpp index f741843..7637bb5 100755 --- a/plugins/dns-sd/dns-sd-plugin.cpp +++ b/plugins/dns-sd/dns-sd-plugin.cpp @@ -325,7 +325,7 @@ static DNSServiceProtocol get_protocol(int family) vine_disc_error dns_sd_resolve_ip(void *plugin_handle, const char *service_type, const char *service_name, - const char *host_name, const char *iface_name, int family) + const char *host_name, const char *mac, const char *iface_name, int family) { RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); @@ -400,7 +400,7 @@ static void __resolve_reply(DNSServiceRef sdRef, unsigned int flags, char iface_name[IF_NAMESIZE + 1] = {0, }; if (if_indextoname(if_index, iface_name)) event_callbacks.discovered_cb(dns_sd_handle, true, - service->service_type, service->service_name, host_name, + service->service_type, service->service_name, host_name, nullptr, service->port, service->attributes, iface_name, flags & kDNSServiceFlagsMoreComing, dns_sd_handle->user_data); else @@ -472,7 +472,7 @@ static void __browse_reply(DNSServiceRef sdRef, unsigned int flags, map empty_map; if (event_callbacks.discovered_cb) event_callbacks.discovered_cb(dns_sd_handle, false, - dns_sd_handle->service_type, service_name, NULL, + dns_sd_handle->service_type, service_name, nullptr, nullptr, 0, empty_map, iface_name, flags & kDNSServiceFlagsMoreComing, dns_sd_handle->user_data); diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp index 9f2f9a6..3bcadb8 100755 --- a/plugins/nan/nan-plugin.cpp +++ b/plugins/nan/nan-plugin.cpp @@ -52,7 +52,7 @@ static vine_disc_error __convert_nan_error_to_vine_disc_error(int error) vine_disc_error nan_resolve_ip(void *plugin_handle, const char *service_type, const char *service_name, - const char *host_name, const char *iface_name, int family) + const char *host_name, const char *mac, const char *iface_name, int family) { RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); @@ -195,7 +195,7 @@ static void __subscribed_cb(wifi_aware_session_h session, if (event_callbacks.discovered_cb) { std::map empty_map; event_callbacks.discovered_cb(nan_handle, false, - nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle); + nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle); } } @@ -416,7 +416,6 @@ void nan_register_callbacks(vine_disc_plugin_callbacks callbacks) event_callbacks.ip_resolved_cb = callbacks.ip_resolved_cb; event_callbacks.fd_added_cb = nullptr; event_callbacks.fd_removed_cb = nullptr; - event_callbacks.ble_discovered_cb = nullptr; } vine_disc_error nan_process_event(void *plugin_handle, int fd) diff --git a/src/include/vine-disc-plugin.h b/src/include/vine-disc-plugin.h index cf36d20..60eac58 100755 --- a/src/include/vine-disc-plugin.h +++ b/src/include/vine-disc-plugin.h @@ -54,16 +54,13 @@ typedef struct { const char *service_name, vine_disc_error error, void *disc_handle); void (*discovered_cb)(void *plugin_handle, bool available, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, + const char *host_name, const char *mac, int port, const map &attr, const char *iface_name, int more_coming, void *disc_handle); void (*ip_resolved_cb)(void *plugin_handle, bool add, const char *ip, sa_family_t address_family, void *disc_handle); void (*fd_added_cb)(int fd, void *disc_handle); void (*fd_removed_cb)(int fd, void *disc_handle); - void (*ble_discovered_cb)(void *plugin_handle, bool available, - const char *service_type, const char *service_name, const char *mac, - void *disc_handle); } vine_disc_plugin_callbacks; typedef struct { @@ -79,7 +76,7 @@ typedef struct { vine_disc_error (*stop_subscribe)(void *plugin_handle); vine_disc_error (*resolve_ip)(void *plugin_handle, const char *service_type, const char *service_name, - const char *host_name, const char *iface_name, int family); + const char *host_name, const char *mac, const char *iface_name, int family); vine_disc_error (*cancel_resolve_ip)(void *plugin_handle); vine_disc_error (*process_event)(void *plugin_handle, int fd); diff --git a/src/include/vine-disc.h b/src/include/vine-disc.h index 42faa43..820a9c9 100755 --- a/src/include/vine-disc.h +++ b/src/include/vine-disc.h @@ -31,8 +31,8 @@ typedef void (*vine_disc_published_cb)(vine_disc_h disc, const char *service_name, vine_error_e error, void *user_data); typedef void (*vine_disc_discovered_cb)(vine_disc_h disc, bool available, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, - const char *iface_name, int more_coming, const char *mac, void *user_data); + const char *host_name, const char *mac, int port, const map &attr, + const char *iface_name, int more_coming, void *user_data); typedef void (*vine_disc_ip_resolved_cb)(vine_disc_h disc, vine_service_h service, bool add, const char *ip, vine_address_family_e address_family, void *user_data); diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index 77083a2..084172d 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -146,11 +146,11 @@ static void __invoke_discovered_user_cb(void *event, void *user_data) discovered_event->service_type, discovered_event->service_name, discovered_event->host_name, + discovered_event->mac, discovered_event->port, discovered_event->attributes, discovered_event->iface_name, discovered_event->more_coming, - discovered_event->mac, disc_handle->discovered_cb_data); } @@ -217,15 +217,15 @@ static void __published_cb(void *plugin_handle, static void __discovered_cb(void *plugin_handle, bool available, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, + const char *host_name, const char *mac, int port, const map &attr, const char *iface_name, int more_coming, void *user_data) { RET_IF(service_type == NULL, "service type is NULL"); RET_IF(service_name == NULL, "service_name type is NULL"); VINE_LOGD("Discovered callback from plugin available[%d]", available); - VINE_LOGD("service type[%s] service_name[%s] host_name[%s] port[%d] iface[%s] user_data[%p]", - service_type, service_name, host_name, port, iface_name, user_data); + VINE_LOGD("service type[%s] service_name[%s] host_name[%s] mac[%s] port[%d] iface[%s] user_data[%p]", + service_type, service_name, host_name, mac, port, iface_name, user_data); vine_discovered_event *discovered_event = new vine_discovered_event; @@ -235,6 +235,12 @@ static void __discovered_cb(void *plugin_handle, bool available, strncpy(discovered_event->iface_name, iface_name, IF_NAMESIZE); if (host_name != NULL) strncpy(discovered_event->host_name, host_name, VINE_MAX_HOST_NAME_LEN); + else + memset(discovered_event->host_name, 0, VINE_MAX_HOST_NAME_LEN + 1); + if (mac != NULL) + strncpy(discovered_event->mac, mac, VINE_MAC_LEN); + else + memset(discovered_event->mac, 0, VINE_MAC_LEN + 1); discovered_event->port = port; discovered_event->attributes = attr; @@ -251,37 +257,6 @@ static void __discovered_cb(void *plugin_handle, bool available, __free_discovered_event(discovered_event); } -static void __ble_discovered_cb(void *plugin_handle, bool available, - const char *service_type, const char *service_name, const char *mac, - void *user_data) -{ - RET_IF(service_type == NULL, "service type is NULL"); - RET_IF(service_name == NULL, "service_name type is NULL"); - RET_IF(mac == NULL, "service mac is NULL"); - - VINE_LOGD("Discovered callback from plugin available[%d]", available); - VINE_LOGD("service type[%s] service_name[%s] mac[%s] user_data[%p]", - service_type, service_name, mac, user_data); - - vine_discovered_event *discovered_event = new vine_discovered_event; - - discovered_event->available = available; - strncpy(discovered_event->service_type, service_type, VINE_MAX_SERVICE_TYPE_LEN); - strncpy(discovered_event->service_name, service_name, VINE_MAX_SERVICE_NAME_LEN); - strncpy(discovered_event->mac, mac, VINE_MAC_LEN); - discovered_event->port = -1; - - VINE_LOGD("Create a discovered_event[%p]", discovered_event); - - vine_disc_s *disc_handle = (vine_disc_s *)user_data; - if (disc_handle) { - if (vine_event_loop_add_event(disc_handle->event_queue, discovered_event, - __invoke_discovered_user_cb, __free_discovered_event, user_data) == VINE_ERROR_NONE) - return; - } - __free_discovered_event(discovered_event); -} - static void __ip_resolved_cb(void *plugin_handle, bool add, const char *ip, sa_family_t address_family, void *user_data) { @@ -375,7 +350,6 @@ static void __init_plugins() __vine_disc_plugins[i].callbacks.ip_resolved_cb = __ip_resolved_cb; __vine_disc_plugins[i].callbacks.fd_added_cb = __fd_added_cb; __vine_disc_plugins[i].callbacks.fd_removed_cb = __fd_removed_cb; - __vine_disc_plugins[i].callbacks.ble_discovered_cb = __ble_discovered_cb; __vine_disc_plugins[i].fn.register_callbacks(__vine_disc_plugins[i].callbacks); } } @@ -683,7 +657,7 @@ vine_error_e __vine_disc_plugin_resolve_ip(vine_disc_h disc, vine_service_h serv } error = disc_handle->plugin_fn->resolve_ip(plugin_handle, _vine_service_get_type(service), _vine_service_get_name(service), - _vine_service_get_host_name(service), _vine_service_get_iface_name(service), + _vine_service_get_host_name(service), nullptr, _vine_service_get_iface_name(service), (int)_vine_service_get_address_family(service)); if (error != VINE_DISC_ERROR_NONE) { VINE_LOGE("Fail to resolve ip %d", error); diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index e66715f..94a94d0 100755 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -327,8 +327,8 @@ static std::string __get_full_topic(const map &attr) static void _service_discovered_cb(vine_disc_h disc, bool available, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, - const char *iface_name, int more_coming, const char *mac, void *user_data) + const char *host_name, const char *mac, int port, const map &attr, + const char *iface_name, int more_coming, void *user_data) { VINE_LOGD("%s is discovered. %s", service_name, available ? "available" : "not available"); diff --git a/src/vine-session.cpp b/src/vine-session.cpp index 8652e96..4415aef 100755 --- a/src/vine-session.cpp +++ b/src/vine-session.cpp @@ -262,8 +262,8 @@ int _vine_session_unregister(vine_session_h session) static int __vine_set_discovered_service(vine_service_h service, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, - const char *iface_name, const char *mac) + const char *host_name, const char *mac, int port, const map &attr, + const char *iface_name) { int ret = VINE_ERROR_NONE; ret = _vine_service_set_type(service, service_type); @@ -272,6 +272,8 @@ static int __vine_set_discovered_service(vine_service_h service, RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set service name"); ret = _vine_service_set_host_name(service, host_name); RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set host name"); + ret = _vine_service_set_mac(service, mac); + RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set mac"); if (port >= 0) { ret = _vine_service_set_port(service, port); @@ -284,15 +286,13 @@ static int __vine_set_discovered_service(vine_service_h service, ret = _vine_service_set_iface_name(service, iface_name); RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set iface_name"); - ret = _vine_service_set_mac(service, mac); - RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to set mac"); return VINE_ERROR_NONE; } static void __discovered_cb(vine_disc_h disc, bool available, const char *service_type, const char *service_name, - const char *host_name, int port, const map &attr, - const char *iface_name, int more_coming, const char *mac, void *user_data) + const char *host_name, const char *mac, int port, const map &attr, + const char *iface_name, int more_coming, void *user_data) { VINE_LOGD("Service is discovered. Available[%d]", available); int ret = VINE_ERROR_NONE; @@ -306,7 +306,7 @@ static void __discovered_cb(vine_disc_h disc, bool available, RET_IF(ret != VINE_ERROR_NONE, "Fail to create a service"); ret = __vine_set_discovered_service(discovered_service, - service_type, service_name, host_name, port, attr, iface_name, mac); + service_type, service_name, host_name, mac, port, attr, iface_name); if (ret != VINE_ERROR_NONE) { VINE_LOGE("Fail to set a service. error(%d)", ret); _vine_service_destroy(discovered_service); diff --git a/tests/unittest/mocks/vine-mock-dns-sd.cpp b/tests/unittest/mocks/vine-mock-dns-sd.cpp old mode 100644 new mode 100755 index c574d79..a51c9dd --- a/tests/unittest/mocks/vine-mock-dns-sd.cpp +++ b/tests/unittest/mocks/vine-mock-dns-sd.cpp @@ -74,7 +74,7 @@ vine_disc_error __mock_disc_plugin_stop_subscribe(void *plugin_handle) vine_disc_error __mock_disc_plugin_resolve_ip(void *plugin_handle, const char *service_type, const char *service_name, - const char *host_name, const char *iface_name, int family) + const char *host_name, const char *mac, const char *iface_name, int family) { return VINE_DISC_ERROR_NONE; } -- 2.7.4 From 20d9305138dda490dde6fadc7cc31849bef4ef7d Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Wed, 28 Jul 2021 13:55:39 +0900 Subject: [PATCH 14/16] nan-plugin: add resolve_ip Change-Id: Ib0d10a908b4ba73baedf07629004bfc56bf1768e --- include/vine.h | 1 + packaging/capi-network-vine.spec | 2 +- plugins/nan/nan-plugin.cpp | 315 ++++++++++++++++++++++++++++++++------- plugins/nan/nan-plugin.h | 1 + 4 files changed, 261 insertions(+), 58 deletions(-) diff --git a/include/vine.h b/include/vine.h index e68d347..fd77cbc 100755 --- a/include/vine.h +++ b/include/vine.h @@ -463,6 +463,7 @@ int vine_session_unset_registered_cb(vine_session_h session); /** * @brief Called when service is discovered. * @remarks @a service will be freed after this callback. Use @a vine_service_clone(). + * @remarks If there is an internal error, @a service will be NULL. * @since_tizen 6.5 * @param[in] session The session handle * @param[in] discovered_service The discovered service diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index 105abde..1b5adbb 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -3,7 +3,7 @@ %bcond_without use_glib_event_loop Name: capi-network-vine Summary: An service discovery framework -Version: 1.1.7 +Version: 1.1.8 Release: 0 Group: Network & Connectivity/API License: Apache-2.0 diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp index 3bcadb8..ef108e8 100755 --- a/plugins/nan/nan-plugin.cpp +++ b/plugins/nan/nan-plugin.cpp @@ -18,6 +18,8 @@ #include #include +#include + #include #include #include @@ -35,9 +37,11 @@ typedef struct { wifi_aware_publish_h publish_config; wifi_aware_subscribe_h subscribe_config; wifi_aware_session_h session; - std::map peer_map; // + std::map peers; // + std::map ndps; // - char service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1]; + char published_service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1]; + char service_type[VINE_MAX_NAN_SERVICE_TYPE_LEN + 1]; int port; } vine_nan_s; @@ -49,6 +53,132 @@ static vine_disc_error __convert_nan_error_to_vine_disc_error(int error) return VINE_DISC_ERROR_NONE; } +static bool __is_data_path_request_message(const unsigned char *message, size_t len) +{ + RET_VAL_IF(len != strlen(VINE_FOLLOWUP_MESSAGE), false, "Wrong message"); + return memcmp(message, VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE)) == 0; +} + +static void __add_ndp(vine_nan_s *nan_handle, + wifi_aware_data_path_h ndp, wifi_aware_peer_h peer) +{ + VINE_LOGD("Add NDP[%p]. peer[%p]", ndp, peer); + auto v = nan_handle->ndps.find(peer); + if (v == nan_handle->ndps.end()) { + // TODO: Can the same peer request NAN data path? + } + nan_handle->ndps[peer] = ndp; +} + +static void __terminated_cb(wifi_aware_data_path_h ndp, + wifi_aware_termination_reason_e reason, void *user_data) +{ + VINE_LOGD("NDP is terminated [%p]. reason[%d]", ndp, (int)reason); + + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + if (event_callbacks.ip_resolved_cb) + event_callbacks.ip_resolved_cb(nan_handle, false, + nullptr, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle); +} + +static void __open_cb(wifi_aware_data_path_h ndp, + wifi_aware_error_e error, void *user_data) +{ + RET_IF(!event_callbacks.ip_resolved_cb, "No callbacks"); + + char *ipv6; + if (wifi_aware_data_path_get_peer_ipv6_address(ndp, &ipv6) != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_data_path_get_peer_ipv6_address() fails"); + return; + } + + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + + event_callbacks.ip_resolved_cb(nan_handle, true, + ipv6, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle); + g_free(ipv6); +} + +static void __open_nan_data_path(wifi_aware_session_h session, + wifi_aware_peer_h peer, vine_nan_s *nan_handle) +{ + VINE_LOGD("Open NAN data path. session[%p]", session); + + /* + std::string mac; + bool found = false; + for (const auto &kv : nan_handle->peers) { + if (kv.second == peer) { + mac = kv.first; + found = true; + break; + } + } + + if (!found) { + VINE_LOGE("Invalid peer"); + return; + } + */ + + wifi_aware_data_path_h ndp; + if (wifi_aware_data_path_create(session, peer, &ndp) != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_data_path_create() fails"); + return; + } + + if (wifi_aware_data_path_set_terminated_cb(ndp, __terminated_cb, nan_handle) + != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_data_path_set_terminated_cb() fails"); + return; + } + + if (wifi_aware_data_path_open(ndp, __open_cb, nan_handle) != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_data_path_open() fails"); + return; + } + + // TODO: Need to maintain ndp list? + __add_ndp(nan_handle, ndp, peer); +} + +static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer, + const unsigned char *message, size_t len, void *user_data) +{ + RET_IF(!user_data, "user_data is NULL"); + VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]", + session, peer, user_data); + + if (!__is_data_path_request_message(message, len)) { + VINE_LOGD("This message will be not used"); + return; + } + + __open_nan_data_path(session, peer, (vine_nan_s *)user_data); +} + +static void __message_result_cb(wifi_aware_session_h session, + wifi_aware_error_e error, void *user_data) +{ + if (error == WIFI_AWARE_ERROR_NONE) { + VINE_LOGD("Message is successfully sent"); + return; + } + + // TODO + // How can inform the failure to app? + // Use ip_resolved_cb with nullptr IP address? + // Then, in terminated_cb, I think ip_resolved_cb is called with ip address (add is false) +} + +static int __send_nan_dp_request(wifi_aware_session_h session, + wifi_aware_peer_h peer, vine_nan_s *nan_handle) +{ + VINE_LOGD("Send NAN Datapath request message"); + return wifi_aware_session_send_message(session, peer, + (unsigned char *)VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE), + __message_result_cb, nan_handle); +} vine_disc_error nan_resolve_ip(void *plugin_handle, const char *service_type, const char *service_name, @@ -57,17 +187,30 @@ vine_disc_error nan_resolve_ip(void *plugin_handle, RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL"); RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL"); RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL"); + RET_VAL_IF(!mac, VINE_DISC_ERROR_INVALID_PARAMETER, "mac is NULL"); // Ignore host_name and iface_name - RET_VAL_IF(family == VINE_DISC_ADDR_FAMILY_IPV4, VINE_DISC_ERROR_NOT_SUPPORTED, "Only IPv6 is allowed for NAN"); + vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + RET_VAL_IF(nan_handle->peers.find(mac) == nan_handle->peers.end(), + VINE_DISC_ERROR_INVALID_PARAMETER, "Invalid mac[%s]", mac); + VINE_LOGD("Start to resolve IP. plugin_handle[%p]\n", plugin_handle); - VINE_LOGD("type[%s] name[%s]", service_type, service_name); + VINE_LOGD("type[%s] name[%s] mac[%s]", service_type, service_name, mac); - vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; + int ret = wifi_aware_session_set_message_received_cb(nan_handle->session, + __received_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_session_set_message_received_cb() fails"); + return __convert_nan_error_to_vine_disc_error(ret); + } - return VINE_DISC_ERROR_NONE; + ret = __send_nan_dp_request(nan_handle->session, nan_handle->peers[mac], nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) + VINE_LOGE("__send_nan_dp_request() fails"); + + return __convert_nan_error_to_vine_disc_error(ret); } vine_disc_error nan_cancel_resolve_ip(void *plugin_handle) @@ -102,50 +245,13 @@ void nan_deinit(void *plugin_handle) vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle; // TODO - // Disable NAN here. + // Disable NAN here? // However, we have to check if NAN is used for data path or not // , and if NAN data path is broken or not when NAN is disabled. delete nan_handle; } -static bool __is_interest_message(const unsigned char *message, size_t len) -{ - // TODO: We have to determine message format. - return true; -} - -static void __open_nan_data_path(wifi_aware_session_h session, - wifi_aware_peer_h peer, vine_nan_s *nan_handle) -{ - VINE_LOGD("Open NAN data path. session[%p]", session); - - wifi_aware_data_path_h ndp; - int ret = wifi_aware_data_path_create(session, peer, &ndp); - - // TODO - // Need to keep ndp -} - -static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer, - const unsigned char *message, size_t len, void *user_data) -{ - RET_IF(!user_data, "user_data is NULL"); - VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]", - session, peer, user_data); - - if (!__is_interest_message(message, len)) { - VINE_LOGD("This message will be not used"); - return; - } - - vine_nan_s *nan_handle = (vine_nan_s *)user_data; - __open_nan_data_path(session, peer, nan_handle); - - // TODO - // Need to keep peer -} - static void __published_cb(wifi_aware_session_h session, wifi_aware_error_e error, void *user_data) { @@ -154,7 +260,7 @@ static void __published_cb(wifi_aware_session_h session, if (event_callbacks.published_cb) event_callbacks.published_cb(nan_handle, - nan_handle->service_name, __convert_nan_error_to_vine_disc_error(error), + nan_handle->published_service_name, __convert_nan_error_to_vine_disc_error(error), nan_handle->disc_handle); } @@ -185,20 +291,104 @@ ERR: wifi_aware_session_destroy(session); } -static void __subscribed_cb(wifi_aware_session_h session, - wifi_aware_error_e error, void *user_data) +static bool __get_attributes(const unsigned char *info, size_t len, map &attr) { - RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error"); + VINE_LOGD("Get Attributes"); + + const unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN]; + const unsigned char *max = info + len; + char key_buf[MAX_SPECIFIC_INFO_LEN + 1]; + char value_buf[MAX_SPECIFIC_INFO_LEN + 1]; + + while (ptr < max) { + const unsigned char *const end = ptr + 1 + ptr[0]; + if (end > max) { + VINE_LOGE("Invalid attribute"); + return false; + } + char *buf = &key_buf[0]; + while (++ptr < end) { + if (*ptr == '=') { + *buf = 0; + buf = &value_buf[0]; + } else { + *buf = *ptr; + ++buf; + } + } + *buf = 0; + VINE_LOGD("Key[%s] Value[%s]", key_buf, value_buf); + string key(key_buf); + string value(value_buf); + attr[key] = value; + } + return true; +} + +static void __add_peer(vine_nan_s *nan_handle, wifi_aware_peer_h peer, const char *mac) +{ + VINE_LOGD("Add peer[%p]. mac[%s]", peer, mac); + nan_handle->peers[mac] = peer; +} + +static void __discovered_cb(wifi_aware_session_h session, + wifi_aware_peer_h peer, const unsigned char *service_specific_info, size_t len, + int distance, void *user_data) +{ + VINE_LOGD("Service Discovered. session[%p] peer[%p]", session, peer); + RET_IF(event_callbacks.discovered_cb == NULL, "discovered_cb is NULL"); + + if (len > MAX_SPECIFIC_INFO_LEN || len < VINE_MAX_NAN_SERVICE_NAME_LEN) { + VINE_LOGE("Invalid info len[%d]", len); + return; + } + + char service_name[VINE_MAX_SERVICE_NAME_LEN + 1]; + memcpy(service_name, service_specific_info, VINE_MAX_NAN_SERVICE_NAME_LEN); + service_name[VINE_MAX_NAN_SERVICE_NAME_LEN] = 0; + + map attributes; + if (__get_attributes(service_specific_info, len, attributes) == false) + return; + + char *mac; + int ret = wifi_aware_peer_get_mac(peer, (unsigned char **)&mac); + RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_peer_get_mac() fails"); + vine_nan_s *nan_handle = (vine_nan_s *)user_data; + __add_peer(nan_handle, peer, mac); + g_free(mac); - VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error)); + event_callbacks.discovered_cb(nan_handle, true, + nan_handle->service_type, service_name, nullptr, + mac, -1, attributes, nullptr, 0, + nan_handle->disc_handle); +} + +/** + * When NAN subscription is failed, it is informed with discovered_cb. + * If service_type and service_name are nullptr, it is considered as an error. + * vine_session_discovered_cb will be called with NULL vine_service_h. + */ +static void __subscribe_failed(vine_nan_s *nan_handle) +{ if (event_callbacks.discovered_cb) { std::map empty_map; event_callbacks.discovered_cb(nan_handle, false, - nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle); + nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, + nan_handle->disc_handle); } } +static void __subscribed_cb(wifi_aware_session_h session, + wifi_aware_error_e error, void *user_data) +{ + RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error"); + + VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error)); + __subscribe_failed((vine_nan_s *)user_data); +} + static void __subscribe(vine_nan_s *nan_handle) { wifi_aware_session_h session; @@ -207,14 +397,25 @@ static void __subscribe(vine_nan_s *nan_handle) VINE_LOGD("Subscribe a NAN service"); - ret = wifi_aware_session_subscribe(session, nan_handle->subscribe_config, - __subscribed_cb, nan_handle); + ret = wifi_aware_session_set_service_discovered_cb(session, __discovered_cb, nan_handle); + if (ret != WIFI_AWARE_ERROR_NONE) { + VINE_LOGE("wifi_aware_session_publish() fails"); + goto ERR; + } + + ret = wifi_aware_session_subscribe(session, + nan_handle->subscribe_config, __subscribed_cb, nan_handle); if (ret != WIFI_AWARE_ERROR_NONE) { VINE_LOGE("wifi_aware_session_publish() fails"); - wifi_aware_session_destroy(session); + goto ERR; } nan_handle->session = session; + return; + +ERR: + wifi_aware_session_destroy(session); + __subscribe_failed(nan_handle); } static void __start_session(vine_nan_s *nan_handle) @@ -298,8 +499,6 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type, VINE_LOGD("Publish. plugin_handle[%p], service_type[%s], service_name[%s], port[%d]", plugin_handle, service_type, service_name, port); - strncpy(nan_handle->service_name, service_name, VINE_MAX_NAN_SERVICE_NAME_LEN); - wifi_aware_publish_h config = nullptr; int ret = wifi_aware_publish_create(&config); RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret), @@ -320,8 +519,6 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type, } __fill_specific_info(info, service_name, attributes); - nan_handle->publish_config = config; - nan_handle->port = port; // port will be set for NAN data path ret = wifi_aware_enable(__enabled_cb, nan_handle); if (ret != WIFI_AWARE_ERROR_NONE) { @@ -329,6 +526,10 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type, goto ERR; } + nan_handle->publish_config = config; + nan_handle->port = port; // port will be set for NAN data path + strncpy(nan_handle->published_service_name, service_name, VINE_MAX_SERVICE_NAME_LEN); + return VINE_DISC_ERROR_NONE; ERR: diff --git a/plugins/nan/nan-plugin.h b/plugins/nan/nan-plugin.h index 890b51e..47ebd51 100755 --- a/plugins/nan/nan-plugin.h +++ b/plugins/nan/nan-plugin.h @@ -18,3 +18,4 @@ #define NAN_MAX_SERVICE_NAME_LEN 255 #define MAX_SPECIFIC_INFO_LEN 1024 +#define VINE_FOLLOWUP_MESSAGE "VINE_REQ_NAN_DATAPATH" -- 2.7.4 From 9c69a3c53226759044f6f420f51c97ff0f524668 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Wed, 28 Jul 2021 16:18:44 +0900 Subject: [PATCH 15/16] nan-plugin: add NAN init/deinit Change-Id: I8c342786e9908a5a25ef80526036afd203ff4cd3 Signed-off-by: Cheoleun Moon --- plugins/nan/nan-plugin.cpp | 16 ++++++++++++++-- tests/vine-test/vine-test-glib.cpp | 12 ++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp index ef108e8..8393d61 100755 --- a/plugins/nan/nan-plugin.cpp +++ b/plugins/nan/nan-plugin.cpp @@ -224,7 +224,14 @@ vine_disc_error nan_cancel_resolve_ip(void *plugin_handle) vine_disc_error nan_init(void **plugin_handle, void *disc_handle) { + int ret = wifi_aware_initialize(); + if (ret != WIFI_AWARE_ERROR_NONE && ret != WIFI_AWARE_ERROR_ALREADY_INITIALIZED) { + VINE_LOGE("wifi_aware_initialize() fails"); + return __convert_nan_error_to_vine_disc_error(ret); + } + vine_nan_s *handle = new vine_nan_s; + VINE_LOGD("Create plugin_handle[%p]", handle); handle->disc_handle = disc_handle; handle->publish_config = nullptr; @@ -233,6 +240,7 @@ vine_disc_error nan_init(void **plugin_handle, void *disc_handle) handle->port = -1; + *plugin_handle = handle; // NAN will be enabled when publish() or subscribe() // because enable function works asynchronously. @@ -250,6 +258,7 @@ void nan_deinit(void *plugin_handle) // , and if NAN data path is broken or not when NAN is disabled. delete nan_handle; + wifi_aware_deinitialize(); } static void __published_cb(wifi_aware_session_h session, @@ -383,9 +392,12 @@ static void __subscribe_failed(vine_nan_s *nan_handle) static void __subscribed_cb(wifi_aware_session_h session, wifi_aware_error_e error, void *user_data) { - RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error"); + if (error == WIFI_AWARE_ERROR_NONE) { + VINE_LOGD("No error"); + return; + } - VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error)); + VINE_LOGE("Fails to subscribe. error: %d", __convert_nan_error_to_vine_disc_error(error)); __subscribe_failed((vine_nan_s *)user_data); } diff --git a/tests/vine-test/vine-test-glib.cpp b/tests/vine-test/vine-test-glib.cpp index b973466..163e204 100755 --- a/tests/vine-test/vine-test-glib.cpp +++ b/tests/vine-test/vine-test-glib.cpp @@ -106,6 +106,18 @@ static void __select_method() if (g_disc_method == 2) g_dp_method = 0; + + switch (g_disc_method) { + case 0: + printf("Default is selected\n"); + break; + case 1: + printf("BLE is selected\n"); + break; + case 2: + printf("NAN is selected\n"); + break; + } } static void __init() -- 2.7.4 From 9d7db32fc7465981d8dbfd814c46ec884472fb24 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Mon, 2 Aug 2021 18:31:46 +0900 Subject: [PATCH 16/16] Add vine_dp_set_service() Change-Id: I899bb36b330c10db9f0a40a174e1c14865cc7a86 --- include/vine.h | 16 ++++++++++++++++ src/include/vine-dp.h | 7 +++++++ src/vine-dp.cpp | 32 ++++++++++++++++++++++++++++++++ src/vine.cpp | 8 ++++++++ tests/unittest/vine-unittest-dp.cpp | 24 ++++++++++++++++++++++++ 5 files changed, 87 insertions(+) diff --git a/include/vine.h b/include/vine.h index fd77cbc..5a4cf69 100755 --- a/include/vine.h +++ b/include/vine.h @@ -1125,6 +1125,22 @@ int vine_dp_set_max_connections(vine_dp_h dp, int max_conn); int vine_dp_set_security(vine_dp_h dp, vine_security_h security); /** + * @brief Sets the service information. + * @remarks This API works only for @a VINE_DP_METHOD_BLE_GATT. + * @since_tizen 6.5 + * @param[in] dp The data path handle + * @param[in] service The service handle + * @return 0 on success, otherwise a negative error value + * @retval #VINE_ERROR_NONE Successful + * @retval #VINE_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #VINE_ERROR_INVALID_OPERATION Invalid operation + * @retval #VINE_ERROR_NOT_SUPPORTED Not supported + * @see vine_dp_create() + * @see vine_service_create() + */ +int vine_dp_set_service(vine_dp_h dp, vine_service_h service); + +/** * @brief Called whenever the peer is accepted. * @remarks @a dp must be released by vine_dp_destroy() if you don't use it anymore. * @since_tizen 6.5 diff --git a/src/include/vine-dp.h b/src/include/vine-dp.h index 06c2aa2..2e86615 100755 --- a/src/include/vine-dp.h +++ b/src/include/vine-dp.h @@ -62,6 +62,7 @@ public: virtual int update_local_address_info() = 0; virtual int set_topic(std::string topic) = 0; virtual int set_max_connections(int max_conn) = 0; + virtual int set_service(vine_service_h service) = 0; virtual int set_accepted_cb(vine_dp_accepted_cb callback, void *user_data) = 0; virtual int unset_accepted_cb() = 0; virtual int set_peer_joined_cb(vine_dp_peer_joined_cb callback, void *user_data) = 0; @@ -125,6 +126,7 @@ public: virtual int update_local_address_info(); virtual int set_topic(std::string topic); virtual int set_max_connections(int max_conn); + virtual int set_service(vine_service_h service); virtual int set_accepted_cb(vine_dp_accepted_cb callback, void *user_data); virtual int unset_accepted_cb(); virtual int set_peer_joined_cb(vine_dp_peer_joined_cb callback, void *user_data); @@ -141,6 +143,7 @@ private: int mListenPort; std::string mLocalIp; int mMaxConnNum; + vine_service_h mService; vine_dp_accepted_cb mAcceptedCb; void *mAcceptedCbData; }; @@ -172,6 +175,7 @@ public: virtual int update_local_address_info(); virtual int set_topic(std::string topic); virtual int set_max_connections(int max_conn){ return VINE_ERROR_NONE; }; + virtual int set_service(vine_service_h service); virtual int set_accepted_cb(vine_dp_accepted_cb callback, void *user_data); virtual int unset_accepted_cb(); virtual int set_peer_joined_cb(vine_dp_peer_joined_cb callback, void *user_data); @@ -187,6 +191,7 @@ private: int mPeerPort; std::string mLocalIp; int mPort; + vine_service_h mService; bool isCreatedByServerDp; }; @@ -231,6 +236,7 @@ public: virtual int set_topic(std::string topic); virtual std::string get_topic() { return mTopic; } virtual int set_max_connections(int max_conn); + virtual int set_service(vine_service_h service); virtual int set_accepted_cb(vine_dp_accepted_cb callback, void *user_data); virtual int unset_accepted_cb(); virtual int set_peer_joined_cb(vine_dp_peer_joined_cb callback, void *user_data); @@ -310,6 +316,7 @@ int _vine_dp_get_port(vine_dp_h dp, int *port); int _vine_dp_set_topic(vine_dp_h dp, const char *topic); int _vine_dp_set_max_connections(vine_dp_h dp, int max_conn); int _vine_dp_set_security(vine_dp_h dp, vine_security_h security); +int _vine_dp_set_service(vine_dp_h dp, vine_service_h service); int _vine_dp_set_accepted_cb(vine_dp_h dp, vine_dp_accepted_cb callback, void *user_data); int _vine_dp_unset_accepted_cb(vine_dp_h dp); int _vine_dp_open(vine_dp_h dp, vine_dp_opened_cb callback, void *user_data); diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index 94a94d0..2d83fcd 100755 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -486,6 +486,7 @@ DPServer::DPServer(void *event_queue) mDataPath = NULL; mListenPort = 0; mMaxConnNum = VINE_DP_DEFAULT_CONNECTIONS_NUM; + mService = NULL; mAcceptedCb = NULL; mAcceptedCbData = NULL; mReceivedCb = NULL; @@ -500,6 +501,7 @@ DPServer::~DPServer() { VINE_LOGD("DPServer[%p] is deleted.", this); _vine_security_destroy(mSecurity); + vine_service_destroy(mService); vine_data_path_destroy(mDataPath); } @@ -606,6 +608,13 @@ int DPServer::set_max_connections(int max_conn) return VINE_ERROR_NONE; } +int DPServer::set_service(vine_service_h service) +{ + if (mMethod != VINE_DATA_PATH_METHOD_BLE_GATT) + return VINE_ERROR_INVALID_OPERATION; + return vine_service_clone(service, &mService); +} + int DPServer::set_accepted_cb(vine_dp_accepted_cb callback, void *user_data) { mAcceptedCb = callback; @@ -695,6 +704,7 @@ DPClient::DPClient(void *event_queue) mPeerIp = ""; mPeerPort = 0; mPort = 0; + mService = NULL; mReceivedCb = NULL; mReceivedCbData = NULL; mOpenedCb = NULL; @@ -730,6 +740,7 @@ DPClient::~DPClient() { VINE_LOGD("DPClient[%p] is deleted.", this); _vine_security_destroy(mSecurity); + vine_service_destroy(mService); vine_data_path_destroy(mDataPath); } @@ -841,6 +852,13 @@ int DPClient::set_topic(std::string topic) return VINE_ERROR_INVALID_OPERATION; } +int DPClient::set_service(vine_service_h service) +{ + if (mMethod != VINE_DATA_PATH_METHOD_BLE_GATT) + return VINE_ERROR_INVALID_OPERATION; + return vine_service_clone(service, &mService); +} + int DPClient::set_accepted_cb(vine_dp_accepted_cb callback, void *user_data) { return VINE_ERROR_INVALID_OPERATION; @@ -1056,6 +1074,11 @@ int DPPubSub::set_max_connections(int max_conn) return VINE_ERROR_NONE; } +int DPPubSub::set_service(vine_service_h service) +{ + return VINE_ERROR_INVALID_OPERATION; +} + int DPPubSub::set_accepted_cb(vine_dp_accepted_cb callback, void *user_data) { return VINE_ERROR_INVALID_OPERATION; @@ -1682,6 +1705,15 @@ int _vine_dp_set_security(vine_dp_h dp, vine_security_h security) return _dp->set_security(security); } +int _vine_dp_set_service(vine_dp_h dp, vine_service_h service) +{ + RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); + RET_VAL_IF(service == NULL, VINE_ERROR_INVALID_PARAMETER, "service is null."); + + DataPath *_dp = static_cast(dp); + return _dp->set_service(service); +} + int _vine_dp_set_accepted_cb(vine_dp_h dp, vine_dp_accepted_cb callback, void *user_data) { RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); diff --git a/src/vine.cpp b/src/vine.cpp index 8290152..22057e8 100755 --- a/src/vine.cpp +++ b/src/vine.cpp @@ -478,6 +478,14 @@ API int vine_dp_set_security(vine_dp_h dp, vine_security_h security) return _vine_dp_set_security(dp, security); } +API int vine_dp_set_service(vine_dp_h dp, vine_service_h service) +{ + __VINE_FUNC_ENTER__; + CHECK_FEATURE_SUPPORTED; + + return _vine_dp_set_service(dp, service); +} + API int vine_dp_set_accepted_cb(vine_dp_h dp, vine_dp_accepted_cb callback, void *user_data) { __VINE_FUNC_ENTER__; diff --git a/tests/unittest/vine-unittest-dp.cpp b/tests/unittest/vine-unittest-dp.cpp index 8dd6838..718da0e 100755 --- a/tests/unittest/vine-unittest-dp.cpp +++ b/tests/unittest/vine-unittest-dp.cpp @@ -467,6 +467,30 @@ TEST_F(VineDpTest, SetSecurityP) vine_security_destroy(security); } +TEST_F(VineDpTest, SetServiceN) +{ + vine_service_h service; + + vine_service_create(&service); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, + vine_dp_set_service(NULL, service)); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, + vine_dp_set_service(client_dp, NULL)); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, + vine_dp_set_service(pubsub_dp, service)); + vine_service_destroy(service); +} + +TEST_F(VineDpTest, SetServiceP) +{ + vine_service_h service; + + vine_service_create(&service); + vine_dp_set_method(server_dp, VINE_DP_METHOD_BLE_GATT); + EXPECT_EQ(VINE_ERROR_NONE, vine_dp_set_service(server_dp, service)); + vine_service_destroy(service); +} + TEST_F(VineDpTest, SetIfaceNameN) { EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, -- 2.7.4