nan plugin: add publish and subscribe 03/261703/2
authorCheoleun Moon <chleun.moon@samsung.com>
Fri, 23 Jul 2021 03:11:37 +0000 (12:11 +0900)
committerCheoleun Moon <chleun.moon@samsung.com>
Mon, 30 Aug 2021 07:07:51 +0000 (16:07 +0900)
Change-Id: I891c5e17cd87909b6fabbffec45509610a20f69f
Signed-off-by: Cheoleun Moon <chleun.moon@samsung.com>
CMakeLists.txt
packaging/capi-network-vine.spec
plugins/nan/CMakeLists.txt [new file with mode: 0755]
plugins/nan/nan-plugin.cpp [new file with mode: 0755]
plugins/nan/nan-plugin.h [new file with mode: 0755]
src/include/vine-constants.h

index a6834a7e14cbefa216c934a9da90289109611d08..c9dfd61699179d7515a6c3aad9902e8a274a2526 100755 (executable)
@@ -36,6 +36,8 @@ OPTION(WITH_VINE_TEST "With vine command-line test tools" OFF)
 OPTION(ENABLE_INSTRUMENTATION_MODE "Enable instrumentation mode" OFF)
 OPTION(ENABLE_DATAPATH_PLUGIN_DEBUG "Enable debug mode for data path plugin" OFF)
 
+OPTION(NAN_SUPPORT "Support NAN" OFF)
+
 INCLUDE(FindPkgConfig)
 
 SET(BUILD_OS "default")
@@ -90,6 +92,13 @@ IF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB)
        SET(BT_SUPPORT ON)
 ENDIF(TIZEN_OS AND USE_EVENT_LOOP_EXTERNAL_GLIB)
 
+IF(NAN_SUPPORT)
+       IF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB)
+               MESSAGE("NAN is supported in Tizen with external glib loop")
+               SET(NAN_SUPPORT OFF)
+       ENDIF(NOT TIZEN_OS OR NOT USE_EVENT_LOOP_EXTERNAL_GLIB)
+ENDIF(NAN_SUPPORT)
+
 IF(ENABLE_INSTRUMENTATION_MODE)
        SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -finstrument-functions -finstrument-functions-exclude-file-list=src/logger")
        ADD_DEFINITIONS("-DENABLE_INSTRUMENTATION_MODE")
@@ -129,6 +138,9 @@ IF(BT_SUPPORT)
        ADD_SUBDIRECTORY(plugins/ble)
        ADD_SUBDIRECTORY(plugins/ble-gatt)
 ENDIF(BT_SUPPORT)
+IF(NAN_SUPPORT)
+       ADD_SUBDIRECTORY(plugins/nan)
+ENDIF(NAN_SUPPORT)
 
 ADD_SUBDIRECTORY(include)
 ADD_SUBDIRECTORY(src/logger)
index ddff2eb2f314e378a5a641787efd92e6de4aaf23..0f7b057e532a08b40cd04234b76ebdccc3c1c75a 100755 (executable)
@@ -24,6 +24,7 @@ BuildRequires: pkgconfig(capi-base-common)
 BuildRequires: pkgconfig(capi-system-info)
 BuildRequires: pkgconfig(dlog)
 
+BuildRequires: pkgconfig(capi-network-wifi-aware)
 BuildRequires: pkgconfig(capi-network-bluetooth)
 %endif
 
@@ -103,6 +104,7 @@ export LDFLAGS+=" -lgcov"
 %else
         -DUSE_LIBWEBSOCKETS_STATIC=OFF \
 %endif
+        -DNAN_SUPPORT=ON \
 %if %{with lws_static_prebuilt}
         -DUSE_LIBWEBSOCKETS_STATIC_PREBUILT=ON \
 %else
