#include <string>
#include <map>
+#include <glib.h>
+
#include <wifi-aware.h>
#include <netinet/in.h>
#include <arpa/inet.h>
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;
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,
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)
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)
{
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);
}
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;
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)
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),
}
__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) {
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: