nan-plugin: add resolve_ip 70/261870/4
authorCheoleun Moon <chleun.moon@samsung.com>
Wed, 28 Jul 2021 04:55:39 +0000 (13:55 +0900)
committercheoleun moon <chleun.moon@samsung.com>
Mon, 30 Aug 2021 07:51:41 +0000 (07:51 +0000)
Change-Id: Ib0d10a908b4ba73baedf07629004bfc56bf1768e

include/vine.h
packaging/capi-network-vine.spec
plugins/nan/nan-plugin.cpp
plugins/nan/nan-plugin.h

index e68d347..fd77cbc 100755 (executable)
@@ -463,6 +463,7 @@ int vine_session_unset_registered_cb(vine_session_h session);
 /**
  * @brief Called when service is discovered.
  * @remarks @a service will be freed after this callback. Use @a vine_service_clone().
+ * @remarks If there is an internal error, @a service will be NULL.
  * @since_tizen 6.5
  * @param[in] session The session handle
  * @param[in] discovered_service The discovered service
index 105abde..1b5adbb 100755 (executable)
@@ -3,7 +3,7 @@
 %bcond_without use_glib_event_loop
 Name:    capi-network-vine
 Summary: An service discovery framework
-Version: 1.1.7
+Version: 1.1.8
 Release: 0
 Group:   Network & Connectivity/API
 License: Apache-2.0
index 3bcadb8..ef108e8 100755 (executable)
@@ -18,6 +18,8 @@
 #include <string>
 #include <map>
 
+#include <glib.h>
+
 #include <wifi-aware.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -35,9 +37,11 @@ typedef struct {
        wifi_aware_publish_h publish_config;
        wifi_aware_subscribe_h subscribe_config;
        wifi_aware_session_h session;
-       std::map<string, wifi_aware_peer_h> peer_map;   // <mac, peer>
+       std::map<string, wifi_aware_peer_h> peers;      // <mac, peer>
+       std::map<wifi_aware_peer_h, wifi_aware_data_path_h> ndps;       // <peer, ndp>
 
-       char service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1];
+       char published_service_name[VINE_MAX_NAN_SERVICE_NAME_LEN + 1];
+       char service_type[VINE_MAX_NAN_SERVICE_TYPE_LEN + 1];
        int port;
 } vine_nan_s;
 
@@ -49,6 +53,132 @@ static vine_disc_error __convert_nan_error_to_vine_disc_error(int error)
        return VINE_DISC_ERROR_NONE;
 }
 
+static bool __is_data_path_request_message(const unsigned char *message, size_t len)
+{
+       RET_VAL_IF(len != strlen(VINE_FOLLOWUP_MESSAGE), false, "Wrong message");
+       return memcmp(message, VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE)) == 0;
+}
+
+static void __add_ndp(vine_nan_s *nan_handle,
+       wifi_aware_data_path_h ndp, wifi_aware_peer_h peer)
+{
+       VINE_LOGD("Add NDP[%p]. peer[%p]", ndp, peer);
+       auto v = nan_handle->ndps.find(peer);
+       if (v == nan_handle->ndps.end()) {
+               // TODO: Can the same peer request NAN data path?
+       }
+       nan_handle->ndps[peer] = ndp;
+}
+
+static void __terminated_cb(wifi_aware_data_path_h ndp,
+       wifi_aware_termination_reason_e reason, void *user_data)
+{
+       VINE_LOGD("NDP is terminated [%p]. reason[%d]", ndp, (int)reason);
+
+       vine_nan_s *nan_handle = (vine_nan_s *)user_data;
+       if (event_callbacks.ip_resolved_cb)
+               event_callbacks.ip_resolved_cb(nan_handle, false,
+                       nullptr, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle);
+}
+
+static void __open_cb(wifi_aware_data_path_h ndp,
+       wifi_aware_error_e error, void *user_data)
+{
+       RET_IF(!event_callbacks.ip_resolved_cb, "No callbacks");
+
+       char *ipv6;
+       if (wifi_aware_data_path_get_peer_ipv6_address(ndp, &ipv6) != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_data_path_get_peer_ipv6_address() fails");
+               return;
+       }
+
+       vine_nan_s *nan_handle = (vine_nan_s *)user_data;
+
+       event_callbacks.ip_resolved_cb(nan_handle, true,
+               ipv6, VINE_DISC_ADDR_FAMILY_IPV6, nan_handle->disc_handle);
+       g_free(ipv6);
+}
+
+static void __open_nan_data_path(wifi_aware_session_h session,
+       wifi_aware_peer_h peer, vine_nan_s *nan_handle)
+{
+       VINE_LOGD("Open NAN data path. session[%p]", session);
+
+       /*
+       std::string mac;
+       bool found = false;
+       for (const auto &kv : nan_handle->peers) {
+               if (kv.second == peer) {
+                       mac = kv.first;
+                       found = true;
+                       break;
+               }
+       }
+
+       if (!found) {
+               VINE_LOGE("Invalid peer");
+               return;
+       }
+       */
+
+       wifi_aware_data_path_h ndp;
+       if (wifi_aware_data_path_create(session, peer, &ndp) != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_data_path_create() fails");
+               return;
+       }
+
+       if (wifi_aware_data_path_set_terminated_cb(ndp, __terminated_cb, nan_handle)
+               != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_data_path_set_terminated_cb() fails");
+               return;
+       }
+
+       if (wifi_aware_data_path_open(ndp, __open_cb, nan_handle) != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_data_path_open() fails");
+               return;
+       }
+
+       // TODO: Need to maintain ndp list?
+       __add_ndp(nan_handle, ndp, peer);
+}
+
+static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer,
+       const unsigned char *message, size_t len, void *user_data)
+{
+       RET_IF(!user_data, "user_data is NULL");
+       VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]",
+               session, peer, user_data);
+
+       if (!__is_data_path_request_message(message, len)) {
+               VINE_LOGD("This message will be not used");
+               return;
+       }
+
+       __open_nan_data_path(session, peer, (vine_nan_s *)user_data);
+}
+
+static void __message_result_cb(wifi_aware_session_h session,
+       wifi_aware_error_e error, void *user_data)
+{
+       if (error == WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGD("Message is successfully sent");
+               return;
+       }
+
+       // TODO
+       // How can inform the failure to app?
+       // Use ip_resolved_cb with nullptr IP address?
+       // Then, in terminated_cb, I think ip_resolved_cb is called with ip address (add is false)
+}
+
+static int __send_nan_dp_request(wifi_aware_session_h session,
+       wifi_aware_peer_h peer, vine_nan_s *nan_handle)
+{
+       VINE_LOGD("Send NAN Datapath request message");
+       return wifi_aware_session_send_message(session, peer,
+               (unsigned char *)VINE_FOLLOWUP_MESSAGE, strlen(VINE_FOLLOWUP_MESSAGE),
+               __message_result_cb, nan_handle);
+}
 
 vine_disc_error nan_resolve_ip(void *plugin_handle,
                                const char *service_type, const char *service_name,
@@ -57,17 +187,30 @@ vine_disc_error nan_resolve_ip(void *plugin_handle,
        RET_VAL_IF(!plugin_handle, VINE_DISC_ERROR_INVALID_PARAMETER, "plugin_handle is NULL");
        RET_VAL_IF(!service_type, VINE_DISC_ERROR_INVALID_PARAMETER, "service_type is NULL");
        RET_VAL_IF(!service_name, VINE_DISC_ERROR_INVALID_PARAMETER, "service_name is NULL");
+       RET_VAL_IF(!mac, VINE_DISC_ERROR_INVALID_PARAMETER, "mac is NULL");
        // Ignore host_name and iface_name
-
        RET_VAL_IF(family == VINE_DISC_ADDR_FAMILY_IPV4, VINE_DISC_ERROR_NOT_SUPPORTED,
                "Only IPv6 is allowed for NAN");
 
+       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       RET_VAL_IF(nan_handle->peers.find(mac) == nan_handle->peers.end(),
+               VINE_DISC_ERROR_INVALID_PARAMETER, "Invalid mac[%s]", mac);
+
        VINE_LOGD("Start to resolve IP. plugin_handle[%p]\n", plugin_handle);
-       VINE_LOGD("type[%s] name[%s]", service_type, service_name);
+       VINE_LOGD("type[%s] name[%s] mac[%s]", service_type, service_name, mac);
 
-       vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
+       int ret = wifi_aware_session_set_message_received_cb(nan_handle->session,
+               __received_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_session_set_message_received_cb() fails");
+               return __convert_nan_error_to_vine_disc_error(ret);
+       }
 
-       return VINE_DISC_ERROR_NONE;
+       ret = __send_nan_dp_request(nan_handle->session, nan_handle->peers[mac], nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE)
+               VINE_LOGE("__send_nan_dp_request() fails");
+
+       return __convert_nan_error_to_vine_disc_error(ret);
 }
 
 vine_disc_error nan_cancel_resolve_ip(void *plugin_handle)
@@ -102,50 +245,13 @@ void nan_deinit(void *plugin_handle)
        vine_nan_s *nan_handle = (vine_nan_s *)plugin_handle;
 
        // TODO
-       // Disable NAN here.
+       // Disable NAN here?
        // However, we have to check if NAN is used for data path or not
        // , and if NAN data path is broken or not when NAN is disabled.
 
        delete nan_handle;
 }
 
