From b76d4a057b713de15f8ec3f881fdf653ace9c7e5 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 2 Jul 2021 11:16:19 +0900 Subject: [PATCH 01/16] Handle unsupported functions Change-Id: I9ae35dd453129acd27dc5d6e0713724256fdad24 Signed-off-by: Cheoleun Moon --- CMakeLists.txt | 10 ++++++++-- packaging/capi-network-vine.spec | 6 +++--- plugins/ble/ble-plugin.cpp | 4 ++++ src/include/vine-event-loop.h | 4 ++-- src/vine-disc.cpp | 2 ++ src/vine-event-loop-epoll.cpp | 3 ++- src/vine-event-loop-glib.cpp | 3 ++- src/vine-event-loop.cpp | 4 ++-- src/vine-session.cpp | 16 ++++++++++++---- tool/tool_config.cpp | 0 tool/tool_run.cpp | 4 ++++ 11 files changed, 41 insertions(+), 15 deletions(-) mode change 100644 => 100755 tool/tool_config.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e0109b..eae5055 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -84,6 +84,12 @@ IF(TIZEN_OS) ADD_DEFINITIONS("-DTIZEN_OS -DUSE_DLOG") ENDIF(TIZEN_OS) +SET(BT_SUPPORT OFF) +IF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) + ADD_DEFINITIONS("-DBT_SUPPORT") + SET(BT_SUPPORT ON) +ENDIF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) + 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") @@ -119,9 +125,9 @@ IF(USE_LIBWEBSOCKETS) ENDIF(USE_LIBWEBSOCKETS) ADD_SUBDIRECTORY(plugins/dns-sd) -IF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) +IF(BT_SUPPORT) ADD_SUBDIRECTORY(plugins/ble) -ENDIF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB) +ENDIF(BT_SUPPORT) ADD_SUBDIRECTORY(include) ADD_SUBDIRECTORY(src/logger) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index 2cfa80e..1aa666a 100755 --- a/packaging/capi-network-vine.spec +++ b/packaging/capi-network-vine.spec @@ -104,12 +104,12 @@ export LDFLAGS+=" -lgcov" -DUSE_LIBWEBSOCKETS_STATIC=OFF \ %endif %if %{with lws_static_prebuilt} - -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=ON \ + -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=ON \ %else - -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=OFF \ + -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=OFF \ %endif -DWITH_UNITTEST=ON \ - -DENABLE_DATAPATH_PLUGIN_DEBUG=ON \ + -DENABLE_DATAPATH_PLUGIN_DEBUG=ON \ -DWITH_VINE_TEST=ON make %{?jobs:-j%jobs} diff --git a/plugins/ble/ble-plugin.cpp b/plugins/ble/ble-plugin.cpp index 01de78c..33f057b 100755 --- a/plugins/ble/ble-plugin.cpp +++ b/plugins/ble/ble-plugin.cpp @@ -270,6 +270,8 @@ vine_disc_error ble_publish(void *plugin_handle, const char *service_type, vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle; RET_VAL_IF(ble_handle->adv != NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "Already published"); + VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle); + int ret = bt_adapter_le_create_advertiser(&ble_handle->adv); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_ble_error_to_vine_disc_error(ret), "bt_adapter_le_create_advertiser() fails"); @@ -377,6 +379,8 @@ vine_disc_error ble_subscribe(void *plugin_handle, vine_ble_s *ble_handle = (vine_ble_s *)plugin_handle; RET_VAL_IF(ble_handle->filter != NULL, VINE_DISC_ERROR_INVALID_PARAMETER, "Already subscribed"); + VINE_LOGD("Subscribe a service. plugin_handle[%p]", plugin_handle); + int ret = bt_adapter_le_scan_filter_create(&ble_handle->filter); RET_VAL_IF(ret != BT_ERROR_NONE, __convert_ble_error_to_vine_disc_error(ret), "bt_adapter_le_scan_filter_create() fails"); diff --git a/src/include/vine-event-loop.h b/src/include/vine-event-loop.h index 48ab5b6..05379c4 100755 --- a/src/include/vine-event-loop.h +++ b/src/include/vine-event-loop.h @@ -47,7 +47,7 @@ void vine_event_loop_stop(); int vine_event_queue_create(vine_event_queue_h *event_queue); void vine_event_queue_destroy(vine_event_queue_h event_queue); -void vine_event_loop_get_eventfd(vine_event_queue_h event_queue, int *eventfd); +int vine_event_loop_get_eventfd(vine_event_queue_h event_queue, int *eventfd); int vine_event_loop_process(vine_event_queue_h event_queue); int vine_event_loop_add_io_handler(int fd, int events, @@ -68,7 +68,7 @@ typedef struct { void (*stop)(); int (*event_queue_create)(vine_event_queue_h *event_queue); void (*event_queue_destroy)(vine_event_queue_h event_queue); - void (*get_eventfd)(vine_event_queue_h event_queue, int *eventfd); + int (*get_eventfd)(vine_event_queue_h event_queue, int *eventfd); int (*process)(vine_event_queue_h event_queue); int (*add_io_handler)(int fd, int events, vine_poll_handler handler, void *user_data); int (*mod_io_handler)(int fd, int events, vine_poll_handler handler, void *user_data); diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index f967c59..01aa202 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -31,7 +31,9 @@ static struct { const char *path; } __vine_disc_plugins_info[] = { [VINE_DISCOVERY_METHOD_DNS_SD] = {"DNS-SD", DNS_SD_PLUGIN_PATH}, +#ifdef BT_SUPPORT [VINE_DISCOVERY_METHOD_BLE] = {"BLE", BLE_PLUGIN_PATH}, +#endif {NULL, NULL}, }; diff --git a/src/vine-event-loop-epoll.cpp b/src/vine-event-loop-epoll.cpp index c3beefd..e8815dd 100755 --- a/src/vine-event-loop-epoll.cpp +++ b/src/vine-event-loop-epoll.cpp @@ -179,10 +179,11 @@ void vine_event_queue_epoll_destroy(vine_event_queue_h event_queue) delete event_queue_handle; } -void vine_event_loop_epoll_get_eventfd(vine_event_queue_h event_queue, int *eventfd) +int vine_event_loop_epoll_get_eventfd(vine_event_queue_h event_queue, int *eventfd) { vine_epoll_event_queue_s *event_queue_handle = (vine_epoll_event_queue_s *)event_queue; *eventfd = event_queue_handle->fd; + return VINE_ERROR_NONE; } static void _add_io_event_handler(int fd, vine_epoll_io_event_handler *h) diff --git a/src/vine-event-loop-glib.cpp b/src/vine-event-loop-glib.cpp index eafea33..390eb51 100755 --- a/src/vine-event-loop-glib.cpp +++ b/src/vine-event-loop-glib.cpp @@ -69,8 +69,9 @@ void vine_event_queue_glib_destroy(vine_event_queue_h event_queue) { } -void vine_event_loop_glib_get_eventfd(vine_event_queue_h event_queue, int *eventfd) +int vine_event_loop_glib_get_eventfd(vine_event_queue_h event_queue, int *eventfd) { + return VINE_ERROR_NOT_SUPPORTED; } static void _add_io_event_handler(int fd, vine_glib_io_event_handler *h) diff --git a/src/vine-event-loop.cpp b/src/vine-event-loop.cpp index 84dae68..950edf0 100755 --- a/src/vine-event-loop.cpp +++ b/src/vine-event-loop.cpp @@ -90,9 +90,9 @@ void vine_event_queue_destroy(vine_event_queue_h event_queue) __event_loop[__event_loop_type].event_queue_destroy(event_queue); } -void vine_event_loop_get_eventfd(vine_event_queue_h event_queue, int *eventfd) +int vine_event_loop_get_eventfd(vine_event_queue_h event_queue, int *eventfd) { - __event_loop[__event_loop_type].get_eventfd(event_queue, eventfd); + return __event_loop[__event_loop_type].get_eventfd(event_queue, eventfd); } int vine_event_loop_add_io_handler( diff --git a/src/vine-session.cpp b/src/vine-session.cpp index 599a349..6ca5d53 100755 --- a/src/vine-session.cpp +++ b/src/vine-session.cpp @@ -166,8 +166,11 @@ int _vine_session_unset_discovered_cb(vine_session_h session) static bool __check_disc_method(vine_discovery_method_e method) { - return method >= VINE_DISCOVERY_METHOD_DNS_SD - && method <= VINE_DISCOVERY_METHOD_BLE; + bool ret = (method == VINE_DISCOVERY_METHOD_DNS_SD); +#ifdef BT_SUPPORT + ret = ret || (method == VINE_DISCOVERY_METHOD_BLE); +#endif + return ret; } int _vine_session_set_discovery_method(vine_session_h session, vine_discovery_method_e method) @@ -399,6 +402,8 @@ int _vine_session_set_ip_resolved_cb(vine_session_h session, int ret = VINE_ERROR_NONE; vine_session_s *s = (vine_session_s *)session; + RET_VAL_IF(s->disc_method == VINE_DISCOVERY_METHOD_BLE, VINE_ERROR_NOT_SUPPORTED, + "BLE discovery doesn't support vine_session_set_ip_resolved_cb()"); vine_disc_h disc_handle; ret = vine_disc_create(s->disc_method, &disc_handle); RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to vine_disc_create"); @@ -425,6 +430,10 @@ int _vine_session_unset_ip_resolved_cb(vine_session_h session, VINE_LOGD("Cancel resolving IP address for a service[%p]. session[%p]", service, session); + vine_session_s *s = (vine_session_s *)session; + RET_VAL_IF(s->disc_method == VINE_DISCOVERY_METHOD_BLE, VINE_ERROR_NOT_SUPPORTED, + "BLE discovery doesn't support vine_session_unset_ip_resolved_cb()"); + int ret = VINE_ERROR_NONE; vine_disc_h disc_handle = NULL; ret = _vine_service_get_disc_handle(service, VINE_DISCOVERY_METHOD_DNS_SD, &disc_handle); @@ -452,8 +461,7 @@ int _vine_session_get_event_fd(vine_session_h session, int *fd) RET_VAL_IF(session == NULL, VINE_ERROR_INVALID_PARAMETER, "session is NULL"); vine_session_s *s = (vine_session_s *)session; - vine_event_loop_get_eventfd(s->event_queue, fd); - return VINE_ERROR_NONE; + return vine_event_loop_get_eventfd(s->event_queue, fd); } int _vine_session_process_event(vine_session_h session) diff --git a/tool/tool_config.cpp b/tool/tool_config.cpp old mode 100644 new mode 100755 diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index db3952a..c76cadd 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -610,6 +610,7 @@ static void _event_handler(vine_session_h session) vine_session_process_event(session); } +#ifdef BT_SUPPORT static void _run_glib_event_loop() { GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); @@ -618,6 +619,7 @@ static void _run_glib_event_loop() g_main_loop_unref(main_loop); } +#endif static void _run_epoll_event_loop(vine_session_h session) { int fd; @@ -658,9 +660,11 @@ static void _run_epoll_event_loop(vine_session_h session) static void run_event_loop(vine_session_h session) { +#ifdef BT_SUPPORT if (vine_configs.with_ble) _run_glib_event_loop(); else +#endif _run_epoll_event_loop(session); } -- 2.7.4 From 9c3b279bc48977de1c134da148aa2d1578a3bdae Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 2 Jul 2021 11:50:29 +0900 Subject: [PATCH 02/16] Add null check in discovered_cb Change-Id: I29a3e3044473ad3943131b91a4b2b896a0e15ace Signed-off-by: Cheoleun Moon --- src/vine-disc.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index 01aa202..b0302b0 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -216,6 +216,9 @@ static void __discovered_cb(void *plugin_handle, bool available, const char *host_name, 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); @@ -246,6 +249,10 @@ 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); -- 2.7.4 From 733f2ff9c9feb90df21be4a2819fb99640e38835 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 2 Jul 2021 14:38:32 +0900 Subject: [PATCH 03/16] vine-tool: Handle SIGINT for glib event loop Change-Id: I2c4d09f46595ee29a913b4954a5833bdebd8bbfe Signed-off-by: Cheoleun Moon --- tool/tool_main.cpp | 3 +-- tool/tool_run.cpp | 21 ++++++++++++++++++--- tool/tool_run.h | 1 + 3 files changed, 20 insertions(+), 5 deletions(-) mode change 100644 => 100755 tool/tool_main.cpp mode change 100644 => 100755 tool/tool_run.h diff --git a/tool/tool_main.cpp b/tool/tool_main.cpp old mode 100644 new mode 100755 index 72c47d6..87f055a --- a/tool/tool_main.cpp +++ b/tool/tool_main.cpp @@ -7,10 +7,9 @@ #include "tool_parse.h" #include "tool_run.h" -int interrupt_flag = 0; static void interrupt_handler(int signo) { - interrupt_flag = 1; + stop_event_loop(); } int main(int argc, char **argv) diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index c76cadd..384bcc1 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -25,7 +25,7 @@ #define MAX_EVENTS 10 #define MAX_READ_LEN 1024 -extern int interrupt_flag; +int interrupt_flag; static int epollfd = 0; static FILE *log_file = NULL; @@ -71,6 +71,10 @@ static int send_message(vine_dp_h dp); static void _stop_message_timer(vine_dp_h dp); static int joined_peer = 0; +#ifdef USE_VINE_EVENT_LOOP_EXTERNAL_GLIB +static GMainLoop *main_loop = NULL; +#endif + static vine_dp_type_e _convert_dp_type(dp_type_t type) { switch (type) { @@ -610,16 +614,27 @@ static void _event_handler(vine_session_h session) vine_session_process_event(session); } -#ifdef BT_SUPPORT +#ifdef USE_VINE_EVENT_LOOP_EXTERNAL_GLIB static void _run_glib_event_loop() { - GMainLoop *main_loop = g_main_loop_new(NULL, FALSE); + main_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(main_loop); g_main_loop_unref(main_loop); } #endif + +void stop_event_loop() +{ +#ifdef USE_VINE_EVENT_LOOP_EXTERNAL_GLIB + if (main_loop) + g_main_loop_quit(main_loop); +#else + interrupt_flag = 1; +#endif +} + static void _run_epoll_event_loop(vine_session_h session) { int fd; diff --git a/tool/tool_run.h b/tool/tool_run.h old mode 100644 new mode 100755 index a00b9e6..c038361 --- a/tool/tool_run.h +++ b/tool/tool_run.h @@ -1 +1,2 @@ int tool_run(); +void stop_event_loop(); -- 2.7.4 From 5076fd0b8a5250678534748b653d5f9522dbd030 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Fri, 2 Jul 2021 15:40:53 +0900 Subject: [PATCH 04/16] Fix resource leak Change-Id: I29ed976a281773c75f8f1a5eaed108edcb09b4a3 Signed-off-by: Cheoleun Moon --- src/vine-disc.cpp | 20 ++++++++++++-------- tool/tool_run.cpp | 3 --- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index b0302b0..9626153 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -239,10 +239,12 @@ static void __discovered_cb(void *plugin_handle, bool available, VINE_LOGD("Create a discovered_event[%p]", discovered_event); vine_disc_s *disc_handle = (vine_disc_s *)user_data; - if (disc_handle) - vine_event_loop_add_event(disc_handle->event_queue, discovered_event, - __invoke_discovered_user_cb, __free_discovered_event, - 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 __ble_discovered_cb(void *plugin_handle, bool available, @@ -267,10 +269,12 @@ static void __ble_discovered_cb(void *plugin_handle, bool available, VINE_LOGD("Create a discovered_event[%p]", discovered_event); vine_disc_s *disc_handle = (vine_disc_s *)user_data; - if (disc_handle) - vine_event_loop_add_event(disc_handle->event_queue, discovered_event, - __invoke_discovered_user_cb, __free_discovered_event, - 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, diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index 384bcc1..6c8445a 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -264,9 +264,6 @@ static void __ble_service_discovered(vine_session_h session, vine_service_h serv vine_service_state_e state, void *user_data) { printf("available[%d]\n", state); - vine_service_h s; - vine_service_clone(service, &s); - printf("Service discovered.\n"); char *service_type; -- 2.7.4 From 8199e3839bcb5aa386e18117e344236ecd6b49a1 Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Mon, 5 Jul 2021 17:02:17 +0900 Subject: [PATCH 05/16] ble disc: Do not set service_data Change-Id: I53ee0fc993a628c12a2028079641b3a588ec0271 Signed-off-by: Cheoleun Moon --- plugins/ble/ble-plugin.cpp | 12 +----------- src/vine-disc.cpp | 1 + 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/plugins/ble/ble-plugin.cpp b/plugins/ble/ble-plugin.cpp index 33f057b..4388042 100755 --- a/plugins/ble/ble-plugin.cpp +++ b/plugins/ble/ble-plugin.cpp @@ -207,17 +207,6 @@ static int __configure_advertiser(bt_advertiser_h adv, BT_ADAPTER_LE_PACKET_ADVERTISING, VINE_UUID); RET_VAL_IF(ret != BT_ERROR_NONE, ret, "bt_adapter_le_add_advertising_service_uuid() fails %d", ret); - // TODO: Determine which data should be set for service_data - // It should be set mandatorily? - // Or we don't have to set service_data if manufacturer data is set - char service_data[3] = {0x01, 0x02, 0x03}; - // TODO: ALso set for BT_ADAPTER_LE_PACKET_ADVERTISING? - ret = bt_adapter_le_add_advertising_service_data(adv, - BT_ADAPTER_LE_PACKET_SCAN_RESPONSE, - VINE_UUID, service_data, sizeof(service_data)); - RET_VAL_IF(ret != BT_ERROR_NONE, ret, - "bt_adapter_le_add_advertising_service_data() fails %s(%d)", - __convert_ble_erro_to_str(ret), ret); // TODO: Also set for BT_ADAPTER_LE_PACKET_ADVERTISING? ret = bt_adapter_le_set_advertising_device_name(adv, @@ -355,6 +344,7 @@ static void __le_scan_result_cb(int result, bt_adapter_le_device_scan_result_inf char service_name[VINE_MAX_BLE_SERVICE_NAME_LEN + 1] = {0, }; int service_name_len = manufacturer_len - 1 - service_type_len; strncpy(service_name, manufacturer_data + service_type_len + 1, VINE_MAX_BLE_SERVICE_NAME_LEN); + service_name[service_name_len] = 0; char mac[VINE_MAC_LEN + 1] = {0, }; strncpy(mac, info->remote_address, VINE_MAC_LEN); diff --git a/src/vine-disc.cpp b/src/vine-disc.cpp index 9626153..b6ddf24 100755 --- a/src/vine-disc.cpp +++ b/src/vine-disc.cpp @@ -265,6 +265,7 @@ static void __ble_discovered_cb(void *plugin_handle, bool 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); -- 2.7.4 From 99a86f2a4eb517d71294f4e27328225bb01c24c6 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Fri, 2 Jul 2021 14:24:45 +0900 Subject: [PATCH 06/16] First draft for BLE GATT plugin Change-Id: I70065ea272a3fe63ca156188656112fce04333cc --- plugins/ble/gatt-plugin.cpp | 504 ++++++++++++++++++++++++++++++++++++ src/include/vine-data-path-plugin.h | 1 + 2 files changed, 505 insertions(+) create mode 100755 plugins/ble/gatt-plugin.cpp diff --git a/plugins/ble/gatt-plugin.cpp b/plugins/ble/gatt-plugin.cpp new file mode 100755 index 0000000..19898d0 --- /dev/null +++ b/plugins/ble/gatt-plugin.cpp @@ -0,0 +1,504 @@ +/* + * 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 "vine-data-path-plugin.h" +#include "vine-log.h" +#include "vine-utils.h" + +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_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66" + +typedef enum { + VINE_GATT_ROLE_UNKNOWN = 0, + VINE_GATT_ROLE_SERVER, + VINE_GATT_ROLE_CLIENT, +} vine_gatt_role_e; + +typedef struct { + bt_gatt_h service; + bt_gatt_h characteristic; + bt_gatt_h descriptor; + + vine_gatt_role_e type; + union { + bt_gatt_server_h server; + bt_gatt_client_h client; + } role; + + char *remote_address; + bool is_accepted; + void *user; // vine_data_path_h +} vine_gatt_s; + +static vine_dp_plugin_callbacks g_callbacks = { + .pollfd_cb = NULL, + .opened_cb = NULL, + .accepted_cb = NULL, + .connected_cb = NULL, + .received_cb = NULL, + .written_cb = NULL, + .terminated_cb = NULL, +}; + +static vine_gatt_s *_create_gatt(void); + +static vine_data_path_error __convert_bt_error_to_data_path_error(int error) +{ + switch (error) { + case BT_ERROR_NONE: + return VINE_DATA_PATH_ERROR_NONE; + case BT_ERROR_OUT_OF_MEMORY: + return VINE_DATA_PATH_ERROR_OUT_OF_MEMORY; + case BT_ERROR_INVALID_PARAMETER: + return VINE_DATA_PATH_ERROR_INVALID_PARAMETER; + case BT_ERROR_OPERATION_FAILED: + default: + return VINE_DATA_PATH_ERROR_OPERATION_FAILED; + } +} + +static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data) +{ + if (!g_callbacks.accepted_cb) + return; + + vine_gatt_s *accepted_gatt = _create_gatt(); + RET_IF(accepted_gatt == NULL, "Failed to create accepted_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->is_accepted = true; + accepted_gatt->user = user_data; + + g_callbacks.accepted_cb(VINE_DP_NOT_IP, accepted_gatt->remote_address, 0, accepted_gatt, user_data); +} + +static void __invoke_connected_cb(int result, void *user_data) +{ + if (!g_callbacks.connected_cb) + return; + g_callbacks.connected_cb(result, user_data); +} + +static void __invoke_terminated_cb(void *user_data) +{ + if (!g_callbacks.terminated_cb) + return; + g_callbacks.terminated_cb(user_data); +} + +// Server Callbacks +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. +} + +static void __gatt_server_write_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) +{ + VINE_LOGI("Got write value requestment from %s.", remote_address); + + // TODO: Send response. +} + +void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, + bt_gatt_h gatt_handle, void *user_data) +{ + VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle); +} + +// Client Callbacks +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) +{ + VINE_LOGI("gatt[%p] service[%s] is %s", + type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." ); +} + +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"); + RET_VAL_IF(remote_address == NULL, + VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "remote_address is NULL"); + + bt_gatt_client_h client = NULL; + bt_gatt_h service = NULL; + bt_gatt_h characteristic = NULL; + int ret; + + ret = bt_gatt_client_create(remote_address, &client); + if (ret != BT_ERROR_NONE || !client) + return __convert_bt_error_to_data_path_error(ret); + + ret = bt_gatt_client_set_service_changed_cb(client, __gatt_client_service_changed_cb, gatt); + if (ret != BT_ERROR_NONE) + goto ERR; + + ret = bt_gatt_client_get_service(client, VINE_GATT_SERVICE_UUID, &service); + if (ret != BT_ERROR_NONE) + goto ERR; + + ret = bt_gatt_service_get_characteristic(service, VINE_GATT_CHAR_UUID, &characteristic); + if (ret != BT_ERROR_NONE) + goto ERR; + + gatt->role.client = client; + gatt->service = service; + gatt->characteristic = characteristic; + + VINE_LOGE("Succeeded to update GATT service info."); + return VINE_DATA_PATH_ERROR_NONE; + +ERR: + VINE_LOGE("Failed to update GATT service info."); + bt_gatt_client_destroy(client); + return __convert_bt_error_to_data_path_error(ret); +} + +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]", + gatt, result, connected, remote_address); + + if (!connected) { + __invoke_terminated_cb(gatt->user); + return; + } + + if (gatt->type == VINE_GATT_ROLE_SERVER) { + __invoke_accepted_cb(remote_address, gatt, gatt->user); + } 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; + } + __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)); + RET_VAL_IF(gatt == NULL, NULL, "Out of memory"); + + 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; + } + return gatt; +} + +static bt_gatt_h _add_gatt_characteristic(bt_gatt_h service, 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_NOTIFY; + + if (bt_gatt_characteristic_create(VINE_GATT_CHAR_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) + goto ERR; + + if (bt_gatt_server_set_write_value_requested_cb(characteristic, + __gatt_server_write_value_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) + goto ERR; + + if (bt_gatt_service_add_characteristic(service, characteristic) != BT_ERROR_NONE) + goto ERR; + + VINE_LOGI("Succeeded to add GATT characteristic."); + return characteristic; + +ERR: + bt_gatt_characteristic_destroy(characteristic); + return NULL; +} + +static bt_gatt_h _add_gatt_descriptor(bt_gatt_h characteristic) +{ + bt_gatt_h descriptor = NULL; + char initial_value[1] = {'0'}; // TODO: will be changed + int permissions = BT_GATT_PERMISSION_READ | BT_GATT_PERMISSION_WRITE; + + // TODO: Change UUID + if (bt_gatt_descriptor_create("2902", permissions, + initial_value, sizeof(initial_value), &descriptor) != BT_ERROR_NONE) + return NULL; + + if (bt_gatt_characteristic_add_descriptor(characteristic, descriptor) != BT_ERROR_NONE) { + bt_gatt_descriptor_destroy(descriptor); + return NULL; + } + return descriptor; +} + +int gatt_init(void) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +void gatt_deinit(void) +{ +} + +void gatt_register_callbacks(vine_dp_plugin_callbacks callbacks) +{ + g_callbacks = callbacks; +} + +void gatt_process_event(int gatt_fd, int events) +{ + // Do nothing. use g_main_loop. +} + +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"); + + vine_gatt_s *gatt = _create_gatt(); + RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "Out of memory"); + + gatt->user = user; + *handle = gatt; + + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_destroy(vine_dp_plugin_h handle) +{ + RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)handle; + + if (gatt->type == VINE_GATT_ROLE_SERVER) { + bt_gatt_server_destroy(gatt->role.server); + gatt->role.server = NULL; + bt_gatt_service_destroy(gatt->service); + bt_gatt_characteristic_destroy(gatt->characteristic); + bt_gatt_descriptor_destroy(gatt->descriptor); + } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { + // bt_gatt_h handles will be freed during bt_gatt_client_destroy(). + bt_gatt_client_destroy(gatt->role.client); + gatt->role.client = NULL; + } + + gatt->service = NULL; + gatt->characteristic = NULL; + gatt->descriptor = NULL; + free(gatt->remote_address); + gatt->remote_address = NULL; + free(gatt); + + return VINE_DATA_PATH_ERROR_NONE; +} + +// All parameters except handle are not used in BT GATT. +int gatt_open(vine_dp_plugin_h handle, int addr_family, + int gatt_port, const char *iface_name, int max_conn, vine_dp_ssl ssl) // server only +{ + RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); + + 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; + int ret = BT_ERROR_OPERATION_FAILED; + + // This returns OPERATION_FAILED when already initialized. ignore it. + bt_gatt_server_initialize(); + + ret = bt_gatt_server_create(&server); + if (ret != BT_ERROR_NONE || !server) { + VINE_LOGE("Failed to create GATT server"); + goto ERR; + } + + ret = bt_gatt_service_create(VINE_GATT_SERVICE_UUID, BT_GATT_SERVICE_TYPE_PRIMARY, &service); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to create service."); + goto ERR; + } + + characteristic = _add_gatt_characteristic(service, handle); + if (!characteristic) { + VINE_LOGE("Failed to add characteristc."); + goto ERR; + } + + descriptor = _add_gatt_descriptor(characteristic); + if (!characteristic) { + VINE_LOGE("Failed to add descriptor."); + goto ERR; + } + + 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(); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to start GATT server."); + goto ERR; + } + + gatt->type = VINE_GATT_ROLE_SERVER; + gatt->role.server = server; + gatt->service = service; + gatt->characteristic = characteristic; + gatt->descriptor = descriptor; + + VINE_LOGI("Succeeded to start GATT server."); + return VINE_DATA_PATH_ERROR_NONE; + +ERR: + if (server) + 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); + 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) +{ + 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"); + + vine_gatt_s *gatt = (vine_gatt_s *)handle; + bt_gatt_client_h client = NULL; + int ret; + + ret = bt_gatt_connect(addr, false); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to connect remote LE based service."); + return __convert_bt_error_to_data_path_error(ret); + } + + gatt->type = VINE_GATT_ROLE_CLIENT; + gatt->role.client = client; + gatt->remote_address = STRDUP(addr); + + VINE_LOGI("Succeed to request to GATT connect."); + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_read(vine_dp_plugin_h handle, unsigned char *buf, size_t len) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +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"); + + // TODO + // vine_gatt_s *gatt = (vine_gatt_s *)handle; + + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_close(vine_dp_plugin_h handle) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_get_local_address_info(vine_dp_plugin_h handle, + int *addr_family, char local_ip[], int *port) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_set_token(vine_dp_plugin_h handle, const char *token) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_get_token(vine_dp_plugin_h handle, char **token) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +int gatt_set_host_name(vine_dp_plugin_h handle, const char *name) +{ + return VINE_DATA_PATH_ERROR_NONE; +} + +void vine_data_path_plugin_init(vine_dp_plugin_fn *fn) +{ + fn->init = gatt_init; + fn->deinit = gatt_deinit; + fn->register_callbacks = gatt_register_callbacks; + fn->process_event = gatt_process_event; + + fn->create = gatt_create; + fn->destroy = gatt_destroy; + fn->open = gatt_open; + fn->connect = gatt_connect; + fn->read = gatt_read; + fn->write = gatt_write; + fn->close = gatt_close; + + fn->get_local_address_info = gatt_get_local_address_info; + + fn->set_token = gatt_set_token; + fn->get_token = gatt_get_token; + fn->set_host_name = gatt_set_host_name; +} diff --git a/src/include/vine-data-path-plugin.h b/src/include/vine-data-path-plugin.h index 214d0d8..4a451d0 100755 --- a/src/include/vine-data-path-plugin.h +++ b/src/include/vine-data-path-plugin.h @@ -48,6 +48,7 @@ typedef enum { VINE_DP_IPV4_IPV6 = 0, // IPv6 has higer priority. VINE_DP_IPV4, VINE_DP_IPV6, + VINE_DP_NOT_IP } vine_dp_addr_family_e; typedef enum { -- 2.7.4 From 99174aea0dace47bcf4f4be517711c3976bfc5fc Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Mon, 5 Jul 2021 11:21:58 +0900 Subject: [PATCH 07/16] Seperate GATT from BLE plugin Change-Id: I341ad739a779a0d4659da478e6acf00d8c4a8d2c --- CMakeLists.txt | 1 + plugins/ble-gatt/CMakeLists.txt | 51 ++++++++++++++++++++++ .../ble-gatt-plugin.cpp} | 0 plugins/ble-gatt/ble-gatt-plugin.h | 18 ++++++++ 4 files changed, 70 insertions(+) create mode 100755 plugins/ble-gatt/CMakeLists.txt rename plugins/{ble/gatt-plugin.cpp => ble-gatt/ble-gatt-plugin.cpp} (100%) create mode 100755 plugins/ble-gatt/ble-gatt-plugin.h diff --git a/CMakeLists.txt b/CMakeLists.txt index eae5055..a6834a7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -127,6 +127,7 @@ ENDIF(USE_LIBWEBSOCKETS) ADD_SUBDIRECTORY(plugins/dns-sd) IF(BT_SUPPORT) ADD_SUBDIRECTORY(plugins/ble) + ADD_SUBDIRECTORY(plugins/ble-gatt) ENDIF(BT_SUPPORT) ADD_SUBDIRECTORY(include) diff --git a/plugins/ble-gatt/CMakeLists.txt b/plugins/ble-gatt/CMakeLists.txt new file mode 100755 index 0000000..977029e --- /dev/null +++ b/plugins/ble-gatt/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 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. +# + +SET(BLE_GATT_PLUGIN "vine-plugin-ble-gatt") + +SET(BLE_GATT_PLUGIN_VERSION_MAJOR "1") +SET(BLE_GATT_PLUGIN_VERSION_MINOR "0") +SET(BLE_GATT_PLUGIN_VERSION_PATCH "0") +SET(BLE_GATT_PLUGIN_VERSION ${BLE_GATT_PLUGIN_VERSION_MAJOR}.${BLE_GATT_PLUGIN_VERSION_MINOR}.${BLE_GATT_PLUGIN_VERSION_PATCH}) + +PKG_CHECK_MODULES(BLE_DEPS REQUIRED "capi-network-bluetooth") + +INCLUDE_DIRECTORIES( + ${VINE_PATH}/include + ${VINE_LOGGER_PATH} + ${CMAKE_CURRENT_SOURCE_DIR} + ${${fw_name}_INCLUDE_DIRS} + ${BLE_DEPS_INCLUDE_DIRS} +) + +FILE(GLOB VINE_BLE_GATT_PLUGIN_SOURCES *.cpp) + +ADD_DEFINITIONS("-fvisibility=default") +ADD_LIBRARY(${BLE_GATT_PLUGIN} SHARED ${VINE_BLE_GATT_PLUGIN_SOURCES}) + +SET_TARGET_PROPERTIES( + ${BLE_GATT_PLUGIN} + PROPERTIES + SOVERSION ${BLE_GATT_PLUGIN_VERSION_MAJOR} +) + +TARGET_LINK_LIBRARIES(${BLE_GATT_PLUGIN} + ${VINE_LOGGER} + ${BLE_DEPS_LIBRARIES} + ${fw_name_deps_LIBRARIES} + dl +) + +INSTALL(TARGETS ${BLE_GATT_PLUGIN} DESTINATION "${LIB_DIR}") diff --git a/plugins/ble/gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp similarity index 100% rename from plugins/ble/gatt-plugin.cpp rename to plugins/ble-gatt/ble-gatt-plugin.cpp diff --git a/plugins/ble-gatt/ble-gatt-plugin.h b/plugins/ble-gatt/ble-gatt-plugin.h new file mode 100755 index 0000000..d1766f0 --- /dev/null +++ b/plugins/ble-gatt/ble-gatt-plugin.h @@ -0,0 +1,18 @@ +/* + * 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 -- 2.7.4 From 0c41ab9a379dc3269b628794a477228153b0198a Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Tue, 6 Jul 2021 19:11:22 +0900 Subject: [PATCH 08/16] Add new API to set DP method Change-Id: I92440476858e246d859bb31958e65e0bacff7330 --- include/vine.h | 28 ++++- plugins/ble-gatt/ble-gatt-plugin.cpp | 2 +- src/include/vine-data-path-plugin.h | 8 +- src/include/vine-data-path-state.h | 29 +++-- src/include/vine-data-path.h | 12 +- src/include/vine-dp.h | 7 ++ src/vine-data-path-state.cpp | 99 ++++++++-------- src/vine-data-path.cpp | 213 +++++++++++++++++++++++------------ src/vine-dp.cpp | 74 +++++++++++- src/vine.cpp | 8 ++ tests/unittest/vine-unittest-dp.cpp | 14 +++ tool/tool_run.cpp | 3 + 12 files changed, 350 insertions(+), 147 deletions(-) diff --git a/include/vine.h b/include/vine.h index aa9d10b..c9a663f 100755 --- a/include/vine.h +++ b/include/vine.h @@ -271,6 +271,16 @@ typedef enum { } vine_discovery_method_e; /** + * @brief Enumeration for data path method + * @since_tizen 6.5 + */ +typedef enum { + VINE_DP_METHOD_DEFAULT = 0, + VINE_DP_METHOD_BLE_GATT, + VINE_DP_METHOD_UNKNOWN +} vine_dp_method_e; + +/** * @brief Enumeration for address family * @since_tizen 6.5 */ @@ -868,6 +878,20 @@ int vine_dp_create(vine_session_h session, vine_dp_type_e type, vine_dp_h *dp); int vine_dp_destroy(vine_dp_h dp); /** + * @brief Sets the data path method + * @remarks Default method is websocket + * @since_tizen 6.5 + * @param[in] dp The data path handle + * @param[in] method The data path method + * @return 0 on success, otherwise a negative error value + * @retval #VINE_ERROR_NONE Successful + * @retval #VINE_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #VINE_ERROR_NOT_SUPPORTED Not supported + * @see vine_dp_create() + */ +int vine_dp_set_method(vine_dp_h dp, vine_dp_method_e method); + +/** * @brief Gets the Id for DP_TYPE_PUBSUB. * @remarks This should be called after completing vine_dp_open() * @since_tizen 6.5 @@ -1153,7 +1177,9 @@ typedef void (*vine_dp_opened_cb)(vine_dp_h dp, vine_error_e result, void *user_ /** * @brief Opens a datapath. - * @remarks This works depending on the type of datapath differently. + * @remarks This works depending on the type of datapath differently. \ + * If you want to open VINE_DP_SERVER with BLE GATT, \ + * BLE service should be registered before. * If @a dp is a server, a listen port is opened. * If @a dp is a client, it tries to connect to a server. * If @a dp is for Publish-Subscribe, it joins to a service which has the same topic. diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index 19898d0..dccb252 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -304,7 +304,7 @@ int gatt_create(vine_dp_plugin_h *handle, void *plugin_data, void *user) RET_VAL_IF(user == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "user is NULL"); vine_gatt_s *gatt = _create_gatt(); - RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OUT_OF_MEMORY, "Out of memory"); + RET_VAL_IF(gatt == NULL, VINE_DATA_PATH_ERROR_OPERATION_FAILED, "Failed to create GATT handle"); gatt->user = user; *handle = gatt; diff --git a/src/include/vine-data-path-plugin.h b/src/include/vine-data-path-plugin.h index 4a451d0..e74ad5c 100755 --- a/src/include/vine-data-path-plugin.h +++ b/src/include/vine-data-path-plugin.h @@ -17,12 +17,8 @@ #ifndef __VINE_DATA_PATH_PLUGIN_H__ #define __VINE_DATA_PATH_PLUGIN_H__ -#ifdef USE_LIBWEBSOCKETS -#define LIBWEBSOCKETS_PLUGIN_PATH "libvine-plugin-libwebsockets.so" -#define DATA_PATH_PLUGIN_PATH LIBWEBSOCKETS_PLUGIN_PATH -#else -#define DATA_PATH_PLUGIN_PATH "" -#endif +#define LWS_PLUGIN_PATH "libvine-plugin-libwebsockets.so" +#define BLE_GATT_PLUGIN_PATH "libvine-plugin-ble-gatt.so" #define VINE_DATA_PATH_MAX_BUFFER_SIZE 131072 // 128 * 1024 bytes diff --git a/src/include/vine-data-path-state.h b/src/include/vine-data-path-state.h index 4147ecb..7ac17ba 100644 --- a/src/include/vine-data-path-state.h +++ b/src/include/vine-data-path-state.h @@ -34,7 +34,7 @@ typedef void *vine_data_path_h; class VineDataPathState { public: - VineDataPathState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineDataPathState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); virtual ~VineDataPathState(); virtual void enter() = 0; @@ -51,13 +51,14 @@ public: protected: vine_data_path_h __dp; vine_dp_plugin_h __plugin; + vine_dp_plugin_fn __fn; }; // Vine Datapath is in the VineDefaultState when initialized class VineDefaultState : public VineDataPathState { public: - VineDefaultState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineDefaultState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineDefaultState(); void enter(); @@ -78,7 +79,7 @@ public: class VineAcceptedState : public VineDataPathState { public: - VineAcceptedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineAcceptedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineAcceptedState(); void enter(); @@ -107,7 +108,7 @@ private: class VineConnectedState : public VineDataPathState { public: - VineConnectedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineConnectedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineConnectedState(); void enter(); @@ -143,7 +144,7 @@ private: class VineAuthRequestedState : public VineDataPathState { public: - VineAuthRequestedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineAuthRequestedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineAuthRequestedState(); void enter(); @@ -178,7 +179,7 @@ private: class VineAuthRespondedState : public VineDataPathState { public: - VineAuthRespondedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineAuthRespondedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineAuthRespondedState(); void enter(); @@ -207,7 +208,7 @@ private: class VineAuthFailedState : public VineDataPathState { public: - VineAuthFailedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineAuthFailedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineAuthFailedState(); void enter(); @@ -226,7 +227,7 @@ public: class VineEstablishedState : public VineDataPathState { public: - VineEstablishedState(vine_data_path_h dp, vine_dp_plugin_h plugin); + VineEstablishedState(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); ~VineEstablishedState(); void enter(); @@ -248,7 +249,11 @@ void vine_dp_state_set_state_changed_notifier(state_changed_notifier notifier); void vine_dp_state_set_established_notifier(established_notifier notifier); void vine_dp_state_set_data_received_notifier(data_received_notifier notifier); -VineDataPathState *vine_get_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin); -void start_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin, VineDataPathState *state); -void start_connected_state(vine_data_path_h dp, vine_dp_plugin_h plugin, VineDataPathState *state); -void start_accepted_state(vine_data_path_h dp, vine_dp_plugin_h plugin, VineDataPathState *state); +VineDataPathState *vine_get_default_state(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn); +void start_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, + VineDataPathState *state); +void start_connected_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, + VineDataPathState *state); +void start_accepted_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, + VineDataPathState *state); diff --git a/src/include/vine-data-path.h b/src/include/vine-data-path.h index 8a64d34..775cb21 100755 --- a/src/include/vine-data-path.h +++ b/src/include/vine-data-path.h @@ -18,6 +18,7 @@ #define __VINE_DATA_PATH_H__ #include "vine.h" +#include "vine-data-path.h" #include "vine-data-path-state.h" #include "vine-event-loop.h" @@ -31,18 +32,25 @@ typedef void (*vine_data_path_accepted_cb)(vine_data_path_h datapath, void *user typedef void (*vine_data_path_connected_cb)(vine_data_path_h datapath, int result, void *user_data); typedef void (*vine_data_path_terminated_cb)(vine_data_path_h datapath, void *user_data); +typedef enum { + VINE_DATA_PATH_METHOD_LWS = 0, // default + VINE_DATA_PATH_METHOD_BLE_GATT, + VINE_DATA_PATH_METHOD_UNKNOWN +} vine_data_path_method_e; int vine_data_path_init(void); int vine_data_path_deinit(void); -int vine_data_path_open(vine_address_family_e addr_family, int port, +int vine_data_path_open(vine_data_path_method_e method, + vine_address_family_e addr_family, int port, const char *iface_name, int max_conn, vine_security_h security, const char *host_name, vine_data_path_opened_cb opened_cb, void *opened_cb_data, vine_data_path_accepted_cb accepted_cb, void *accepted_cb_data, vine_data_path_h *opened_datapath, vine_event_queue_h event_queue); -int vine_data_path_connect(vine_address_family_e addr_family, +int vine_data_path_connect(vine_data_path_method_e method, + vine_address_family_e addr_family, const char *ip, int port, const char *iface_name, vine_security_h security, const char *host_name, const char *token, vine_data_path_connected_cb callback, void *user_data, diff --git a/src/include/vine-dp.h b/src/include/vine-dp.h index eb7eb43..498aefd 100644 --- a/src/include/vine-dp.h +++ b/src/include/vine-dp.h @@ -47,6 +47,7 @@ public: virtual int send(unsigned char *buf, size_t len) = 0; virtual int recv(unsigned char *buf, size_t buf_len, size_t *read_len) = 0; + virtual int set_method(vine_dp_method_e method) = 0; virtual int get_id(char **id) = 0; virtual int set_addr_family(vine_address_family_e addr_family) = 0; virtual int set_remote_ip(vine_address_family_e, const std::string &ip) = 0; @@ -80,6 +81,8 @@ public: void invoke_received_cb(size_t received_len); protected: + vine_data_path_method_e mMethod; + void *mEventQueue; void *mSecurity; std::string mIfaceName; @@ -105,6 +108,7 @@ public: virtual int send(unsigned char *buf, size_t len); virtual int recv(unsigned char *buf, size_t buf_len, size_t *read_len); + virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); @@ -149,6 +153,7 @@ public: virtual int send(unsigned char *buf, size_t len); virtual int recv(unsigned char *buf, size_t buf_len, size_t *read_len); + virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); @@ -203,6 +208,7 @@ public: virtual int send(unsigned char *buf, size_t len); virtual int recv(unsigned char *buf, size_t buf_len, size_t *read_len); + virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); @@ -277,6 +283,7 @@ private: int _vine_dp_create(vine_session_h session, vine_dp_type_e type, vine_dp_h *dp); int _vine_dp_destroy(vine_dp_h dp); +int _vine_dp_set_method(vine_dp_h dp, vine_dp_method_e method); int _vine_dp_get_id(vine_dp_h dp, char **id); int _vine_dp_set_iface_name(vine_dp_h dp, const char *iface_name); int _vine_dp_set_addr_family(vine_dp_h dp, vine_address_family_e addr_family); diff --git a/src/vine-data-path-state.cpp b/src/vine-data-path-state.cpp index 2c62af2..c7f1bf7 100644 --- a/src/vine-data-path-state.cpp +++ b/src/vine-data-path-state.cpp @@ -22,8 +22,6 @@ #include "vine-log.h" #include "vine-utils.h" -extern vine_dp_plugin_fn g_dp_plugin_fn; - static state_changed_notifier __set_state; static established_notifier __established; static data_received_notifier __data_received; @@ -37,15 +35,17 @@ static void state_transition(vine_data_path_h dp, new_state->enter(); } -VineDataPathState::VineDataPathState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : __dp(dp), __plugin(plugin) +VineDataPathState::VineDataPathState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : __dp(dp), __plugin(plugin), __fn(fn) {} VineDataPathState::~VineDataPathState() {} -VineDefaultState::VineDefaultState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin) +VineDefaultState::VineDefaultState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn) { } @@ -78,8 +78,9 @@ void VineDefaultState::received_cb(size_t bytes) void VineDefaultState::written_cb(size_t bytes) {} -VineAcceptedState::VineAcceptedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin), __sent_frame(0), __accept(0) +VineAcceptedState::VineAcceptedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn), __sent_frame(0), __accept(0) { } @@ -142,13 +143,13 @@ void VineAcceptedState::written_cb(size_t bytes) VINE_LOGD("+"); switch (__sent_frame) { case AUTH_OP_REQUEST: - state_transition(__dp, this, new VineAuthRequestedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthRequestedState(__dp, __plugin, __fn)); break; case AUTH_OP_CONFIRM: if (__accept == 1) - state_transition(__dp, this, new VineEstablishedState(__dp, __plugin)); + state_transition(__dp, this, new VineEstablishedState(__dp, __plugin, __fn)); else - state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin, __fn)); break; default: VINE_LOGE("Invalid Frame %d", __sent_frame); @@ -158,7 +159,7 @@ void VineAcceptedState::written_cb(size_t bytes) void VineAcceptedState::handle_failure(std::string msg) { VINE_LOGE("Failure %s", msg.c_str()); - state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin, __fn)); } void VineAcceptedState::send_auth_request() @@ -175,7 +176,7 @@ void VineAcceptedState::send_auth_request() return; } - g_dp_plugin_fn.write(__plugin, frame, size); + __fn.write(__plugin, frame, size); release_auth_frame(frame); } @@ -195,12 +196,13 @@ void VineAcceptedState::send_auth_confirm(int accept) return; } - g_dp_plugin_fn.write(__plugin, frame, size); + __fn.write(__plugin, frame, size); release_auth_frame(frame); } -VineConnectedState::VineConnectedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin), __sent_frame(0) +VineConnectedState::VineConnectedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn), __sent_frame(0) { } @@ -248,7 +250,7 @@ void VineConnectedState::written_cb(size_t bytes) VINE_LOGD("+"); switch (__sent_frame) { case AUTH_OP_RESPONSE: - state_transition(__dp, this, new VineAuthRespondedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthRespondedState(__dp, __plugin, __fn)); break; default: VINE_LOGE("Invalid Frame %d", __sent_frame); @@ -258,13 +260,13 @@ void VineConnectedState::written_cb(size_t bytes) void VineConnectedState::handle_failure(std::string msg) { VINE_LOGE("Failure %s", msg.c_str()); - state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin, __fn)); } void VineConnectedState::read_data(size_t bytes) { unsigned char *buf = (unsigned char *)malloc(bytes); - size_t read_size = g_dp_plugin_fn.read(__plugin, buf, bytes); + size_t read_size = __fn.read(__plugin, buf, bytes); if (bytes != read_size) { // TODO: Check it handle_failure("Wrong size"); @@ -345,7 +347,7 @@ void VineConnectedState::recv_auth_confirm(unsigned char ver, return; } - state_transition(__dp, this, new VineEstablishedState(__dp, __plugin)); + state_transition(__dp, this, new VineEstablishedState(__dp, __plugin, __fn)); } void VineConnectedState::send_auth_response() @@ -369,15 +371,16 @@ void VineConnectedState::send_auth_response() return; } - g_dp_plugin_fn.write(__plugin, frame, size); + __fn.write(__plugin, frame, size); release_auth_frame(frame); free(psk); __sent_frame = AUTH_OP_RESPONSE; } -VineAuthRequestedState::VineAuthRequestedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin), __sent_frame(0), __accept(0) +VineAuthRequestedState::VineAuthRequestedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn), __sent_frame(0), __accept(0) { } @@ -423,7 +426,7 @@ void VineAuthRequestedState::written_cb(size_t bytes) switch (__sent_frame) { case AUTH_OP_CONFIRM: if (__accept == 1) - state_transition(__dp, this, new VineEstablishedState(__dp, __plugin)); + state_transition(__dp, this, new VineEstablishedState(__dp, __plugin, __fn)); else handle_failure("Not Accepted"); break; @@ -435,13 +438,13 @@ void VineAuthRequestedState::written_cb(size_t bytes) void VineAuthRequestedState::handle_failure(std::string msg) { VINE_LOGE("Failure %s", msg.c_str()); - state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin, __fn)); } void VineAuthRequestedState::read_data(size_t bytes) { unsigned char *buf = (unsigned char *)malloc(bytes); - size_t read_size = g_dp_plugin_fn.read(__plugin, buf, bytes); + size_t read_size = __fn.read(__plugin, buf, bytes); if (bytes != read_size) { // TODO: Check it @@ -533,15 +536,16 @@ void VineAuthRequestedState::send_auth_confirm(int accept) return; } - g_dp_plugin_fn.write(__plugin, frame, size); + __fn.write(__plugin, frame, size); release_auth_frame(frame); __sent_frame = AUTH_OP_CONFIRM; __accept = accept; } -VineAuthRespondedState::VineAuthRespondedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin) +VineAuthRespondedState::VineAuthRespondedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn) { } @@ -589,13 +593,13 @@ void VineAuthRespondedState::written_cb(size_t bytes) void VineAuthRespondedState::handle_failure(std::string msg) { VINE_LOGE("Failure %s", msg.c_str()); - state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin)); + state_transition(__dp, this, new VineAuthFailedState(__dp, __plugin, __fn)); } void VineAuthRespondedState::read_data(size_t bytes) { unsigned char *buf = (unsigned char *)malloc(bytes); - size_t read_size = g_dp_plugin_fn.read(__plugin, buf, bytes); + size_t read_size = __fn.read(__plugin, buf, bytes); if (bytes != read_size) { // TODO: Check it @@ -646,11 +650,12 @@ void VineAuthRespondedState::recv_auth_confirm(unsigned char ver, } __timer.stop(); - state_transition(__dp, this, new VineEstablishedState(__dp, __plugin)); + state_transition(__dp, this, new VineEstablishedState(__dp, __plugin, __fn)); } -VineAuthFailedState::VineAuthFailedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin) +VineAuthFailedState::VineAuthFailedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn) { } @@ -687,8 +692,9 @@ void VineAuthFailedState::written_cb(size_t bytes) VINE_LOGD("+"); } -VineEstablishedState::VineEstablishedState(vine_data_path_h dp, vine_dp_plugin_h plugin) - : VineDataPathState(dp, plugin) +VineEstablishedState::VineEstablishedState(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) + : VineDataPathState(dp, plugin, fn) { } @@ -708,14 +714,14 @@ void VineEstablishedState::exit() int VineEstablishedState::read(unsigned char *buf, size_t buf_len, size_t *read_len) { - size_t bytes = g_dp_plugin_fn.read(__plugin, buf, buf_len); + size_t bytes = __fn.read(__plugin, buf, buf_len); *read_len = bytes; return VINE_ERROR_NONE; } int VineEstablishedState::write(unsigned char *buf, size_t len) { - g_dp_plugin_fn.write(__plugin, buf, len); + __fn.write(__plugin, buf, len); return VINE_ERROR_NONE; } @@ -748,28 +754,29 @@ void vine_dp_state_set_data_received_notifier(data_received_notifier notifier) __data_received = notifier; } -VineDataPathState *vine_get_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin) +VineDataPathState *vine_get_default_state(vine_data_path_h dp, + vine_dp_plugin_h plugin, vine_dp_plugin_fn fn) { - return new VineDefaultState(dp, plugin); + return new VineDefaultState(dp, plugin, fn); } -void start_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin, +void start_default_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, VineDataPathState *state) { VINE_LOGD("Default"); - state_transition(dp, state, new VineDefaultState(dp, plugin)); + state_transition(dp, state, new VineDefaultState(dp, plugin, fn)); } -void start_connected_state(vine_data_path_h dp, vine_dp_plugin_h plugin, +void start_connected_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, VineDataPathState *state) { VINE_LOGD("Connected"); - state_transition(dp, state, new VineConnectedState(dp, plugin)); + state_transition(dp, state, new VineConnectedState(dp, plugin, fn)); } -void start_accepted_state(vine_data_path_h dp, vine_dp_plugin_h plugin, +void start_accepted_state(vine_data_path_h dp, vine_dp_plugin_h plugin, vine_dp_plugin_fn fn, VineDataPathState *state) { VINE_LOGD("Accepted"); - state_transition(dp, state, new VineAcceptedState(dp, plugin)); + state_transition(dp, state, new VineAcceptedState(dp, plugin, fn)); } diff --git a/src/vine-data-path.cpp b/src/vine-data-path.cpp index 6360779..e2fa7f5 100755 --- a/src/vine-data-path.cpp +++ b/src/vine-data-path.cpp @@ -25,7 +25,34 @@ #include "vine-log.h" #include "vine-utils.h" +static struct { + const char *name; + const char *path; +} __vine_data_path_plugins_info[] = { + [VINE_DATA_PATH_METHOD_LWS] = {"Websocket", LWS_PLUGIN_PATH}, +#ifdef BT_SUPPORT + [VINE_DATA_PATH_METHOD_BLE_GATT] = {"BLE GATT", BLE_GATT_PLUGIN_PATH}, +#endif + {NULL, NULL}, +}; + +struct { + vine_dp_plugin_fn fn; + vine_dp_plugin_callbacks callbacks; + void (*init)(vine_dp_plugin_fn *fn); +} __vine_data_path_plugins[] = { + {{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}, + {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 { + vine_data_path_method_e method; + vine_dp_plugin_fn *plugin_fn; + vine_address_family_e addr_family; char *addr; int port; @@ -68,31 +95,8 @@ typedef struct { vine_data_path_s *connected_dp; } vine_dp_accepted_event; -vine_dp_plugin_fn g_dp_plugin_fn = { - .init = NULL, - .deinit = NULL, - .register_callbacks = NULL, - .process_event = NULL, - .create = NULL, - .destroy = NULL, - .open = NULL, - .connect = NULL, - .read = NULL, - .write = NULL -}; - -static vine_dp_plugin_callbacks g_dp_plugin_cbs = { - .pollfd_cb = NULL, - .opened_cb = NULL, - .accepted_cb = NULL, - .connected_cb = NULL, - .received_cb = NULL, - .written_cb = NULL, - .terminated_cb = NULL, -}; - -static void (*__init_plugin)(vine_dp_plugin_fn *fn); -static vine_data_path_s *_vine_data_path_create(vine_address_family_e addr_family, +static vine_data_path_s *_vine_data_path_create(vine_data_path_method_e method, + vine_address_family_e addr_family, const char *addr, int port, vine_security_h security, void *plugin_data, vine_event_queue_h event_queue); @@ -136,7 +140,10 @@ static vine_error_e __convert_address_family(vine_address_family_e addr_family, void __vine_dp_poll_handler(int fd, int events, void *user_data) { - g_dp_plugin_fn.process_event(fd, events); + // 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); } void __vine_dp_op_handler(int fd, int events, void *user_data) @@ -148,7 +155,10 @@ void __vine_dp_op_handler(int fd, int events, void *user_data) VINE_LOGE("Read error(%d)", errno); return; } - g_dp_plugin_fn.process_event(fd, events); + // 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); } static void __pollfd_cb(vine_data_path_pollfd_op_e op, int fd, int events) @@ -261,8 +271,10 @@ static vine_address_family_e __convert_addr_family(vine_dp_addr_family_e addr_fa return VINE_ADDRESS_FAMILY_IPV4; case VINE_DP_IPV6: return VINE_ADDRESS_FAMILY_IPV6; + case VINE_DP_NOT_IP: + default: + return VINE_ADDRESS_FAMILY_DEFAULT; } - return VINE_ADDRESS_FAMILY_DEFAULT; } static void __accepted_cb(vine_dp_addr_family_e addr_family, char *addr, @@ -273,7 +285,8 @@ static void __accepted_cb(vine_dp_addr_family_e addr_family, char *addr, vine_data_path_s *listen_dp = (vine_data_path_s *)user_data; VINE_LOGE("listen_dp[%p], security[%p]", listen_dp, listen_dp->security); - vine_data_path_s *connected_dp = _vine_data_path_create(__convert_addr_family(addr_family), + vine_data_path_s *connected_dp = _vine_data_path_create(listen_dp->method, + __convert_addr_family(addr_family), addr, port, listen_dp->security, plugin_data, listen_dp->event_queue); RET_IF(connected_dp == NULL, "Out of memory"); @@ -282,7 +295,8 @@ static void __accepted_cb(vine_dp_addr_family_e addr_family, char *addr, VINE_LOGD("Start Authentication"); connected_dp->established = notify_accepted; - start_accepted_state(connected_dp, connected_dp->plugin_handle, connected_dp->state); + start_accepted_state(connected_dp, connected_dp->plugin_handle, *connected_dp->plugin_fn, + connected_dp->state); } static void __invoke_connected_user_cb(void *event, void *user_data) @@ -328,7 +342,7 @@ static void __connected_cb(int result, void *user_data) VINE_LOGD("Start Authentication"); dp->established = notify_connected; - start_connected_state(dp, dp->plugin_handle, dp->state); + start_connected_state(dp, dp->plugin_handle, *dp->plugin_fn, dp->state); } static void __invoke_received_user_cb(void *event, void *user_data) @@ -385,7 +399,7 @@ static void __invoke_terminated_user_cb(void *event, void *user_data) VINE_LOGD("user callback is invoked by event queue."); - start_default_state(dp, dp->plugin_handle, dp->state); + start_default_state(dp, dp->plugin_handle, *dp->plugin_fn, dp->state); if (dp->terminated_cb) dp->terminated_cb(dp, dp->terminated_cb_data); } @@ -400,17 +414,23 @@ static void __terminated_cb(void *user_data) static int _load_data_path_plugins(void) { - void *handle = dlopen(DATA_PATH_PLUGIN_PATH, RTLD_LAZY | RTLD_NODELETE); - if (handle) { - __init_plugin = (void (*)(vine_dp_plugin_fn *))dlsym(handle, "vine_data_path_plugin_init"); - dlclose(handle); - VINE_LOGI("Loaded %s", DATA_PATH_PLUGIN_PATH); - } else { - VINE_LOGE("%s doesn't exist", DATA_PATH_PLUGIN_PATH); - return VINE_ERROR_OPERATION_FAILED; + int loaded = 0; + + for (int i = 0; __vine_data_path_plugins_info[i].path; ++i) { + void *handle = dlopen(__vine_data_path_plugins_info[i].path, RTLD_LAZY | RTLD_NODELETE); + if (handle) { + __vine_data_path_plugins[i].init = + (void (*)(vine_dp_plugin_fn *))dlsym(handle, "vine_data_path_plugin_init"); + dlclose(handle); + ++loaded; + VINE_LOGI("Loaded %s", __vine_data_path_plugins_info[i].path); + } else { + VINE_LOGE("%s doesn't exist", __vine_data_path_plugins_info[i].path); + } } - return VINE_ERROR_NONE; + VINE_LOGI("%d plugins are loaded.", loaded); + return (loaded > 0 ? VINE_ERROR_NONE : VINE_ERROR_OPERATION_FAILED); } int vine_data_path_set_received_cb( @@ -464,15 +484,20 @@ int vine_data_path_close(vine_data_path_h datapath) RET_VAL_IF(datapath == NULL, VINE_ERROR_INVALID_PARAMETER, "datapath is NULL"); vine_data_path_s *dp = (vine_data_path_s *)datapath; - g_dp_plugin_fn.close(dp->plugin_handle); + RET_VAL_IF(!dp->plugin_fn || dp->plugin_fn->close, + VINE_ERROR_INVALID_PARAMETER, "plugin_fn is NULL"); + dp->plugin_fn->close(dp->plugin_handle); return VINE_ERROR_NONE; } -static vine_data_path_s *_vine_data_path_create(vine_address_family_e addr_family, +static vine_data_path_s *_vine_data_path_create(vine_data_path_method_e method, + vine_address_family_e addr_family, const char *addr, int port, vine_security_h security, void *plugin_data, vine_event_queue_h event_queue) { + RET_VAL_IF(method < VINE_DATA_PATH_METHOD_LWS || method >= VINE_DATA_PATH_METHOD_UNKNOWN, + NULL, "Unknown method."); RET_VAL_IF(addr == NULL, NULL, "addr is NULL"); int ret = VINE_ERROR_NONE; @@ -481,6 +506,13 @@ static vine_data_path_s *_vine_data_path_create(vine_address_family_e addr_famil dp = (vine_data_path_s *)calloc(1, sizeof(vine_data_path_s)); RET_VAL_IF(dp == NULL, NULL, "Out of memory"); + dp->method = method; + dp->plugin_fn = &__vine_data_path_plugins[method].fn; + if (!dp->plugin_fn || !dp->plugin_fn->create) { + free(dp); + return NULL; + } + dp->addr_family = addr_family; dp->addr = STRDUP(addr); if (dp->addr == NULL) { @@ -505,7 +537,7 @@ static vine_data_path_s *_vine_data_path_create(vine_address_family_e addr_famil dp->security = NULL; } - ret = g_dp_plugin_fn.create(&dp->plugin_handle, plugin_data, dp); + ret = dp->plugin_fn->create(&dp->plugin_handle, plugin_data, dp); if (ret != VINE_DATA_PATH_ERROR_NONE) { free(dp->addr); _vine_security_destroy(dp->security); @@ -514,8 +546,8 @@ static vine_data_path_s *_vine_data_path_create(vine_address_family_e addr_famil return NULL; } - dp->state = vine_get_default_state(dp, dp->plugin_handle); - VINE_LOGD("datapath[%p] is created.", dp); + dp->state = vine_get_default_state(dp, dp->plugin_handle, *dp->plugin_fn); + VINE_LOGD("datapath[%p] is created. method[%d]", dp, method); return dp; } @@ -524,7 +556,9 @@ int vine_data_path_destroy(vine_data_path_h datapath) RET_VAL_IF(datapath == NULL, VINE_ERROR_INVALID_PARAMETER, "datapath is NULL"); vine_data_path_s *dp = (vine_data_path_s *)datapath; - g_dp_plugin_fn.destroy(dp->plugin_handle); + if (dp->plugin_fn && dp->plugin_fn->destroy) + dp->plugin_fn->destroy(dp->plugin_handle); + dp->plugin_handle = NULL; free(dp->addr); dp->addr = NULL; @@ -582,26 +616,46 @@ static void __data_received(vine_data_path_h dp, size_t bytes) notify_data_received(dp, bytes); } +static int __init_plugins(void) +{ + vine_dp_plugin_callbacks callbacks = { + .pollfd_cb = __pollfd_cb, + .opened_cb = __opened_cb, + .accepted_cb = __accepted_cb, + .connected_cb = __connected_cb, + .received_cb = __received_cb, + .written_cb = __written_cb, + .terminated_cb = __terminated_cb, + }; + + for (int i = 0; __vine_data_path_plugins[i].init; ++i) { + __vine_data_path_plugins[i].init(&__vine_data_path_plugins[i].fn); + if (__vine_data_path_plugins[i].fn.init() != VINE_ERROR_NONE) + continue; + + __vine_data_path_plugins[i].callbacks = callbacks; + __vine_data_path_plugins[i].fn.register_callbacks(__vine_data_path_plugins[i].callbacks); + } + + return VINE_ERROR_NONE; +} + +static void __deinit_plugins(void) +{ + for (int i = 0; __vine_data_path_plugins[i].fn.deinit; ++i) + __vine_data_path_plugins[i].fn.deinit(); +} + int vine_data_path_init(void) { int ret = _load_data_path_plugins(); RET_VAL_IF(ret != VINE_ERROR_NONE, ret, "Fail to load plugins"); - __init_plugin(&g_dp_plugin_fn); - ret = g_dp_plugin_fn.init(); + ret = __init_plugins(); RET_VAL_IF(ret != VINE_DATA_PATH_ERROR_NONE, __convert_data_path_error_to_vine_error((vine_data_path_error)ret), "Filed to init dp-plugin"); - g_dp_plugin_cbs.pollfd_cb = __pollfd_cb; - g_dp_plugin_cbs.opened_cb = __opened_cb; - g_dp_plugin_cbs.accepted_cb = __accepted_cb; - g_dp_plugin_cbs.connected_cb = __connected_cb; - g_dp_plugin_cbs.received_cb = __received_cb; - g_dp_plugin_cbs.written_cb = __written_cb; - g_dp_plugin_cbs.terminated_cb = __terminated_cb; - g_dp_plugin_fn.register_callbacks(g_dp_plugin_cbs); - vine_dp_state_set_state_changed_notifier(__set_state); vine_dp_state_set_established_notifier(__established); vine_dp_state_set_data_received_notifier(__data_received); @@ -610,8 +664,7 @@ int vine_data_path_init(void) int vine_data_path_deinit(void) { - g_dp_plugin_fn.deinit(); - + __deinit_plugins(); return VINE_ERROR_NONE; } @@ -671,7 +724,8 @@ static void _destroy_security_info(vine_dp_ssl *dest) free(dest->key_path); } -int vine_data_path_open(vine_address_family_e addr_family, int port, const char *iface_name, +int vine_data_path_open(vine_data_path_method_e method, + vine_address_family_e addr_family, int port, const char *iface_name, int max_conn, vine_security_h security, const char *host_name, vine_data_path_opened_cb opened_cb, void *opened_cb_data, vine_data_path_accepted_cb accepted_cb, void *accepted_cb_data, @@ -686,8 +740,10 @@ int vine_data_path_open(vine_address_family_e addr_family, int port, const char } vine_data_path_s *dp = - _vine_data_path_create(addr_family, "", port, security, NULL, event_queue); + _vine_data_path_create(method, addr_family, "", port, security, NULL, event_queue); RET_VAL_IF(dp == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory"); + RET_VAL_IF(dp->plugin_fn == NULL, VINE_ERROR_INVALID_PARAMETER, "Invalid parameter"); + RET_VAL_IF(dp->plugin_fn->open == NULL, VINE_ERROR_INVALID_PARAMETER, "Invalid parameter"); vine_dp_ssl ssl = {false, VINE_DP_TLS_VERSION_DEFAULT, 0, NULL, NULL, NULL}; _extract_security_info(security, &ssl); @@ -698,15 +754,15 @@ int vine_data_path_open(vine_address_family_e addr_family, int port, const char dp->accepted_cb_data = accepted_cb_data; // optional - if (host_name) { - ret = g_dp_plugin_fn.set_host_name(dp->plugin_handle, host_name); + if (host_name && dp->plugin_fn->set_host_name) { + ret = dp->plugin_fn->set_host_name(dp->plugin_handle, host_name); if (ret != VINE_DATA_PATH_ERROR_NONE) { vine_data_path_destroy(dp); return __convert_data_path_error_to_vine_error((vine_data_path_error)ret); } } - ret = g_dp_plugin_fn.open(dp->plugin_handle, dp_addr_family, port, iface_name, max_conn, ssl); + ret = dp->plugin_fn->open(dp->plugin_handle, dp_addr_family, port, iface_name, max_conn, ssl); _destroy_security_info(&ssl); if (ret != VINE_DATA_PATH_ERROR_NONE) { @@ -723,15 +779,18 @@ int vine_data_path_open(vine_address_family_e addr_family, int port, const char return VINE_ERROR_NONE; } -int vine_data_path_connect(vine_address_family_e addr_family, +int vine_data_path_connect(vine_data_path_method_e method, + vine_address_family_e addr_family, const char *ip, int port, const char *iface_name, vine_security_h security, const char *host_name, const char *token, vine_data_path_connected_cb callback, void *user_data, vine_data_path_h *connected_datapath, vine_event_queue_h event_queue) { vine_data_path_s *dp = - _vine_data_path_create(addr_family, ip, port, security, NULL, event_queue); + _vine_data_path_create(method, addr_family, ip, port, security, NULL, event_queue); RET_VAL_IF(dp == NULL, VINE_ERROR_OUT_OF_MEMORY, "Out of memory"); + RET_VAL_IF(dp->plugin_fn == NULL, VINE_ERROR_INVALID_PARAMETER, "Invalid parameter"); + RET_VAL_IF(dp->plugin_fn->connect == NULL, VINE_ERROR_INVALID_PARAMETER, "Invalid parameter"); RET_VAL_IF(connected_datapath == NULL, VINE_ERROR_INVALID_PARAMETER, "connected_datapath is NULL"); @@ -744,16 +803,16 @@ int vine_data_path_connect(vine_address_family_e addr_family, int ret; // optional - if (host_name) { - ret = g_dp_plugin_fn.set_host_name(dp->plugin_handle, host_name); + if (host_name && dp->plugin_fn->set_host_name) { + ret = dp->plugin_fn->set_host_name(dp->plugin_handle, host_name); if (ret != VINE_DATA_PATH_ERROR_NONE) { vine_data_path_destroy(dp); return __convert_data_path_error_to_vine_error((vine_data_path_error)ret); } } - if (token) { - ret = g_dp_plugin_fn.set_token(dp->plugin_handle, token); + if (token && dp->plugin_fn->set_token) { + ret = dp->plugin_fn->set_token(dp->plugin_handle, token); if (ret != VINE_DATA_PATH_ERROR_NONE) { vine_data_path_destroy(dp); _destroy_security_info(&ssl); @@ -761,7 +820,7 @@ int vine_data_path_connect(vine_address_family_e addr_family, } } - ret = g_dp_plugin_fn.connect(dp->plugin_handle, + ret = dp->plugin_fn->connect(dp->plugin_handle, addr_family == VINE_ADDRESS_FAMILY_IPV4 ? VINE_DP_IPV4 : VINE_DP_IPV6, ip, port, iface_name, ssl); _destroy_security_info(&ssl); @@ -795,7 +854,10 @@ int vine_data_path_get_token(vine_data_path_h datapath, char **token) RET_VAL_IF(token == NULL, VINE_ERROR_INVALID_PARAMETER, "token is NULL"); vine_data_path_s *dp = (vine_data_path_s *)datapath; - int ret = g_dp_plugin_fn.get_token(dp->plugin_handle, token); + if (!dp->plugin_fn || !dp->plugin_fn->get_token) + return VINE_ERROR_INVALID_PARAMETER; + + int ret = dp->plugin_fn->get_token(dp->plugin_handle, token); return __convert_data_path_error_to_vine_error((vine_data_path_error)ret); } @@ -816,10 +878,13 @@ int vine_data_path_get_local_address_info(vine_data_path_h datapath, int *addres RET_VAL_IF(port == NULL, VINE_ERROR_INVALID_PARAMETER, "port is NULL"); vine_data_path_s *dp = (vine_data_path_s *)datapath; + RET_VAL_IF(!dp->plugin_fn || !dp->plugin_fn->get_local_address_info, + VINE_ERROR_INVALID_PARAMETER, "plugin_fn is NULL"); + vine_error_e error; int addr_family, local_port; char local_ip[VINE_MAX_IP_LEN + 1] = {0, }; - int ret = g_dp_plugin_fn.get_local_address_info(dp->plugin_handle, + int ret = dp->plugin_fn->get_local_address_info(dp->plugin_handle, &addr_family, local_ip, &local_port); error = __convert_data_path_error_to_vine_error((vine_data_path_error)ret); diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index 29a640f..5fb28ca 100644 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -449,6 +449,7 @@ void DataPath::invoke_terminated_cb() DPServer::DPServer(void *event_queue) { VINE_LOGD("DPServer[%p] is created.", this); + mMethod = VINE_DATA_PATH_METHOD_LWS; mEventQueue = event_queue; mSecurity = NULL; mAddrFamily = VINE_ADDRESS_FAMILY_DEFAULT; @@ -474,6 +475,24 @@ DPServer::~DPServer() vine_data_path_destroy(mDataPath); } +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; + break; + case VINE_DP_METHOD_BLE_GATT: + mMethod = VINE_DATA_PATH_METHOD_BLE_GATT; + break; + default: + mMethod = VINE_DATA_PATH_METHOD_LWS; + } + return VINE_ERROR_NONE; +} + int DPServer::get_id(char **id) { return VINE_ERROR_INVALID_OPERATION; @@ -599,7 +618,8 @@ int DPServer::open(vine_dp_opened_cb callback, void *user_data) mOpenedCbData = user_data; mOpenState = VINE_DP_OPEN_STATE_WAIT; - int ret = vine_data_path_open(mAddrFamily, mListenPort, + int ret = vine_data_path_open(mMethod, + mAddrFamily, mListenPort, mIfaceName.size() > 0 ? mIfaceName.c_str() : NULL, mMaxConnNum, mSecurity, NULL, _opened_cb, static_cast(this), @@ -630,6 +650,7 @@ int DPServer::recv(unsigned char *buf, size_t buf_len, size_t *read_len) DPClient::DPClient(void *event_queue) { VINE_LOGD("DPClient[%p] is created.", this); + mMethod = VINE_DATA_PATH_METHOD_LWS; mEventQueue = event_queue; mSecurity = NULL; mAddrFamily = VINE_ADDRESS_FAMILY_DEFAULT; @@ -676,6 +697,24 @@ DPClient::~DPClient() vine_data_path_destroy(mDataPath); } +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; + break; + case VINE_DP_METHOD_BLE_GATT: + mMethod = VINE_DATA_PATH_METHOD_BLE_GATT; + break; + default: + mMethod = VINE_DATA_PATH_METHOD_LWS; + } + return VINE_ERROR_NONE; +} + int DPClient::get_id(char **id) { return VINE_ERROR_INVALID_OPERATION; @@ -789,7 +828,8 @@ int DPClient::open(vine_dp_opened_cb callback, void *user_data) mOpenedCbData = user_data; mOpenState = VINE_DP_OPEN_STATE_WAIT; - int ret = vine_data_path_connect(mAddrFamily, mPeerIp.c_str(), mPeerPort, + int ret = vine_data_path_connect(mMethod, + mAddrFamily, mPeerIp.c_str(), mPeerPort, mIfaceName.size() > 0 ? mIfaceName.c_str() : NULL, mSecurity, NULL, NULL, _connected_cb, static_cast(this), &mDataPath, mEventQueue); @@ -817,6 +857,7 @@ int DPClient::recv(unsigned char *buf, size_t buf_len, size_t *read_len) DPPubSub::DPPubSub(void *event_queue) { VINE_LOGD("DPPubSub[%p] is created.", this); + mMethod = VINE_DATA_PATH_METHOD_LWS; mEventQueue = event_queue; mSecurity = NULL; mIfaceName = ""; @@ -853,6 +894,18 @@ DPPubSub::~DPPubSub() close(); } +int DPPubSub::set_method(vine_dp_method_e method) +{ + if (method < VINE_DP_METHOD_DEFAULT || method >= VINE_DP_METHOD_UNKNOWN) + return VINE_ERROR_INVALID_PARAMETER; + + if (method == VINE_DP_METHOD_BLE_GATT) + return VINE_ERROR_INVALID_OPERATION; + + mMethod = VINE_DATA_PATH_METHOD_LWS; + return VINE_ERROR_NONE; +} + void DPPubSub::set_id(const char *id) { if (id == NULL || mId.compare(id) == 0) @@ -1003,7 +1056,8 @@ int DPPubSub::connect(const char *service_name, const char *ip, int port) conn_data->dp = static_cast(this); conn_data->service_name = STRDUP(service_name); - int ret = vine_data_path_connect(mAddrFamily, ip, port, iface_name, + int ret = vine_data_path_connect(mMethod, + mAddrFamily, ip, port, iface_name, mSecurity, service_name, mId.c_str(), _pubsub_connected_cb, (void *)conn_data, &datapath, mEventQueue); @@ -1113,7 +1167,8 @@ int DPPubSub::open(vine_dp_opened_cb callback, void *user_data) create_id(service_name); set_id(service_name); - int ret = vine_data_path_open(mAddrFamily, mListenPort, + int ret = vine_data_path_open(mMethod, + mAddrFamily, mListenPort, mIfaceName.size() > 0 ? mIfaceName.c_str() : NULL, mMaxConnNum, mSecurity, mId.c_str(), _pubsub_opened_cb, static_cast(this), @@ -1361,7 +1416,8 @@ int _vine_dp_create(vine_session_h session, vine_dp_type_e type, vine_dp_h *dp) vine_event_queue_h eq = NULL; int ret = _vine_session_get_event_queue(session, &eq); - if (ret != VINE_ERROR_NONE || !eq) + // eq can be NULL if glib is used as the eventloop. + if (ret != VINE_ERROR_NONE) return VINE_ERROR_INVALID_PARAMETER; if (type == VINE_DP_TYPE_SERVER) { @@ -1385,6 +1441,14 @@ int _vine_dp_destroy(vine_dp_h dp) return VINE_ERROR_NONE; } +int _vine_dp_set_method(vine_dp_h dp, vine_dp_method_e method) +{ + RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); + + DataPath *_dp = static_cast(dp); + return _dp->set_method(method);; +} + int _vine_dp_get_id(vine_dp_h dp, char **id) { RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); diff --git a/src/vine.cpp b/src/vine.cpp index 6c2d95e..2931ecb 100755 --- a/src/vine.cpp +++ b/src/vine.cpp @@ -350,6 +350,14 @@ API int vine_dp_destroy(vine_dp_h dp) return _vine_dp_destroy(dp); } +API int vine_dp_set_method(vine_dp_h dp, vine_dp_method_e method) +{ + __VINE_FUNC_ENTER__; + CHECK_FEATURE_SUPPORTED; + + return _vine_dp_set_method(dp, method); +} + API int vine_dp_get_id(vine_dp_h dp, char **id) { __VINE_FUNC_ENTER__; diff --git a/tests/unittest/vine-unittest-dp.cpp b/tests/unittest/vine-unittest-dp.cpp index 26fcfac..a6daf59 100755 --- a/tests/unittest/vine-unittest-dp.cpp +++ b/tests/unittest/vine-unittest-dp.cpp @@ -110,6 +110,20 @@ TEST_F(VineDpTest, DestroyP) vine_dp_destroy(dp)); } +TEST_F(VineDpTest, SetMethodN) +{ + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_set_method(server_dp, VINE_DP_METHOD_UNKNOWN)); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_set_method(client_dp, VINE_DP_METHOD_UNKNOWN)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_set_method(pubsub_dp, VINE_DP_METHOD_BLE_GATT)); +} + +TEST_F(VineDpTest, SetMethodP) +{ + EXPECT_EQ(VINE_ERROR_NONE, vine_dp_set_method(server_dp, VINE_DP_METHOD_BLE_GATT)); + EXPECT_EQ(VINE_ERROR_NONE, vine_dp_set_method(client_dp, VINE_DP_METHOD_BLE_GATT)); + EXPECT_EQ(VINE_ERROR_NONE, vine_dp_set_method(pubsub_dp, VINE_DP_METHOD_DEFAULT)); +} + TEST_F(VineDpTest, GetIdN) { char *id = NULL; diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index 6c8445a..9bfd677 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -554,6 +554,9 @@ static void _set_dp_info(vine_dp_type_e type) vine_dp_set_address_family(vine_configs.dp, addr_family); vine_dp_set_max_connections(vine_configs.dp, tool_config_get_max_conn()); + if (vine_configs.with_ble) + vine_dp_set_method(vine_configs.dp, VINE_DP_METHOD_BLE_GATT); + if (type == VINE_DP_TYPE_CLIENT) { vine_dp_set_remote_port(vine_configs.dp, tool_config_get_port()); vine_dp_set_remote_ip(vine_configs.dp, addr_family, -- 2.7.4 From 7f88964069bf91904a0c074d71515917cad1c353 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Wed, 7 Jul 2021 18:45:58 +0900 Subject: [PATCH 09/16] Add new API to set/get remote address(GATT) Change-Id: I2e6523b01af33aa7d7bfd99a4f7720f484adb4ab --- include/vine.h | 30 ++++++++++++++++++ plugins/ble-gatt/ble-gatt-plugin.cpp | 15 +++++++++ src/include/vine-dp.h | 11 +++++++ src/vine-dp.cpp | 60 +++++++++++++++++++++++++++++++++++- src/vine.cpp | 16 ++++++++++ tests/unittest/vine-unittest-dp.cpp | 25 +++++++++++++++ tool/tool_run.cpp | 4 ++- 7 files changed, 159 insertions(+), 2 deletions(-) diff --git a/include/vine.h b/include/vine.h index c9a663f..0931fd1 100755 --- a/include/vine.h +++ b/include/vine.h @@ -921,6 +921,36 @@ int vine_dp_get_id(vine_dp_h dp, char **id); int vine_dp_set_iface_name(vine_dp_h dp, const char *iface_or_ip); /** + * @brief Sets the remote address. + * @remarks This is used with VINE_DP_METHOD_BLE_GATT. + * @since_tizen 6.5 + * @param[in] dp The data path handle + * @param[in] address The remote address + * @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() + */ +int vine_dp_set_remote_address(vine_dp_h dp, const char *address); + +/** + * @brief Gets the remote address. + * @remarks This is used with VINE_DP_METHOD_BLE_GATT. + * @since_tizen 6.5 + * @param[in] dp The data path handle + * @param[out] address The remote address + * @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() + */ +int vine_dp_get_remote_address(vine_dp_h dp, char **address); + +/** * @brief Sets the address family. * @remarks This is ignored when dp type is VINE_DP_TYPE_CLIENT. * @since_tizen 6.5 diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index dccb252..c8a3292 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -28,6 +28,8 @@ using namespace std; #define VINE_GATT_CHAR_UUID "00002af6-0000-1000-8000-00805f9b34fb" #define VINE_GATT_DESC_UUID "fa87c0d0-afac-11de-8a39-0800200c9a66" +#define BT_ADDRESS_LEN 17 + typedef enum { VINE_GATT_ROLE_UNKNOWN = 0, VINE_GATT_ROLE_SERVER, @@ -399,6 +401,9 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, gatt->descriptor = descriptor; VINE_LOGI("Succeeded to start GATT server."); + + //if (g_callbacks.opened_cb) + // g_callbacks.opened_cb(VINE_DATA_PATH_ERROR_NONE, -1, gatt->user); return VINE_DATA_PATH_ERROR_NONE; ERR: @@ -463,6 +468,16 @@ int gatt_close(vine_dp_plugin_h handle) int gatt_get_local_address_info(vine_dp_plugin_h handle, int *addr_family, char local_ip[], int *port) { + char *addr = NULL; + int ret = bt_adapter_get_address(&addr); + if (ret != BT_ERROR_NONE) { + VINE_LOGE("Failed to get local address."); + free(addr); + return __convert_bt_error_to_data_path_error(ret); + } + + strncpy(local_ip, addr, BT_ADDRESS_LEN); + free(addr); return VINE_DATA_PATH_ERROR_NONE; } diff --git a/src/include/vine-dp.h b/src/include/vine-dp.h index 498aefd..b389085 100644 --- a/src/include/vine-dp.h +++ b/src/include/vine-dp.h @@ -49,6 +49,8 @@ public: virtual int set_method(vine_dp_method_e method) = 0; virtual int get_id(char **id) = 0; + virtual int set_remote_address(const char *address) = 0; + virtual int get_remote_address(char **address) = 0; virtual int set_addr_family(vine_address_family_e addr_family) = 0; virtual int set_remote_ip(vine_address_family_e, const std::string &ip) = 0; virtual int get_remote_ip(vine_address_family_e *addr_family, char **ip) = 0; @@ -110,6 +112,8 @@ public: virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); + virtual int set_remote_address(const char *address); + virtual int get_remote_address(char **address); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); virtual int get_remote_ip(vine_address_family_e *addr_family, char **ip); @@ -155,6 +159,8 @@ public: virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); + virtual int set_remote_address(const char *address); + virtual int get_remote_address(char **address); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); virtual int get_remote_ip(vine_address_family_e *addr_family, char **ip); @@ -175,6 +181,7 @@ public: private: vine_data_path_h mDataPath; + std::string mPeerAddr; vine_address_family_e mAddrFamily; std::string mPeerIp; int mPeerPort; @@ -210,6 +217,8 @@ public: virtual int set_method(vine_dp_method_e method); virtual int get_id(char **id); + virtual int set_remote_address(const char *address); + virtual int get_remote_address(char **address); virtual int set_addr_family(vine_address_family_e addr_family); virtual int set_remote_ip(vine_address_family_e, const std::string &ip); virtual int get_remote_ip(vine_address_family_e *addr_family, char **ip); @@ -285,6 +294,8 @@ int _vine_dp_create(vine_session_h session, vine_dp_type_e type, vine_dp_h *dp); int _vine_dp_destroy(vine_dp_h dp); int _vine_dp_set_method(vine_dp_h dp, vine_dp_method_e method); int _vine_dp_get_id(vine_dp_h dp, char **id); +int _vine_dp_set_remote_address(vine_dp_h dp, const char *address); +int _vine_dp_get_remote_address(vine_dp_h dp, char **address); int _vine_dp_set_iface_name(vine_dp_h dp, const char *iface_name); int _vine_dp_set_addr_family(vine_dp_h dp, vine_address_family_e addr_family); int _vine_dp_set_remote_ip(vine_dp_h dp, vine_address_family_e addr_family, const char *ip); diff --git a/src/vine-dp.cpp b/src/vine-dp.cpp index 5fb28ca..6ab8e65 100644 --- a/src/vine-dp.cpp +++ b/src/vine-dp.cpp @@ -498,6 +498,16 @@ int DPServer::get_id(char **id) return VINE_ERROR_INVALID_OPERATION; } +int DPServer::set_remote_address(const char *address) +{ + return VINE_ERROR_INVALID_OPERATION; +} + +int DPServer::get_remote_address(char **address) +{ + return VINE_ERROR_INVALID_OPERATION; +} + int DPServer::set_addr_family(vine_address_family_e addr_family) { mAddrFamily = addr_family; @@ -720,6 +730,24 @@ int DPClient::get_id(char **id) return VINE_ERROR_INVALID_OPERATION; } +int DPClient::set_remote_address(const char *address) +{ + RET_VAL_IF(isCreatedByServerDp, VINE_ERROR_INVALID_OPERATION, "cannot set remote address"); + RET_VAL_IF(mMethod == VINE_DATA_PATH_METHOD_LWS, VINE_ERROR_INVALID_OPERATION, + "cannot set remote address"); + + mPeerAddr = address; + return VINE_ERROR_NONE; +} + +int DPClient::get_remote_address(char **address) +{ + if (mPeerAddr.size() == 0) + return VINE_ERROR_OPERATION_FAILED; + *address = STRDUP(mPeerAddr.c_str()); + return VINE_ERROR_NONE; +} + int DPClient::set_addr_family(vine_address_family_e addr_family) { return VINE_ERROR_INVALID_OPERATION; @@ -829,7 +857,9 @@ int DPClient::open(vine_dp_opened_cb callback, void *user_data) mOpenState = VINE_DP_OPEN_STATE_WAIT; int ret = vine_data_path_connect(mMethod, - mAddrFamily, mPeerIp.c_str(), mPeerPort, + mAddrFamily, + mMethod == VINE_DATA_PATH_METHOD_BLE_GATT ? mPeerAddr.c_str() : mPeerIp.c_str(), + mPeerPort, mIfaceName.size() > 0 ? mIfaceName.c_str() : NULL, mSecurity, NULL, NULL, _connected_cb, static_cast(this), &mDataPath, mEventQueue); @@ -921,6 +951,16 @@ int DPPubSub::get_id(char **id) return VINE_ERROR_NONE; } +int DPPubSub::set_remote_address(const char *address) +{ + return VINE_ERROR_INVALID_OPERATION; +} + +int DPPubSub::get_remote_address(char **address) +{ + return VINE_ERROR_INVALID_OPERATION; +} + int DPPubSub::set_addr_family(vine_address_family_e addr_family) { mAddrFamily = addr_family; @@ -1458,6 +1498,24 @@ int _vine_dp_get_id(vine_dp_h dp, char **id) return _dp->get_id(id); } +int _vine_dp_set_remote_address(vine_dp_h dp, const char *address) +{ + RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); + RET_VAL_IF(address == NULL, VINE_ERROR_INVALID_PARAMETER, "address is null."); + + DataPath *_dp = static_cast(dp); + return _dp->set_remote_address(address); +} + +int _vine_dp_get_remote_address(vine_dp_h dp, char **address) +{ + RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); + RET_VAL_IF(address == NULL, VINE_ERROR_INVALID_PARAMETER, "address is null."); + + DataPath *_dp = static_cast(dp); + return _dp->get_remote_address(address); +} + int _vine_dp_set_iface_name(vine_dp_h dp, const char *iface_name) { RET_VAL_IF(dp == NULL, VINE_ERROR_INVALID_PARAMETER, "dp is null."); diff --git a/src/vine.cpp b/src/vine.cpp index 2931ecb..8290152 100755 --- a/src/vine.cpp +++ b/src/vine.cpp @@ -366,6 +366,22 @@ API int vine_dp_get_id(vine_dp_h dp, char **id) return _vine_dp_get_id(dp, id); } +API int vine_dp_set_remote_address(vine_dp_h dp, const char *address) +{ + __VINE_FUNC_ENTER__; + CHECK_FEATURE_SUPPORTED; + + return _vine_dp_set_remote_address(dp, address); +} + +API int vine_dp_get_remote_address(vine_dp_h dp, char **address) +{ + __VINE_FUNC_ENTER__; + CHECK_FEATURE_SUPPORTED; + + return _vine_dp_get_remote_address(dp, address); +} + API int vine_dp_set_iface_name(vine_dp_h dp, const char *iface_name) { __VINE_FUNC_ENTER__; diff --git a/tests/unittest/vine-unittest-dp.cpp b/tests/unittest/vine-unittest-dp.cpp index a6daf59..8dd6838 100755 --- a/tests/unittest/vine-unittest-dp.cpp +++ b/tests/unittest/vine-unittest-dp.cpp @@ -20,6 +20,7 @@ #include "mocks/vine-mock-memory.h" +#define TEST_MAC "ab:cd:ef:ab:cd:ef" #define TEST_IP "192.168.1.123" class VineDpTest : public ::testing::Test { @@ -138,6 +139,30 @@ TEST_F(VineDpTest, GetIdP) EXPECT_EQ(VINE_ERROR_NONE, vine_dp_get_id(pubsub_dp, &id)); } +TEST_F(VineDpTest, SetRemoteAddressN) +{ + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_set_remote_address(client_dp, NULL)); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_set_remote_address(NULL, TEST_MAC)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_set_remote_address(client_dp, TEST_MAC)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_set_remote_address(server_dp, TEST_MAC)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_set_remote_address(pubsub_dp, TEST_MAC)); +} + +TEST_F(VineDpTest, SetRemoteAddressP) +{ + vine_dp_set_method(client_dp, VINE_DP_METHOD_BLE_GATT); + EXPECT_EQ(VINE_ERROR_NONE, vine_dp_set_remote_address(client_dp, TEST_MAC)); +} + +TEST_F(VineDpTest, GetRemoteAddressP) +{ + char *addr; + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_get_remote_address(client_dp, NULL)); + EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, vine_dp_get_remote_address(NULL, &addr)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_get_remote_address(server_dp, &addr)); + EXPECT_EQ(VINE_ERROR_INVALID_OPERATION, vine_dp_get_remote_address(pubsub_dp, &addr)); +} + TEST_F(VineDpTest, SetRemoteIpN) { EXPECT_EQ(VINE_ERROR_INVALID_PARAMETER, diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index 9bfd677..d5e7e84 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -554,8 +554,10 @@ static void _set_dp_info(vine_dp_type_e type) vine_dp_set_address_family(vine_configs.dp, addr_family); vine_dp_set_max_connections(vine_configs.dp, tool_config_get_max_conn()); - if (vine_configs.with_ble) + if (vine_configs.with_ble) { vine_dp_set_method(vine_configs.dp, VINE_DP_METHOD_BLE_GATT); + vine_dp_set_remote_address(vine_configs.dp, tool_config_get_remote_address()); + } if (type == VINE_DP_TYPE_CLIENT) { vine_dp_set_remote_port(vine_configs.dp, tool_config_get_port()); -- 2.7.4 From f5c94753e4180d6f4ef473492b9aa66ee122a368 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Thu, 8 Jul 2021 17:47:04 +0900 Subject: [PATCH 10/16] Implement read/write for BLE GATT Change-Id: Id018c74de7bac482d3d9bd59fca6ab61598a9cb2 --- plugins/ble-gatt/ble-gatt-plugin.cpp | 211 +++++++++++++++++++++++++++++++++-- src/include/vine-data-path-state.h | 2 +- src/vine-data-path.cpp | 2 +- 3 files changed, 206 insertions(+), 9 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index c8a3292..e428706 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -20,6 +20,7 @@ #include "vine-data-path-plugin.h" #include "vine-log.h" #include "vine-utils.h" +#include "vine-queue.h" using namespace std; @@ -37,6 +38,13 @@ typedef enum { } vine_gatt_role_e; typedef struct { + char *buf; + size_t len; + //size_t accumulating; + bool last; // true, single message or last fragment of a message. +} gatt_data_s; + +typedef struct { bt_gatt_h service; bt_gatt_h characteristic; bt_gatt_h descriptor; @@ -47,7 +55,9 @@ typedef struct { bt_gatt_client_h client; } role; - char *remote_address; + VineQueue *recv_buffer; + + char *remote_address; // this is used for VINE_GATT_ROLE_CLIENT only. bool is_accepted; void *user; // vine_data_path_h } vine_gatt_s; @@ -79,6 +89,34 @@ 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) +{ + gatt_data_s *gd = (gatt_data_s *)calloc(1, sizeof(gatt_data_s)); + RET_VAL_IF(!gd, NULL, "Out of memory."); + + char *data = (char *)calloc(len, sizeof(char)); + if (!data) { + VINE_LOGE("Out of memory."); + free(gd); + return NULL; + } + + memcpy(data, buf, len); + gd->buf = data; + gd->len = len; + gd->last = last; + return gd; +} + +static void __destroy_gatt_data(gatt_data_s *data) +{ + RET_IF(!data, "data is NULL"); + + if (data->buf) + free(data->buf); + free(data); +} + static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data) { if (!g_callbacks.accepted_cb) @@ -87,6 +125,7 @@ static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, vine_gatt_s *accepted_gatt = _create_gatt(); RET_IF(accepted_gatt == NULL, "Failed to create accepted_gatt."); + accepted_gatt->type = VINE_GATT_ROLE_CLIENT; accepted_gatt->remote_address = STRDUP(remote_address); // refer to server's gatt handles. @@ -121,6 +160,8 @@ static void __gatt_server_read_value_requested_cb( int offset, void *user_data) { // TODO: Send response. + // TODO: Save data + // Is this function needed for VINE? } static void __gatt_server_write_value_requested_cb(const char *remote_address, @@ -128,9 +169,27 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, 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 value requestment from %s.", remote_address); - // TODO: Send response. + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + + // TODO: Need to handle splited data using offset. + gatt_data_s *recv_data = __create_gatt_data(value, len, true); + RET_IF(recv_data == NULL, "recv_data is NULL"); + + gatt->recv_buffer->push(recv_data); + + VINE_LOGI("Write value requested. offset[%d] len[%d] reponse_needed[%d]", + offset, len, response_needed); + + if (bt_gatt_server_send_response(request_id, + BT_GATT_REQUEST_TYPE_WRITE, offset, BT_ERROR_NONE, NULL, 0) < 0) + VINE_LOGE("bt_gatt_server_send_response() is failed."); + + if (g_callbacks.received_cb) + g_callbacks.received_cb(len, gatt->user); } void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, @@ -139,6 +198,20 @@ void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, VINE_LOGI("Noti state changed. notify[%d] characteristic[%p]", notify, gatt_handle); } +void __gatt_server_noti_sent_cb(int result, + const char *remote_address, bt_gatt_server_h server, bt_gatt_h characteristic, + bool completed, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + RET_IF(g_callbacks.written_cb == NULL, "written_cb() is NULL"); + + 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; + g_callbacks.written_cb(1, gatt->user); // bytes will be ignored. +} + // Client Callbacks 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) @@ -147,6 +220,33 @@ static void __gatt_client_service_changed_cb(bt_gatt_client_h client, type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." ); } +void __gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *user_data) +{ + RET_IF(user_data == NULL, "user_data is NULL"); + RET_IF(g_callbacks.written_cb == NULL, "written_cb() is NULL"); + + VINE_LOGI("gatt[%p] completed to send data. result[%d]", gatt_handle, result); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + g_callbacks.written_cb(1, gatt->user); // bytes will be ignored. +} + +void __gatt_client_characteristic_value_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; + gatt_data_s *recv_data = __create_gatt_data(value, len, true); + RET_IF(recv_data == NULL, "recv_data is NULL"); + + gatt->recv_buffer->push(recv_data); + + 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"); @@ -174,6 +274,11 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g if (ret != BT_ERROR_NONE) goto ERR; + ret = bt_gatt_client_set_characteristic_value_changed_cb(characteristic, + __gatt_client_characteristic_value_changed_cb, gatt); + if (ret != BT_ERROR_NONE) + goto ERR; + gatt->role.client = client; gatt->service = service; gatt->characteristic = characteristic; @@ -224,6 +329,8 @@ static vine_gatt_s *_create_gatt(void) free(gatt); return NULL; } + + gatt->recv_buffer = new VineQueue; return gatt; } @@ -281,6 +388,38 @@ 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) +{ + int ret = bt_gatt_set_value(gatt->characteristic, (const char *)buf, 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); + RET_VAL_IF(ret != BT_ERROR_NONE, __convert_bt_error_to_data_path_error(ret), + "bt_gatt_client_write_value() failed."); + + VINE_LOGI("Succeed to send data to server"); + + return VINE_DATA_PATH_ERROR_NONE; +} + +static int _gatt_write_to_client(vine_gatt_s *gatt, unsigned char *buf, size_t len) +{ + int ret = bt_gatt_set_value(gatt->characteristic, (const char *)buf, 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); + 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"); + + return VINE_DATA_PATH_ERROR_NONE; +} + int gatt_init(void) { return VINE_DATA_PATH_ERROR_NONE; @@ -305,7 +444,7 @@ 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"); - vine_gatt_s *gatt = _create_gatt(); + 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"); gatt->user = user; @@ -402,6 +541,7 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, VINE_LOGI("Succeeded to start GATT server."); + // TODO //if (g_callbacks.opened_cb) // g_callbacks.opened_cb(VINE_DATA_PATH_ERROR_NONE, -1, gatt->user); return VINE_DATA_PATH_ERROR_NONE; @@ -445,7 +585,50 @@ int gatt_connect(vine_dp_plugin_h handle, int addr_family, int gatt_read(vine_dp_plugin_h handle, unsigned char *buf, size_t len) { - return VINE_DATA_PATH_ERROR_NONE; + RET_VAL_IF(handle == NULL, 0, "plugin handle is NULL"); + RET_VAL_IF(buf == NULL, 0, "buf is NULL"); + RET_VAL_IF(len == 0, 0, "len is 0"); + + vine_gatt_s *gatt = (vine_gatt_s *)handle; + gatt_data_s *gd = NULL; + size_t bytes = 0; + + if (!gatt->recv_buffer) + return bytes; + + unsigned char *ptr = buf; + size_t read_len = 0; + while (!gatt->recv_buffer->empty() && len > 0) { + gd = gatt->recv_buffer->front(); + if (gd == nullptr) { + gatt->recv_buffer->pop(); + return bytes; + } + + ptr += read_len; + read_len = gd->len > len ? len : gd->len; + memcpy(ptr, gd->buf, read_len); + len -= read_len; + bytes += read_len; + + if (read_len >= gd->len) { + gatt->recv_buffer->pop(); + bool last = gd->last; + __destroy_gatt_data(gd); + gd = NULL; + if (last) + break; + } else if (read_len < gd->len) { // requeue + size_t remained_len = gd->len - read_len; + char *remained_data = (char *)calloc(remained_len, sizeof(char)); + memcpy(remained_data, gd->buf + read_len, remained_len); + free(gd->buf); + gd->buf = remained_data; + gd->len = remained_len; + return bytes; + } + } + return bytes; } int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len) @@ -454,10 +637,24 @@ int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len) 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"); - // TODO - // vine_gatt_s *gatt = (vine_gatt_s *)handle; + vine_gatt_s *gatt = (vine_gatt_s *)handle; + int ret; - return VINE_DATA_PATH_ERROR_NONE; + switch (gatt->type) { + case VINE_GATT_ROLE_SERVER: + ret =_gatt_write_to_client(gatt, buf, len); + break; + case VINE_GATT_ROLE_CLIENT: + ret = gatt->is_accepted ? _gatt_write_to_client(gatt, buf, len) + : _gatt_write_to_server(gatt, buf, len); + break; + case VINE_GATT_ROLE_UNKNOWN: + default: + ret = VINE_DATA_PATH_ERROR_INVALID_OPERATION; + break; + } + + return ret; } int gatt_close(vine_dp_plugin_h handle) diff --git a/src/include/vine-data-path-state.h b/src/include/vine-data-path-state.h index 7ac17ba..c20b1a5 100644 --- a/src/include/vine-data-path-state.h +++ b/src/include/vine-data-path-state.h @@ -27,7 +27,7 @@ // It will be removed when vine-data-path-state is changed. typedef void *vine_data_path_h; -#define AUTH_CONNECTED_TIMEOUT_MS 5000 +#define AUTH_CONNECTED_TIMEOUT_MS 15000 #define AUTH_REQUEST_TIMEOUT_MS 5000 #define AUTH_RESPONSE_TIMEOUT_MS 5000 diff --git a/src/vine-data-path.cpp b/src/vine-data-path.cpp index e2fa7f5..c0aac6e 100755 --- a/src/vine-data-path.cpp +++ b/src/vine-data-path.cpp @@ -284,7 +284,7 @@ static void __accepted_cb(vine_dp_addr_family_e addr_family, char *addr, vine_data_path_s *listen_dp = (vine_data_path_s *)user_data; - VINE_LOGE("listen_dp[%p], security[%p]", listen_dp, listen_dp->security); + VINE_LOGI("listen_dp[%p], security[%p]", listen_dp, listen_dp->security); vine_data_path_s *connected_dp = _vine_data_path_create(listen_dp->method, __convert_addr_family(addr_family), addr, port, listen_dp->security, plugin_data, listen_dp->event_queue); -- 2.7.4 From 165d2cc9a8c4f0e991cdf8bb06b2a15335f03c6f Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Fri, 9 Jul 2021 15:10:24 +0900 Subject: [PATCH 11/16] Keep client list in GATT server handle BT GATT server api doens't create a new handle each connection. But DataPath is designed that new handle is created whenever connected with a peer. In this patch, to compatibility, GATT server will manage a client list. Change-Id: Ica3971031ae2e348ad1726057336de830b0ced0b --- plugins/ble-gatt/ble-gatt-plugin.cpp | 191 ++++++++++++++++++++++++++++------- 1 file changed, 152 insertions(+), 39 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index e428706..45a1793 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -16,6 +16,7 @@ */ #include +#include #include "vine-data-path-plugin.h" #include "vine-log.h" @@ -37,6 +38,8 @@ typedef enum { VINE_GATT_ROLE_CLIENT, } vine_gatt_role_e; +typedef struct vine_gatt_s vine_gatt_s; + typedef struct { char *buf; size_t len; @@ -45,22 +48,30 @@ typedef struct { } gatt_data_s; typedef struct { + bt_gatt_server_h server; + std::map *client_list; +} gatt_server_s; + +typedef struct { + bt_gatt_client_h client; + bool is_accepted; +} gatt_client_s; + +struct vine_gatt_s { bt_gatt_h service; bt_gatt_h characteristic; bt_gatt_h descriptor; vine_gatt_role_e type; union { - bt_gatt_server_h server; - bt_gatt_client_h client; + gatt_server_s *server; + gatt_client_s *client; } role; VineQueue *recv_buffer; - - char *remote_address; // this is used for VINE_GATT_ROLE_CLIENT only. - bool is_accepted; + char *remote_address; void *user; // vine_data_path_h -} vine_gatt_s; +}; static vine_dp_plugin_callbacks g_callbacks = { .pollfd_cb = NULL, @@ -117,26 +128,64 @@ static void __destroy_gatt_data(gatt_data_s *data) free(data); } -static void __invoke_accepted_cb(const char *remote_address, vine_gatt_s *gatt, void *user_data) +static gatt_server_s *_create_gatt_server(bt_gatt_server_h gatt_server) { - if (!g_callbacks.accepted_cb) - return; + RET_VAL_IF(gatt_server == NULL, NULL, "Invalid parameter."); - vine_gatt_s *accepted_gatt = _create_gatt(); - RET_IF(accepted_gatt == NULL, "Failed to create accepted_gatt."); + gatt_server_s *server = (gatt_server_s *)calloc(1, sizeof(gatt_server_s)); + RET_VAL_IF(server == NULL, NULL, "Out of memory."); - accepted_gatt->type = VINE_GATT_ROLE_CLIENT; - accepted_gatt->remote_address = STRDUP(remote_address); + server->server = gatt_server; + server->client_list = new std::map; + return server; +} - // refer to server's gatt handles. - accepted_gatt->service = gatt->service; - accepted_gatt->characteristic = gatt->characteristic; - accepted_gatt->descriptor = gatt->descriptor; +static void _destroy_gatt_server(gatt_server_s *server) +{ + RET_IF(server == NULL, "Invalid parameter."); + bt_gatt_server_destroy(server->server); + server->server = NULL; + delete server->client_list; +} - accepted_gatt->is_accepted = true; - accepted_gatt->user = user_data; +static gatt_client_s *_create_gatt_client(bt_gatt_client_h gatt_client, bool is_accepted) +{ + gatt_client_s *client = (gatt_client_s *)calloc(1, sizeof(gatt_client_s)); + RET_VAL_IF(client == NULL, NULL, "Out of memory."); - g_callbacks.accepted_cb(VINE_DP_NOT_IP, accepted_gatt->remote_address, 0, accepted_gatt, user_data); + client->client = gatt_client; // gatt_client can be NULL. + client->is_accepted = is_accepted; + return client; +} + +static void _destroy_gatt_client(gatt_client_s *client) +{ + RET_IF(client == NULL, "Invalid parameter."); + bt_gatt_client_destroy(client->client); + client->client = NULL; +} + +static vine_gatt_s *__find_client_gatt(vine_gatt_s *gatt, const char *address) +{ + RET_VAL_IF(gatt == NULL, NULL, "Invalid parameter."); + RET_VAL_IF(address == NULL, NULL, "Invalid parameter."); + RET_VAL_IF(gatt->role.server == NULL, NULL, "Invalid parameter."); + RET_VAL_IF(gatt->role.server->client_list == NULL, NULL, "Invalid parameter."); + + std::map::iterator it; + + it = gatt->role.server->client_list->find(address); + if (it == gatt->role.server->client_list->end()) + return NULL; + + return (vine_gatt_s *)it->second; +} + +static void __invoke_accepted_cb(vine_gatt_s *gatt, void *user_data) +{ + if (!g_callbacks.accepted_cb) + return; + g_callbacks.accepted_cb(VINE_DP_NOT_IP, gatt->remote_address, 0, gatt, user_data); } static void __invoke_connected_cb(int result, void *user_data) @@ -174,12 +223,14 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, VINE_LOGI("Got write value requestment from %s.", remote_address); vine_gatt_s *gatt = (vine_gatt_s *)user_data; + vine_gatt_s *client_gatt = __find_client_gatt(gatt, remote_address); + RET_IF(client_gatt == NULL, "Cannot find a client[%s].", remote_address); // TODO: Need to handle splited data using offset. gatt_data_s *recv_data = __create_gatt_data(value, len, true); RET_IF(recv_data == NULL, "recv_data is NULL"); - gatt->recv_buffer->push(recv_data); + client_gatt->recv_buffer->push(recv_data); VINE_LOGI("Write value requested. offset[%d] len[%d] reponse_needed[%d]", offset, len, response_needed); @@ -189,7 +240,7 @@ static void __gatt_server_write_value_requested_cb(const char *remote_address, VINE_LOGE("bt_gatt_server_send_response() is failed."); if (g_callbacks.received_cb) - g_callbacks.received_cb(len, gatt->user); + g_callbacks.received_cb(len, client_gatt->user); } void __gatt_server_noti_state_changed_cb(bool notify, bt_gatt_server_h server, @@ -256,7 +307,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 characteristic = NULL; - int ret; + int ret = BT_ERROR_OPERATION_FAILED; ret = bt_gatt_client_create(remote_address, &client); if (ret != BT_ERROR_NONE || !client) @@ -279,11 +330,15 @@ static int __update_gatt_service_info(const char *remote_address, vine_gatt_s *g if (ret != BT_ERROR_NONE) goto ERR; - gatt->role.client = client; + gatt->role.client = _create_gatt_client(client, false); + if (!gatt->role.client) + goto ERR; + gatt->service = service; gatt->characteristic = characteristic; + gatt->remote_address = STRDUP(remote_address); - VINE_LOGE("Succeeded to update GATT service info."); + VINE_LOGI("Succeeded to update GATT service info."); return VINE_DATA_PATH_ERROR_NONE; ERR: @@ -292,6 +347,57 @@ ERR: return __convert_bt_error_to_data_path_error(ret); } +static vine_gatt_s *__create_accepted_gatt(const char *remote_address, vine_gatt_s *gatt, void *user) +{ + vine_gatt_s *accepted_gatt = _create_gatt(); + RET_VAL_IF(accepted_gatt == NULL, NULL, "Failed to create accepted_gatt."); + + accepted_gatt->type = VINE_GATT_ROLE_CLIENT; + accepted_gatt->role.client = _create_gatt_client(NULL, true); + if (!accepted_gatt->role.client) { + VINE_LOGE("Failed to create accepted_gatt."); + free(accepted_gatt); + return NULL; + } + + accepted_gatt->remote_address = STRDUP(remote_address); + // refer to server's gatt handles. + accepted_gatt->service = gatt->service; + accepted_gatt->characteristic = gatt->characteristic; + accepted_gatt->descriptor = gatt->descriptor; + + accepted_gatt->user = user; + return accepted_gatt; +} + +static void __handle_connected_client(vine_gatt_s *gatt, const char *address) +{ + RET_IF(gatt == NULL, "Invalid parameter."); + RET_IF(address == NULL, "Invalid parameter."); + RET_IF(gatt->role.server == NULL || gatt->role.server->client_list == NULL, "Invalid parameter."); + + vine_gatt_s *accepted_gatt = __create_accepted_gatt(address, gatt, gatt->user); + RET_IF(accepted_gatt == NULL, "Failed to create accepted gatt."); + + gatt->role.server->client_list->insert(std::make_pair(string(address), accepted_gatt)); + __invoke_accepted_cb(accepted_gatt, accepted_gatt->user); + VINE_LOGI("%s is connected.", address); +} + +static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address) +{ + RET_IF(gatt == NULL, "Invalid parameter."); + RET_IF(address == NULL, "Invalid parameter."); + RET_IF(gatt->role.server == NULL || gatt->role.server->client_list, "Invalid parameter."); + + vine_gatt_s *client_gatt = __find_client_gatt(gatt, address); + RET_IF(client_gatt == NULL, "Cannot find a client[%s].", address); + + gatt->role.server->client_list->erase(address); + __invoke_terminated_cb(client_gatt->user); + VINE_LOGI("%s is disconnected.", address); +} + static void __gatt_connection_state_changed_cb(int result, bool connected, const char *remote_address, void *user_data) { @@ -299,16 +405,19 @@ static void __gatt_connection_state_changed_cb(int result, bool connected, vine_gatt_s *gatt = (vine_gatt_s *)user_data; - VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s]", - gatt, result, connected, remote_address); + VINE_LOGI("gatt[%p] result[%d] connected[%d] remote address[%s] role[%d]", + gatt, result, connected, remote_address, gatt->type); if (!connected) { - __invoke_terminated_cb(gatt->user); + if (gatt->type == VINE_GATT_ROLE_SERVER) + __handle_disconnected_client(gatt, remote_address); + else + __invoke_terminated_cb(gatt->user); return; } - if (gatt->type == VINE_GATT_ROLE_SERVER) { - __invoke_accepted_cb(remote_address, gatt, gatt->user); + if (gatt->type == VINE_GATT_ROLE_SERVER && gatt->role.server) { + __handle_connected_client(gatt, remote_address); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { if (__update_gatt_service_info(remote_address, gatt) != VINE_DATA_PATH_ERROR_NONE) { bt_gatt_disconnect(remote_address); @@ -460,14 +569,14 @@ int gatt_destroy(vine_dp_plugin_h handle) vine_gatt_s *gatt = (vine_gatt_s *)handle; if (gatt->type == VINE_GATT_ROLE_SERVER) { - bt_gatt_server_destroy(gatt->role.server); + _destroy_gatt_server(gatt->role.server); gatt->role.server = NULL; bt_gatt_service_destroy(gatt->service); bt_gatt_characteristic_destroy(gatt->characteristic); bt_gatt_descriptor_destroy(gatt->descriptor); } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { // bt_gatt_h handles will be freed during bt_gatt_client_destroy(). - bt_gatt_client_destroy(gatt->role.client); + _destroy_gatt_client(gatt->role.client); gatt->role.client = NULL; } @@ -534,7 +643,10 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, } gatt->type = VINE_GATT_ROLE_SERVER; - gatt->role.server = server; + gatt->role.server = _create_gatt_server(server); + if (gatt->role.server == NULL) + goto ERR; + gatt->service = service; gatt->characteristic = characteristic; gatt->descriptor = descriptor; @@ -566,19 +678,16 @@ int gatt_connect(vine_dp_plugin_h handle, int addr_family, RET_VAL_IF(addr == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "addr is NULL"); vine_gatt_s *gatt = (vine_gatt_s *)handle; - bt_gatt_client_h client = NULL; int ret; + gatt->type = VINE_GATT_ROLE_CLIENT; ret = bt_gatt_connect(addr, false); if (ret != BT_ERROR_NONE) { VINE_LOGE("Failed to connect remote LE based service."); + gatt->type = VINE_GATT_ROLE_UNKNOWN; return __convert_bt_error_to_data_path_error(ret); } - gatt->type = VINE_GATT_ROLE_CLIENT; - gatt->role.client = client; - gatt->remote_address = STRDUP(addr); - VINE_LOGI("Succeed to request to GATT connect."); return VINE_DATA_PATH_ERROR_NONE; } @@ -645,7 +754,11 @@ int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len) ret =_gatt_write_to_client(gatt, buf, len); break; case VINE_GATT_ROLE_CLIENT: - ret = gatt->is_accepted ? _gatt_write_to_client(gatt, buf, len) + if (!gatt->role.client) { + ret = VINE_DATA_PATH_ERROR_OPERATION_FAILED; + break; + } + ret = gatt->role.client->is_accepted ? _gatt_write_to_client(gatt, buf, len) : _gatt_write_to_server(gatt, buf, len); break; case VINE_GATT_ROLE_UNKNOWN: -- 2.7.4 From 1671247e392df287e3130cbef465461555e93303 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Mon, 12 Jul 2021 18:34:51 +0900 Subject: [PATCH 12/16] vine-tool: terminate a tool when receiving interrupt signal - fix vine-tool bug - increase the version number for BLE GATT Change-Id: I42841ceb7ef72bfa8d17c19da16d30444e0740a0 --- packaging/capi-network-vine.spec | 2 +- tool/tool_run.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index 1aa666a..71a4b99 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.3 +Version: 1.1.4 Release: 0 Group: Network & Connectivity/API License: Apache-2.0 diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index d5e7e84..c74933b 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -632,9 +632,8 @@ void stop_event_loop() #ifdef USE_VINE_EVENT_LOOP_EXTERNAL_GLIB if (main_loop) g_main_loop_quit(main_loop); -#else - interrupt_flag = 1; #endif + interrupt_flag = 1; } static void _run_epoll_event_loop(vine_session_h session) -- 2.7.4 From 80fa6fd4d3bb625f27e3cc6dbe97e023716d1449 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Mon, 12 Jul 2021 19:38:11 +0900 Subject: [PATCH 13/16] Implement close function for GATT plugin Change-Id: I87a9ba031d8e02166b22eb4aebdd1c6b7f31f92f --- plugins/ble-gatt/ble-gatt-plugin.cpp | 25 ++++++++++++++++++++++--- src/vine-data-path.cpp | 2 +- tool/tool_run.cpp | 2 +- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index 45a1793..09f5792 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -267,8 +267,15 @@ void __gatt_server_noti_sent_cb(int result, 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) { - VINE_LOGI("gatt[%p] service[%s] is %s", - type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." ); + VINE_LOGI("gatt[%p] service uuid[%s] is %s", + user_data, uuid, type == BT_GATT_CLIENT_SERVICE_ADDED ? "added." : "removed." ); + + RET_IF(user_data == NULL, "user_data is NULL"); + // Should added state be handled? + RET_IF(type == BT_GATT_CLIENT_SERVICE_ADDED, "service is added."); + + vine_gatt_s *gatt = (vine_gatt_s *)user_data; + __invoke_terminated_cb(gatt->user); } void __gatt_client_write_complete_cb(int result, bt_gatt_h gatt_handle, void *user_data) @@ -772,7 +779,19 @@ int gatt_write(vine_dp_plugin_h handle, unsigned char *buf, size_t len) int gatt_close(vine_dp_plugin_h handle) { - return VINE_DATA_PATH_ERROR_NONE; + RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); + + vine_gatt_s *gatt = (vine_gatt_s *)handle; + int ret; + + 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); + } else if (gatt->type == VINE_GATT_ROLE_CLIENT) { + ret = bt_gatt_disconnect(gatt->remote_address); + VINE_LOGI("Disconnect from %s", gatt->remote_address); + } + return __convert_bt_error_to_data_path_error(ret); } int gatt_get_local_address_info(vine_dp_plugin_h handle, diff --git a/src/vine-data-path.cpp b/src/vine-data-path.cpp index c0aac6e..5dce302 100755 --- a/src/vine-data-path.cpp +++ b/src/vine-data-path.cpp @@ -484,7 +484,7 @@ int vine_data_path_close(vine_data_path_h datapath) RET_VAL_IF(datapath == NULL, VINE_ERROR_INVALID_PARAMETER, "datapath is NULL"); vine_data_path_s *dp = (vine_data_path_s *)datapath; - RET_VAL_IF(!dp->plugin_fn || dp->plugin_fn->close, + RET_VAL_IF(!dp->plugin_fn || !dp->plugin_fn->close, VINE_ERROR_INVALID_PARAMETER, "plugin_fn is NULL"); dp->plugin_fn->close(dp->plugin_handle); diff --git a/tool/tool_run.cpp b/tool/tool_run.cpp index c74933b..12df100 100755 --- a/tool/tool_run.cpp +++ b/tool/tool_run.cpp @@ -141,7 +141,7 @@ static void __received_cb(vine_dp_h dp, size_t received_len, void *user_data) static void __terminated_cb(vine_dp_h dp, void *user_data) { - printf("peer is terminated.\n"); + printf("peer[%p] is terminated.\n", dp); _stop_message_timer(dp); } -- 2.7.4 From 8c0434722cab97005072106ca598edc423ca9ac7 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Wed, 14 Jul 2021 14:18:44 +0900 Subject: [PATCH 14/16] Fix svace issues Change-Id: I3ba728610e840d98d1b9ed50864589708c37c105 --- plugins/ble-gatt/ble-gatt-plugin.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/ble-gatt/ble-gatt-plugin.cpp b/plugins/ble-gatt/ble-gatt-plugin.cpp index 09f5792..56802c4 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -395,7 +395,8 @@ static void __handle_disconnected_client(vine_gatt_s *gatt, const char *address) { RET_IF(gatt == NULL, "Invalid parameter."); RET_IF(address == NULL, "Invalid parameter."); - RET_IF(gatt->role.server == NULL || gatt->role.server->client_list, "Invalid parameter."); + RET_IF(gatt->role.server == NULL + || gatt->role.server->client_list == NULL, "Invalid parameter."); vine_gatt_s *client_gatt = __find_client_gatt(gatt, address); RET_IF(client_gatt == NULL, "Cannot find a client[%s].", address); @@ -632,7 +633,7 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, } descriptor = _add_gatt_descriptor(characteristic); - if (!characteristic) { + if (!descriptor) { VINE_LOGE("Failed to add descriptor."); goto ERR; } @@ -782,7 +783,7 @@ int gatt_close(vine_dp_plugin_h handle) RET_VAL_IF(handle == NULL, VINE_DATA_PATH_ERROR_INVALID_PARAMETER, "handle is NULL"); vine_gatt_s *gatt = (vine_gatt_s *)handle; - int ret; + 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); -- 2.7.4 From fe1cd63bcf2f9d57946f37258b571325af5caac0 Mon Sep 17 00:00:00 2001 From: Seonah Moon Date: Fri, 16 Jul 2021 11:24:54 +0900 Subject: [PATCH 15/16] event-loop: handles idle event Change-Id: I6858826eeba960ddeb0928930462e4d4f848fd5f --- packaging/capi-network-vine.spec | 2 +- plugins/ble-gatt/ble-gatt-plugin.cpp | 5 ++-- src/include/vine-event-loop.h | 6 +++++ src/vine-data-path.cpp | 2 +- src/vine-event-loop-epoll.cpp | 10 ++++++++ src/vine-event-loop-glib.cpp | 50 +++++++++++++++++++++++++++++++++++- src/vine-event-loop.cpp | 7 +++++ 7 files changed, 76 insertions(+), 6 deletions(-) diff --git a/packaging/capi-network-vine.spec b/packaging/capi-network-vine.spec index 71a4b99..ddff2eb 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.4 +Version: 1.1.5 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 56802c4..70d48ed 100755 --- a/plugins/ble-gatt/ble-gatt-plugin.cpp +++ b/plugins/ble-gatt/ble-gatt-plugin.cpp @@ -661,9 +661,8 @@ int gatt_open(vine_dp_plugin_h handle, int addr_family, VINE_LOGI("Succeeded to start GATT server."); - // TODO - //if (g_callbacks.opened_cb) - // g_callbacks.opened_cb(VINE_DATA_PATH_ERROR_NONE, -1, gatt->user); + if (g_callbacks.opened_cb) + g_callbacks.opened_cb(VINE_DATA_PATH_ERROR_NONE, -1, gatt->user); return VINE_DATA_PATH_ERROR_NONE; ERR: diff --git a/src/include/vine-event-loop.h b/src/include/vine-event-loop.h index 05379c4..ee9630a 100755 --- a/src/include/vine-event-loop.h +++ b/src/include/vine-event-loop.h @@ -60,6 +60,9 @@ int vine_event_loop_add_event(vine_event_queue_h event_queue, void *event_data, vine_event_handler handler, vine_event_free_handler free_func, void *user_data); +int vine_event_loop_add_idle_event(vine_event_queue_h event_queue, void *event_data, + vine_event_handler handler, vine_event_free_handler free_func, + void *user_data); typedef struct { int (*init)(); @@ -76,6 +79,9 @@ typedef struct { int (*add_event)(vine_event_queue_h event_queue, void *event_data, vine_event_handler handler, vine_event_free_handler free_func, void *user_data); + int (*add_idle_event)(vine_event_queue_h event_queue, void *event_data, + vine_event_handler handler, vine_event_free_handler free_func, + void *user_data); } vine_event_loop_fn; #define MAX_VINE_FDS 512 diff --git a/src/vine-data-path.cpp b/src/vine-data-path.cpp index 5dce302..0458549 100755 --- a/src/vine-data-path.cpp +++ b/src/vine-data-path.cpp @@ -258,7 +258,7 @@ static void __opened_cb(int result, int port, void *user_data) opened_event->result = result; opened_event->port = port; - vine_event_loop_add_event(dp->event_queue, opened_event, + vine_event_loop_add_idle_event(dp->event_queue, opened_event, __invoke_opened_user_cb, free, dp); } diff --git a/src/vine-event-loop-epoll.cpp b/src/vine-event-loop-epoll.cpp index e8815dd..626da1c 100755 --- a/src/vine-event-loop-epoll.cpp +++ b/src/vine-event-loop-epoll.cpp @@ -288,6 +288,15 @@ int vine_event_loop_epoll_add_event(vine_event_queue_h event_queue, void *event_ return VINE_ERROR_NONE; } +// event-loop-epoll processes the events whenever idle time. +// Therefore, this works the same with vine_event_loop_epoll_add_event(). +int vine_event_loop_epoll_add_idle_event(vine_event_queue_h event_queue, void *event_data, + vine_event_handler handler, vine_event_free_handler free_func, + void *user_data) +{ + return vine_event_loop_epoll_add_event(event_queue, event_data, handler, free_func, user_data); +} + int vine_event_loop_epoll_process(vine_event_queue_h event_queue) { VINE_LOGD("Process a vine event. event_queue[%p]", event_queue); @@ -338,4 +347,5 @@ vine_event_loop_fn vine_event_loop_epoll = { .mod_io_handler = vine_event_loop_epoll_mod_io_handler, .del_io_handler = vine_event_loop_epoll_del_io_handler, .add_event = vine_event_loop_epoll_add_event, + .add_idle_event = vine_event_loop_epoll_add_idle_event, }; diff --git a/src/vine-event-loop-glib.cpp b/src/vine-event-loop-glib.cpp index 390eb51..35a0b87 100755 --- a/src/vine-event-loop-glib.cpp +++ b/src/vine-event-loop-glib.cpp @@ -27,6 +27,13 @@ #include "vine-utils.h" typedef struct { + void *event_data; + vine_event_handler handler; + vine_event_free_handler free_func; + void *user_data; +} vine_glib_idle_event_handler; + +typedef struct { int fd; vine_poll_handler handler; void *user_data; @@ -202,6 +209,46 @@ int vine_event_loop_glib_add_event(vine_event_queue_h event_queue, void *event_d return VINE_ERROR_NONE; } +static gboolean _handle_idle_event(gpointer user_data) +{ + RET_VAL_IF(user_data == NULL, VINE_ERROR_INVALID_PARAMETER, "user_data is NULL"); + + vine_glib_idle_event_handler *idle_handler = (vine_glib_idle_event_handler *)user_data; + VINE_LOGD("event_data[%p]", idle_handler->event_data); + + if (idle_handler->handler) + idle_handler->handler(idle_handler->event_data, idle_handler->user_data); + + if (idle_handler->free_func) + idle_handler->free_func(idle_handler->event_data); + + free(idle_handler); + + return FALSE; +} + +int vine_event_loop_glib_add_idle_event(vine_event_queue_h event_queue, void *event_data, + vine_event_handler handler, vine_event_free_handler free_func, + void *user_data) +{ + // Ignore event_queue + + RET_VAL_IF(handler == NULL, VINE_ERROR_INVALID_PARAMETER, "handler is NULL"); + VINE_LOGD("event_data[%p]", event_data); + + vine_glib_idle_event_handler *idle_handler = + (vine_glib_idle_event_handler *) calloc(1, sizeof(vine_glib_idle_event_handler)); + RET_VAL_IF(idle_handler == NULL, VINE_ERROR_INVALID_PARAMETER, "idle_handler is NULL"); + + idle_handler->event_data = event_data; + idle_handler->handler = handler; + idle_handler->free_func = free_func; + idle_handler->user_data = user_data; + g_idle_add(_handle_idle_event, idle_handler); + + return VINE_ERROR_NONE; +} + int vine_event_loop_glib_process(vine_event_queue_h event_queue) { return VINE_ERROR_NONE; @@ -220,6 +267,7 @@ vine_event_loop_fn vine_event_loop_glib = { .mod_io_handler = vine_event_loop_glib_mod_io_handler, .del_io_handler = vine_event_loop_glib_del_io_handler, .add_event = vine_event_loop_glib_add_event, + .add_idle_event = vine_event_loop_glib_add_idle_event, }; -#endif // USE_VINE_EVENT_LOOP_EXTERNAL_GLIB \ No newline at end of file +#endif // USE_VINE_EVENT_LOOP_EXTERNAL_GLIB diff --git a/src/vine-event-loop.cpp b/src/vine-event-loop.cpp index 950edf0..e5ce195 100755 --- a/src/vine-event-loop.cpp +++ b/src/vine-event-loop.cpp @@ -121,6 +121,13 @@ int vine_event_loop_add_event(vine_event_queue_h event_queue, void *event_data, return __event_loop[__event_loop_type].add_event(event_queue, event_data, handler, free_func, user_data); } +int vine_event_loop_add_idle_event(vine_event_queue_h event_queue, void *event_data, + vine_event_handler handler, vine_event_free_handler free_func, + void *user_data) +{ + return __event_loop[__event_loop_type].add_idle_event(event_queue, event_data, handler, free_func, user_data); +} + int vine_event_loop_process(vine_event_queue_h event_queue) { return __event_loop[__event_loop_type].process(event_queue); -- 2.7.4 From 6156563dfaeb364b80e67a95fd9afbb772a7553d Mon Sep 17 00:00:00 2001 From: Cheoleun Moon Date: Wed, 21 Jul 2021 17:21:04 +0900 Subject: [PATCH 16/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