diff --git a/plugins/nan/CMakeLists.txt b/plugins/nan/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..9367cb5
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
+#
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicanan law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+#
+
+SET(NAN_PLUGIN "vine-plugin-nan")
+
+SET(NAN_PLUGIN_VERSION_MAJOR "1")
+SET(NAN_PLUGIN_VERSION_MINOR "0")
+SET(NAN_PLUGIN_VERSION_PATCH "0")
+SET(NAN_PLUGIN_VERSION ${NAN_PLUGIN_VERSION_MAJOR}.${NAN_PLUGIN_VERSION_MINOR}.${NAN_PLUGIN_VERSION_PATCH})
+
+PKG_CHECK_MODULES(NAN_DEPS REQUIRED "capi-network-wifi-aware")
+
+INCLUDE_DIRECTORIES(
+    ${VINE_PATH}/include
+    ${VINE_LOGGER_PATH}
+    ${CMAKE_CURRENT_SOURCE_DIR}
+    ${${fw_name}_INCLUDE_DIRS}
+    ${NAN_DEPS_INCLUDE_DIRS}
+)
+
+FILE(GLOB VINE_NAN_PLUGIN_SOURCES *.cpp)
+
+ADD_DEFINITIONS("-fvisibility=default")
+ADD_LIBRARY(${NAN_PLUGIN} SHARED ${VINE_NAN_PLUGIN_SOURCES})
+
+SET_TARGET_PROPERTIES(
+    ${NAN_PLUGIN}
+    PROPERTIES
+        SOVERSION ${NAN_PLUGIN_VERSION_MAJOR}
+)
+
+TARGET_LINK_LIBRARIES(${NAN_PLUGIN}
+    ${VINE_LOGGER}
+    ${NAN_DEPS_LIBRARIES}
+    ${fw_name_deps_LIBRARIES}
+    dl
+)
+
+INSTALL(TARGETS ${NAN_PLUGIN} DESTINATION "${LIB_DIR}")
diff --git a/plugins/nan/nan-plugin.cpp b/plugins/nan/nan-plugin.cpp
new file mode 100755 (executable)
index 0000000..0739860
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+
+#include <string>
+
+#include <wifi-aware.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <errno.h>
+
+#include "vine-constants.h"
+#include "vine-disc-plugin.h"
+#include "vine-log.h"
+#include "vine-utils.h"
+#include "nan-plugin.h"
+
+typedef struct {
+       void *disc_handle;      // vine_disc handle
+       wifi_aware_publish_h publish_config;
+       wifi_aware_subscribe_h subscribe_config;
+       wifi_aware_session_h session;
+       //char service_type[NAN_SERVICE_TYPE_LEN + 1];
+       char service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1];
+} vine_nan_s;
+
+static bool __is_nan_enabled = false;
+static vine_disc_plugin_callbacks event_callbacks;
+
+static vine_disc_error __convert_nan_error_to_vine_disc_error(int error)
+{
+       return VINE_DISC_ERROR_NONE;
+}
+
+
+vine_disc_error nan_resolve_ip(void *plugin_handle,
+                               const char *service_type, const char *service_name,
+                               const char *host_name, const char *iface_name, int family)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+       RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
+       RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
+       // Ignore host_name and iface_name
+
+       RET_VAL_IF(family == VINE_DISC_ADDR_FAMILY_IPV4, VINE_DISC_ERROR_NOT_SUPPORTED,
+               "Only IPv6 is allowed for NAN");
+
+       VINE_LOGD("Start to resolve IP. plugin_handle[%p]\n", plugin_handle);
+       VINE_LOGD("type[%s] name[%s]", service_type, service_name);
+
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       return VINE_DISC_ERROR_NONE;
+}
+
+vine_disc_error nan_cancel_resolve_ip(void *plugin_handle)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+       VINE_LOGD("Cancel resolving IP. plugin_handle[%p]\n", plugin_handle);
+
+       return VINE_DISC_ERROR_NONE;
+}
+
+
+vine_disc_error nan_init(void **plugin_handle, void *disc_handle)
+{
+       vine_nan_s *handle = new vine_nan_s;
+
+       handle->disc_handle = disc_handle;
+       handle->publish_config = nullptr;
+       handle->subscribe_config = nullptr;
+       handle->session = nullptr;
+
+       // NAN will be enabled when publish() or subscribe()
+       // because enable function works asynchronously.
+
+       return VINE_DISC_ERROR_NONE;
+}
+
+void nan_deinit(void *plugin_handle)
+{
+       RET_IF(plugin_handle == NULL, "Plugin handle is null");
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+
+       // TODO
+       // Disable NAN here.
+       // However, we have to check if NAN is used for data path
+
+       delete nan_handle;
+}
+
+static void __published_cb(wifi_aware_session_h session,
+       wifi_aware_error_e error, void *user_data)
+{
+       VINE_LOGD("Service is published");
+       vine_nan_s *nan_handle = (vine_nan_s *)user_data;
+
+       if (event_callbacks.published_cb)
+               event_callbacks.published_cb(nan_handle,
+                       nan_handle->service_name, __convert_nan_error_to_vine_disc_error(error),
+                       nan_handle->disc_handle);
+}
+
+static void __publish(vine_nan_s *nan_handle)
+{
+       wifi_aware_session_h session;
+       int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_PUBLISH, &session);
+       RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails");
+
+       ret = wifi_aware_session_publish(session, nan_handle->publish_config,
+               __published_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_session_publish() fails");
+               wifi_aware_session_destroy(session);
+       }
+
+       nan_handle->session = session;
+}
+
+static void __subscribed_cb(wifi_aware_session_h session,
+       wifi_aware_error_e error, void *user_data)
+{
+       RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error");
+       vine_nan_s *nan_handle = (vine_nan_s *)user_data;
+
+       VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error));
+       if (event_callbacks.discovered_cb) {
+               std::map<string, string> empty_map;
+               event_callbacks.discovered_cb(nan_handle, false,
+                       nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle);
+       }
+}
+
+static void __subscribe(vine_nan_s *nan_handle)
+{
+       wifi_aware_session_h session;
+       int ret = wifi_aware_session_create(WIFI_AWARE_SESSION_SUBSCRIBE, &session);
+       RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_session_create() fails");
+
+       ret = wifi_aware_session_subscribe(session, nan_handle->subscribe_config,
+               __subscribed_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_session_publish() fails");
+               wifi_aware_session_destroy(session);
+       }
+
+       nan_handle->session = session;
+}
+
+static void __start_session(vine_nan_s *nan_handle)
+{
+       if (nan_handle->publish_config)
+               __publish(nan_handle);
+       else if (nan_handle->subscribe_config)
+               __subscribe(nan_handle);
+       else
+               VINE_LOGE("Invalid operation");
+}
+
+static void __stop_session(vine_nan_s *nan_handle)
+{
+       if (nan_handle->session) {
+               wifi_aware_session_stop(nan_handle->session);
+               wifi_aware_session_destroy(nan_handle->session);
+       }
+}
+
+static void __enabled_cb(wifi_aware_error_e error, void *user_data)
+{
+       RET_IF(!user_data, "nan_handle is NULL");
+       __start_session((vine_nan_s *)user_data);
+}
+
+static bool __check_attr_len(const map<string, string> &attributes)
+{
+       int info_len = VINE_MAX_NAN_SERVICE_NAME_LEN;
+       for (const auto &kv : attributes) {
+               auto key = kv.first;
+               auto val = kv.second;
+               info_len += key.size() + val.size() + 1;
+               if (info_len > MAX_SPECIFIC_INFO_LEN)
+                       return false;
+       }
+       return true;
+}
+
+static void __fill_specific_info(unsigned char *info, const char *service_name,
+       const map<string, string> &attributes)
+{
+       int service_name_len = strlen(service_name);
+       memcpy(info, service_name, service_name_len);
+       info[service_name_len] = 0;
+
+       unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN];
+       for (const auto &kv : attributes) {
+               auto key = kv.first;
+               auto val = kv.second;
+               int key_len = key.size();
+               int val_len = val.size();
+               *ptr = (unsigned char)(key_len + val_len + 1);
+               ptr++;
+               memcpy(ptr, key.c_str(), key_len);
+               ptr += key_len;
+               *ptr++ = '=';
+               memcpy(ptr, val.c_str(), val_len);
+               ptr += val_len;
+       }
+}
+
+vine_disc_error nan_publish(void *plugin_handle, const char *service_type,
+               const char *service_name, int port, const map<string, string> &attributes,
+               const char *iface_name)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+       RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
+       RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
+       RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+               "Too long service type");
+       RET_VAL_IF(strlen(service_name) > VINE_MAX_NAN_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+               "Too long service name");
+       RET_VAL_IF(__check_attr_len(attributes) == false, VINE_DISC_ERROR_INVALID_PARAMETER,
+               "Too long attributes");
+       for (const auto &kv : attributes) {
+               auto key = kv.first.c_str();
+               auto val = kv.second.c_str();
+       }
+
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle);
+
+       strncpy(nan_handle->service_name, service_name, VINE_MAX_NAN_SERVICE_NAME_LEN);
+
+       wifi_aware_publish_h config = nullptr;
+       int ret = wifi_aware_publish_create(&config);
+       RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret),
+               "wifi_aware_publish_create() fails");
+
+       unsigned char info[MAX_SPECIFIC_INFO_LEN + 1] = {0, };
+
+       ret = wifi_aware_publish_set_type(config, WIFI_AWARE_PUBLISH_TYPE_UNSOLICITED);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_publish_set_type() fails");
+               goto ERR;
+       }
+
+       ret = wifi_aware_publish_set_service_name(config, service_type);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_publish_set_service_name() fails");
+               goto ERR;
+       }
+
+       __fill_specific_info(info, service_name, attributes);
+
+       nan_handle->publish_config = config;
+
+       ret = wifi_aware_enable(__enabled_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_enable() fails");
+               goto ERR;
+       }
+
+       return VINE_DISC_ERROR_NONE;
+
+ERR:
+       wifi_aware_publish_destroy(config);
+       return __convert_nan_error_to_vine_disc_error(ret);
+}
+
+vine_disc_error nan_stop_publish(void *plugin_handle)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       __stop_session(nan_handle);
+
+       if (nan_handle->publish_config)
+               wifi_aware_publish_destroy(nan_handle->publish_config);
+
+       return VINE_DISC_ERROR_NONE;
+}
+
+vine_disc_error nan_subscribe(void *plugin_handle,
+               const char *service_type, const char *iface_name)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+       RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
+       RET_VAL_IF(strlen(service_type) > NAN_MAX_SERVICE_NAME_LEN, VINE_DISC_ERROR_INVALID_PARAMETER,
+               "Too long service type");
+
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       VINE_LOGD("Publish a service. plugin_handle[%p]\n", plugin_handle);
+
+       wifi_aware_subscribe_h config = nullptr;
+       int ret = wifi_aware_subscribe_create(&config);
+       RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret),
+               "wifi_aware_subscribe_create() fails");
+
+       ret = wifi_aware_subscribe_set_type(config, WIFI_AWARE_SUBSCRIBE_TYPE_ACTIVE);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_subscribe_set_type() fails");
+               goto ERR;
+       }
+
+       ret = wifi_aware_subscribe_set_service_name(config, service_type);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_subscribe_set_service_name() fails");
+               goto ERR;
+       }
+
+       nan_handle->subscribe_config = config;
+
+       ret = wifi_aware_enable(__enabled_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_enable() fails");
+               goto ERR;
+       }
+
+       return VINE_DISC_ERROR_NONE;
+
+ERR:
+       wifi_aware_subscribe_destroy(config);
+       return __convert_nan_error_to_vine_disc_error(ret);
+}
+
+vine_disc_error nan_stop_subscribe(void *plugin_handle)
+{
+       RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
+
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       __stop_session(nan_handle);
+
+       if (nan_handle->subscribe_config)
+               wifi_aware_subscribe_destroy(nan_handle->subscribe_config);
+
+       return VINE_DISC_ERROR_NONE;
+}
+
+
+void nan_register_callbacks(vine_disc_plugin_callbacks callbacks)
+{
+       event_callbacks.published_cb = callbacks.published_cb;
+       event_callbacks.discovered_cb = callbacks.discovered_cb;
+       event_callbacks.ip_resolved_cb = callbacks.ip_resolved_cb;
+       event_callbacks.fd_added_cb = nullptr;
+       event_callbacks.fd_removed_cb = nullptr;
+       event_callbacks.ble_discovered_cb = nullptr;
+}
+
+vine_disc_error nan_process_event(void *plugin_handle, int fd)
+{
+       VINE_LOGE("Not supported function");
+       return VINE_DISC_ERROR_NOT_SUPPORTED;
+}
+
+void vine_disc_plugin_init(vine_disc_plugin_fn *fn)
+{
+       fn->init = nan_init;
+       fn->deinit = nan_deinit;
+       fn->publish = nan_publish;
+       fn->stop_publish = nan_stop_publish;
+       fn->subscribe = nan_subscribe;
+       fn->stop_subscribe = nan_stop_subscribe;
+       fn->resolve_ip = nan_resolve_ip;
+       fn->cancel_resolve_ip = nan_cancel_resolve_ip;
+       fn->register_callbacks = nan_register_callbacks;
+       fn->process_event = nan_process_event;
+}
diff --git a/plugins/nan/nan-plugin.h b/plugins/nan/nan-plugin.h
new file mode 100755 (executable)
index 0000000..890b51e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+*/
+#pragma once
+
+#define NAN_MAX_SERVICE_NAME_LEN 255
+#define MAX_SPECIFIC_INFO_LEN 1024
index 206f28d51e36bf7180b188012f600d7a685436f2..6ca58e1b9007b74a67c2c76adb92c9374b795c6d 100755 (executable)
@@ -36,4 +36,7 @@
 #define VINE_MAX_BLE_SERVICE_NAME_LEN 15
 #define VINE_MAC_LEN 17
 
+#define VINE_MAX_NAN_SERVICE_TYPE_LEN 63
+#define VINE_MAX_NAN_SERVICE_NAME_LEN 63
+
 #endif /* __VINE_SERV__VINE_CONSTANTS_H__ICE_H__ */