-static bool __is_interest_message(const unsigned char *message, size_t len)
-{
-       // TODO: We have to determine message format.
-       return true;
-}
-
-static void __open_nan_data_path(wifi_aware_session_h session,
-       wifi_aware_peer_h peer, vine_nan_s *nan_handle)
-{
-       VINE_LOGD("Open NAN data path. session[%p]", session);
-
-       wifi_aware_data_path_h ndp;
-       int ret = wifi_aware_data_path_create(session, peer, &ndp);
-
-       // TODO
-       // Need to keep ndp
-}
-
-static void __received_cb(wifi_aware_session_h session, wifi_aware_peer_h peer,
-       const unsigned char *message, size_t len, void *user_data)
-{
-       RET_IF(!user_data, "user_data is NULL");
-       VINE_LOGD("NAN message is received. session[%p], peer[%p], nan_handle[%p]",
-               session, peer, user_data);
-
-       if (!__is_interest_message(message, len)) {
-               VINE_LOGD("This message will be not used");
-               return;
-       }
-
-       vine_nan_s *nan_handle = (vine_nan_s *)user_data;
-       __open_nan_data_path(session, peer, nan_handle);
-
-       // TODO
-       // Need to keep peer
-}
-
 static void __published_cb(wifi_aware_session_h session,
        wifi_aware_error_e error, void *user_data)
 {
@@ -154,7 +260,7 @@ static void __published_cb(wifi_aware_session_h session,
 
        if (event_callbacks.published_cb)
                event_callbacks.published_cb(nan_handle,
-                       nan_handle->service_name, __convert_nan_error_to_vine_disc_error(error),
+                       nan_handle->published_service_name, __convert_nan_error_to_vine_disc_error(error),
                        nan_handle->disc_handle);
 }
 
@@ -185,20 +291,104 @@ ERR:
        wifi_aware_session_destroy(session);
 }
 
-static void __subscribed_cb(wifi_aware_session_h session,
-       wifi_aware_error_e error, void *user_data)
+static bool __get_attributes(const unsigned char *info, size_t len, map<string, string> &attr)
 {
-       RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error");
+       VINE_LOGD("Get Attributes");
+
+       const unsigned char *ptr = &info[VINE_MAX_NAN_SERVICE_NAME_LEN];
+       const unsigned char *max = info + len;
+       char key_buf[MAX_SPECIFIC_INFO_LEN + 1];
+       char value_buf[MAX_SPECIFIC_INFO_LEN + 1];
+
+       while (ptr < max) {
+               const unsigned char *const end = ptr + 1 + ptr[0];
+               if (end > max) {
+                       VINE_LOGE("Invalid attribute");
+                       return false;
+               }
+               char *buf = &key_buf[0];
+               while (++ptr < end) {
+                       if (*ptr == '=') {
+                               *buf = 0;
+                               buf = &value_buf[0];
+                       } else {
+                               *buf = *ptr;
+                               ++buf;
+                       }
+               }
+               *buf = 0;
+               VINE_LOGD("Key[%s] Value[%s]", key_buf, value_buf);
+               string key(key_buf);
+               string value(value_buf);
+               attr[key] = value;
+       }
+       return true;
+}
+
+static void __add_peer(vine_nan_s *nan_handle, wifi_aware_peer_h peer, const char *mac)
+{
+       VINE_LOGD("Add peer[%p]. mac[%s]", peer, mac);
+       nan_handle->peers[mac] = peer;
+}
+
+static void __discovered_cb(wifi_aware_session_h session,
+       wifi_aware_peer_h peer, const unsigned char *service_specific_info, size_t len,
+       int distance, void *user_data)
+{
+       VINE_LOGD("Service Discovered. session[%p] peer[%p]", session, peer);
+       RET_IF(event_callbacks.discovered_cb == NULL, "discovered_cb is NULL");
+
+       if (len > MAX_SPECIFIC_INFO_LEN || len < VINE_MAX_NAN_SERVICE_NAME_LEN) {
+               VINE_LOGE("Invalid info len[%d]", len);
+               return;
+       }
+
+       char service_name[VINE_MAX_SERVICE_NAME_LEN + 1];
+       memcpy(service_name, service_specific_info, VINE_MAX_NAN_SERVICE_NAME_LEN);
+       service_name[VINE_MAX_NAN_SERVICE_NAME_LEN] = 0;
+
+       map<string, string> attributes;
+       if (__get_attributes(service_specific_info, len, attributes) == false)
+               return;
+
+       char *mac;
+       int ret = wifi_aware_peer_get_mac(peer, (unsigned char **)&mac);
+       RET_IF(ret != WIFI_AWARE_ERROR_NONE, "wifi_aware_peer_get_mac() fails");
+
        vine_nan_s *nan_handle = (vine_nan_s *)user_data;
+       __add_peer(nan_handle, peer, mac);
+       g_free(mac);
 
-       VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error));
+       event_callbacks.discovered_cb(nan_handle, true,
+               nan_handle->service_type, service_name, nullptr,
+               mac, -1, attributes, nullptr, 0,
+               nan_handle->disc_handle);
+}
+
+/**
+ * When NAN subscription is failed, it is informed with discovered_cb.
+ * If service_type and service_name are nullptr, it is considered as an error.
+ * vine_session_discovered_cb will be called with NULL vine_service_h.
+ */
+static void __subscribe_failed(vine_nan_s *nan_handle)
+{
        if (event_callbacks.discovered_cb) {
                std::map<string, string> empty_map;
                event_callbacks.discovered_cb(nan_handle, false,
-                       nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0, nan_handle->disc_handle);
+                       nullptr, nullptr, nullptr, nullptr, -1, empty_map, nullptr, 0,
+                       nan_handle->disc_handle);
        }
 }
 
+static void __subscribed_cb(wifi_aware_session_h session,
+       wifi_aware_error_e error, void *user_data)
+{
+       RET_IF(error == WIFI_AWARE_ERROR_NONE, "No error");
+
+       VINE_LOGE("Fails to subscribe. error: %s", __convert_nan_error_to_vine_disc_error(error));
+       __subscribe_failed((vine_nan_s *)user_data);
+}
+
 static void __subscribe(vine_nan_s *nan_handle)
 {
        wifi_aware_session_h session;
@@ -207,14 +397,25 @@ static void __subscribe(vine_nan_s *nan_handle)
 
        VINE_LOGD("Subscribe a NAN service");
 
-       ret = wifi_aware_session_subscribe(session, nan_handle->subscribe_config,
-               __subscribed_cb, nan_handle);
+       ret = wifi_aware_session_set_service_discovered_cb(session, __discovered_cb, nan_handle);
+       if (ret != WIFI_AWARE_ERROR_NONE) {
+               VINE_LOGE("wifi_aware_session_publish() fails");
+               goto ERR;
+       }
+
+       ret = wifi_aware_session_subscribe(session,
+                       nan_handle->subscribe_config, __subscribed_cb, nan_handle);
        if (ret != WIFI_AWARE_ERROR_NONE) {
                VINE_LOGE("wifi_aware_session_publish() fails");
-               wifi_aware_session_destroy(session);
+               goto ERR;
        }
 
        nan_handle->session = session;
+       return;
+
+ERR:
+       wifi_aware_session_destroy(session);
+       __subscribe_failed(nan_handle);
 }
 
 static void __start_session(vine_nan_s *nan_handle)
@@ -298,8 +499,6 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type,
        VINE_LOGD("Publish. plugin_handle[%p], service_type[%s], service_name[%s], port[%d]",
                plugin_handle, service_type, service_name, port);
 
-       strncpy(nan_handle->service_name, service_name, VINE_MAX_NAN_SERVICE_NAME_LEN);
-
        wifi_aware_publish_h config = nullptr;
        int ret = wifi_aware_publish_create(&config);
        RET_VAL_IF(ret != WIFI_AWARE_ERROR_NONE, __convert_nan_error_to_vine_disc_error(ret),
@@ -320,8 +519,6 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type,
        }
 
        __fill_specific_info(info, service_name, attributes);
-       nan_handle->publish_config = config;
-       nan_handle->port = port;        // port will be set for NAN data path
 
        ret = wifi_aware_enable(__enabled_cb, nan_handle);
        if (ret != WIFI_AWARE_ERROR_NONE) {
@@ -329,6 +526,10 @@ vine_disc_error nan_publish(void *plugin_handle, const char *service_type,
                goto ERR;
        }
 
+       nan_handle->publish_config = config;
+       nan_handle->port = port;        // port will be set for NAN data path
+       strncpy(nan_handle->published_service_name, service_name, VINE_MAX_SERVICE_NAME_LEN);
+
        return VINE_DISC_ERROR_NONE;
 
 ERR:
index 890b51e..47ebd51 100755 (executable)
@@ -18,3 +18,4 @@
 
 #define NAN_MAX_SERVICE_NAME_LEN 255
 #define MAX_SPECIFIC_INFO_LEN 1024
+#define VINE_FOLLOWUP_MESSAGE "VINE_REQ_NAN_DATAPATH"