First draft for internal browse/resovle API 94/258894/3 submit/tizen/20210531.043146
authorSeonah Moon <seonah1.moon@samsung.com>
Thu, 27 May 2021 07:52:00 +0000 (16:52 +0900)
committerSeonah Moon <seonah1.moon@samsung.com>
Fri, 28 May 2021 02:21:15 +0000 (11:21 +0900)
Change-Id: Icb7196abdde5e165bcbcb89d46b6cd7f2d9e3754

include/dns-sd-internal.h
packaging/capi-network-nsd.spec
src/dns-sd/dns-sd-util.h
src/dns-sd/dns-sd.c
tests/CMakeLists.txt
tests/dns-sd-internal-test.c [new file with mode: 0644]

index 51c158ae856ff8824d3a53fe6e39c3fa119a7e98..e21c8ba6940894a850e9fa8ebe02249ac12693b5 100644 (file)
@@ -33,6 +33,101 @@ int dnssd_service_set_interface(dnssd_service_h local_service, const char *inter
 int dnssd_start_browsing_service_on_interface(const char *service_type, const char *interface,
                dnssd_browser_h *dnssd_service, dnssd_found_cb found_cb,
                void *user_data);
+
+/**
+ * @brief Browses the services which have @a service_type.
+ * @details @a found_cb will be called whenever a service appear or disapear from the network.
+ *          Application will keep browsing until it calls dnssd_cancel_browse_service().
+ * @since_tizen 6.5
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/internet
+ * @remark dnssd_resolve_service() should be called in @a found_cb
+ *         if you want to get a service data such as a target host name, a port,
+ *         txt record and IP addresses.
+ * @param[in] service_type The DNSSD service type to browse.
+ * @param[out] browser The DNSSD browse service handle
+ * @param[in] found_cb The callback function to be called
+ * @param[in] user_data The user data passed to the callback function
+ * @return @c 0 on success, otherwise negative error value
+ * @retval #DNSSD_ERROR_NONE Successful
+ * @retval #DNSSD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DNSSD_ERROR_NOT_SUPPORTED Not Supported
+ * @retval #DNSSD_ERROR_SERVICE_NOT_RUNNING Service Not Running
+ * @retval #DNSSD_ERROR_NOT_INITIALIZED Not Initialized
+ * @retval #DNSSD_ERROR_PERMISSION_DENIED Permission Denied
+ * see dnssd_cancel_browse_service()
+ */
+int dnssd_browse_service(const char *service_type, const char *interface,
+               dnssd_browser_h *browser, dnssd_found_cb found_cb, void *user_data);
+
+/**
+ * @brief Cancels browsing the services.
+ * @since_tizen 6.5
+ * @param[in] browser The DNSSD browse service handle returned by dnssd_browse_service()
+ * @return @c 0 on success, otherwise negative error value
+ * @retval #DNSSD_ERROR_NONE Successful
+ * @retval #DNSSD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DNSSD_ERROR_NOT_SUPPORTED Not Supported
+ * @retval #DNSSD_ERROR_SERVICE_NOT_RUNNING Service Not Running
+ * @retval #DNSSD_ERROR_NOT_INITIALIZED Not Initialized
+ * see dnssd_browse_service()
+ */
+
+int dnssd_cancel_browse_service(dnssd_browser_h browser);
+
+/**
+ * @brief Called when the service is resolved.
+ * @since_tizen 6.5
+ * @param[in] result The result of resolving.
+ * @param[in] service The resolved service.
+ * @param[in] user_data The user data passed from the request function
+ * @see dnssd_resolve_service()
+ */
+typedef void (*dnssd_resolved_cb) (dnssd_error_e result,
+               dnssd_service_h service, void *user_data);
+
+/**
+ * @brief Resolves a service browsed by dnssd_browse_service().
+ * @details @a resolved_cb will be called whenever a service is resolved.
+ *         You can get a target host name, a port, txt record and IP addresses
+ *         from @a resolved_cb. If you have gotten the desired results,
+ *         cancel resolving service using dnssd_cancel_resolve_service().
+ * @since_tizen 6.5
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/internet
+ * @param[in] service The DNSSD service handle
+ * @param[in] resolved_cb The callback function to be called
+ * @param[in] user_data The user data passed to the callback function
+ * @return @c 0 on success, otherwise negative error value
+ * @retval #DNSSD_ERROR_NONE Successful
+ * @retval #DNSSD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DNSSD_ERROR_NOT_SUPPORTED Not Supported
+ * @retval #DNSSD_ERROR_SERVICE_NOT_RUNNING Service Not Running
+ * @retval #DNSSD_ERROR_NOT_INITIALIZED Not Initialized
+ * @retval #DNSSD_ERROR_PERMISSION_DENIED Permission Denied
+ * @see dnssd_browse_service()
+ * @see dnssd_cancel_resolve_service()
+ */
+int dnssd_resolve_service(dnssd_service_h service,
+               dnssd_resolved_cb resolved_cb, void *user_data);
+
+/**
+ * @brief Cancels resolving a service.
+ * @since_tizen 6.5
+ * @privlevel public
+ * @privilege %http://tizen.org/privilege/internet
+ * @param[in] service The DNSSD service handle
+ * @return @c 0 on success, otherwise negative error value
+ * @retval #DNSSD_ERROR_NONE Successful
+ * @retval #DNSSD_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #DNSSD_ERROR_NOT_SUPPORTED Not Supported
+ * @retval #DNSSD_ERROR_SERVICE_NOT_RUNNING Service Not Running
+ * @retval #DNSSD_ERROR_NOT_INITIALIZED Not Initialized
+ * @retval #DNSSD_ERROR_PERMISSION_DENIED Permission Denied
+ * @see dnssd_resolve_service()
+ */
+int dnssd_cancel_resolve_service(dnssd_service_h service);
+
 #ifdef __cplusplus
 }
 #endif
index 589cba0ba099ecf9bd4bf10478467ea12d12394e..61c485cb6fd0e2753cd93136457e65b28aa1249e 100644 (file)
@@ -133,6 +133,7 @@ genhtml nsd.info -o out --legend --show-details
 %files tests
 %manifest nsd-tests.manifest
 %attr(755,root,root) %{_bindir}/dns-sd-test
+%attr(755,root,root) %{_bindir}/dns-sd-internal-test
 %attr(755,root,root) %{_bindir}/ssdp-test
 %attr(755,root,root) %{_bindir}/tct-nsd-core
 
index 4ef9f77f92d9f2389c248175cd3df3f530f629f4..e2af923a572226ad2601feefcd5d7bc8d432552a 100644 (file)
@@ -20,6 +20,7 @@
 #include <dlog.h>
 #include <dns_sd.h>
 #include <dns-sd.h>
+#include <dns-sd-internal.h>
 #include <system_info.h>
 
 #ifdef USE_DLOG
@@ -95,6 +96,7 @@ typedef enum {
        DNSSD_TYPE_REGISTER = 1 /**<DNS-SD service type register */,
        DNSSD_TYPE_BROWSE = 2   /**<DNS-SD service type browse */,
        DNSSD_TYPE_FOUND = 3    /**<DNS-SD service type found */,
+       DNSSD_TYPE_FOUND_NOT_RESOLVED = 4 /**<DNS-SD service type found but not resolved */,
 } dnssd_type_e;
 
 typedef struct _dnssd_found_data_s {
@@ -107,6 +109,11 @@ typedef struct _dnssd_found_data_s {
        unsigned int if_index;
        unsigned char ip_v4_addr[IPV4_LEN];
        unsigned char ip_v6_addr[IPV6_LEN];
+       union {
+               dnssd_found_cb found_cb;
+               dnssd_resolved_cb resolved_cb;
+       } callback;
+       void *user_data;
 } dnssd_found_data_s;
 
 typedef struct _dnssd_register_data_s {
index 3e784d6e256555513cea0734a9d03147d77a21e4..66101efdb05aaf998550f927b192872f95e2f427 100644 (file)
@@ -33,6 +33,8 @@
 #define GET_REG_DATA_P(a) ((dnssd_register_data_s *)((a)->data))
 #define GET_BROWSE_DATA_P(a) ((dnssd_browse_data_s *)((a)->data))
 #define GET_FOUND_DATA_P(a) ((dnssd_found_data_s *)((a)->data))
+#define INT_TO_POINTER(i) ((void *) (glong) (i))
+#define POINTER_TO_INT(p) ((gint)  (glong) (p))
 
 #define REG_SIZE (sizeof(dnssd_handle_s) + sizeof(dnssd_register_data_s))
 #define BROWSE_SIZE (sizeof(dnssd_handle_s) + sizeof(dnssd_browse_data_s))
@@ -1077,6 +1079,25 @@ static gboolean __remove_service_getaddrinfo_socket(gpointer user_data)
        return FALSE;
 }
 
+static void __update_found_address(const struct sockaddr *address, dnssd_found_data_s *found)
+{
+       if (!address || !found)
+               return;
+
+       if (address->sa_family == AF_INET) {
+               const unsigned char *addr =
+                       (const unsigned char *) &
+                       ((struct sockaddr_in *)address)->sin_addr;
+               memcpy(&(found->ip_v4_addr), addr, IPV4_LEN);
+       } else if (address->sa_family == AF_INET6) {
+               const struct sockaddr_in6 *s6 =
+                       (const struct sockaddr_in6 *)address;
+               const unsigned char *addr =
+                       (const unsigned char *)&s6->sin6_addr;
+               memcpy(&(found->ip_v6_addr), addr, IPV6_LEN);
+       }
+}
+
 static void __dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref,
                unsigned int flags, unsigned int if_index,
                DNSServiceErrorType error_code, const char *host_name,
@@ -1086,10 +1107,8 @@ static void __dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref,
        DNSSD_LOCK;
        dnssd_handle_s *dnssd_handle = NULL;
        dnssd_handle_s *local_handle = NULL;
-       dnssd_browse_data_s *browse = NULL;
        dnssd_found_data_s *found = NULL;
-       dnssd_found_cb callback;
-       void *data;
+       dnssd_service_state_e service_state;
 
        if (user_data == NULL) {
                DNSSD_LOGD("Invalid found handle");
@@ -1117,24 +1136,7 @@ static void __dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref,
        DNSSD_LOGD("GetAddrInfo Callback set for [%p]",
                        dnssd_handle);
 
-       browse = GET_BROWSE_DATA_P(dnssd_handle);
-       callback = browse->callback;
-       data = browse->user_data;
-
-       if (address && address->sa_family == AF_INET) {
-
-               const unsigned char *addr =
-                       (const unsigned char *) &
-                       ((struct sockaddr_in *)address)->sin_addr;
-               memcpy(&(found->ip_v4_addr), addr, IPV4_LEN);
-       } else if (address && address->sa_family == AF_INET6) {
-
-               const struct sockaddr_in6 *s6 =
-                       (const struct sockaddr_in6 *)address;
-               const unsigned char *addr =
-                       (const unsigned char *)&s6->sin6_addr;
-               memcpy(&(found->ip_v6_addr), addr, IPV6_LEN);
-       }
+       __update_found_address(address, found);
 
        if (flags & kDNSServiceFlagsMoreComing) {
                DNSSD_LOGD("More results are queued, No need to send callback to "
@@ -1144,67 +1146,46 @@ static void __dnssd_getaddrinfo_reply_cb(DNSServiceRef sd_ref,
                return;
        }
 
-       if (callback) {
-               if (flags & kDNSServiceFlagsAdd)
-                       callback(DNSSD_SERVICE_STATE_AVAILABLE,
-                                       local_handle->service_handler, data);
-               else
-                       callback(DNSSD_SERVICE_STATE_UNAVAILABLE,
-                                       local_handle->service_handler, data);
+       if(local_handle->op_type == DNSSD_TYPE_FOUND_NOT_RESOLVED) {
+               local_handle->op_type = DNSSD_TYPE_FOUND;
+               found->callback.resolved_cb(DNSSD_ERROR_NONE,
+                               local_handle->service_handler, found->user_data);
+               DNSSD_LOGD("Finished executing Resolve callback");
+       } else {
+               service_state = (flags & kDNSServiceFlagsAdd) ? DNSSD_SERVICE_STATE_AVAILABLE
+                       : DNSSD_SERVICE_STATE_UNAVAILABLE;
+               found->callback.found_cb(service_state, local_handle->service_handler, found->user_data);
                DNSSD_LOGD("Finished executing Browse %s callback",
                                (flags & kDNSServiceFlagsAdd) ? "Available" : "Unavailable");
        }
+
        g_idle_add_full(G_PRIORITY_HIGH, __remove_service_getaddrinfo_socket,
                                        local_handle, NULL);
        DNSSD_UNLOCK;
 }
 
-static int __dnssd_getaddrinfo(dnssd_handle_s *dnssd_handle, unsigned int flags,
-               unsigned int if_index, const char *host_name, char *service_name,
-               const char *fullname, const char *txt_record,
-               unsigned short txt_len, int port)
+static dnssd_handle_s *__create_found_service(dnssd_handle_s *dnssd_handle, dnssd_type_e op_type,
+               unsigned int flags, unsigned int if_index,
+               const char *host_name, const char *service_name, const char *domain, int port,
+               const char *txt_record, unsigned short txt_len)
 {
-       DNSServiceErrorType ret;
-       dnssd_handle_s *local_handle = NULL;
-       dnssd_found_data_s *found = NULL;
-       char *name;
-       char *domain;
-       char *save_str = NULL;
-       int dns_protocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
-
-       if (dnssd_handle == NULL) {
-               DNSSD_LOGD("Invalid browse handle");
-               __DNSSD_LOG_FUNC_EXIT__;
-               return DNSSD_ERROR_OUT_OF_MEMORY;
-       }
+       if (dnssd_handle == NULL)
+               return NULL;
 
-       /* fullname is of the form <servicename>.<protocol>.<domain>
-        * Extract servicename and domain from fullname */
-       name = g_strdup(fullname);
-       if (name == NULL) {
-               DNSSD_LOGE("Invalid browse handle");
-               return DNSSD_ERROR_OPERATION_FAILED;
-       }
-       domain = strtok_r(name, ".", &save_str);
-       domain = strtok_r(NULL, ".", &save_str);
-       domain = strtok_r(NULL, ".", &save_str);
-       domain = strtok_r(NULL, ".", &save_str);
-
-       local_handle = g_try_malloc0(FOUND_SIZE);
+       dnssd_found_data_s *found = NULL;
+       dnssd_handle_s *local_handle = g_try_malloc0(FOUND_SIZE);
        if (local_handle == NULL) {
                DNSSD_LOGD("g_try_malloc failed");
-               g_free(name);
                __DNSSD_LOG_FUNC_EXIT__;
-               return DNSSD_ERROR_OUT_OF_MEMORY;
+               return NULL;
        }
 
        found = GET_FOUND_DATA_P(local_handle);
 
-       local_handle->op_type = DNSSD_TYPE_FOUND;
+       local_handle->op_type = op_type;
        local_handle->service_handler = (uintptr_t)local_handle & 0xffffffff;
        if (domain)
                g_strlcpy(local_handle->domain, domain, sizeof(local_handle->domain));
-       g_free(name);
 
        found->if_index = if_index;
        local_handle->flags = flags;
@@ -1221,12 +1202,72 @@ static int __dnssd_getaddrinfo(dnssd_handle_s *dnssd_handle, unsigned int flags,
        found->host = g_strdup(host_name);
        found->port = (int)ntohs(port);
 
-       DNSSD_LOGD("Create found handle [%u]", local_handle->service_handler);
+       dnssd_browse_data_s *browse = GET_BROWSE_DATA_P(dnssd_handle);
+       if (browse) {
+               found->callback.found_cb = browse->callback;
+               found->user_data = browse->user_data;
+       }
 
+       DNSSD_LOGD("Create found handle [%u]", local_handle->service_handler);
        dnssd_handle_list = g_slist_prepend(dnssd_handle_list, local_handle);
-
        DNSSD_LOGD("g_slist length [%d]", g_slist_length(dnssd_handle_list));
 
+       return local_handle;
+}
+
+/* fullname is of the form <servicename>.<protocol>.<domain>
+        * Extract servicename and domain from fullname */
+static void __extract_domain_from_name(const char *fullname, char **domain)
+{
+       char *name = NULL;
+       char *save_str = NULL;
+
+       name = g_strdup(fullname);
+       if (name == NULL)
+               return;
+
+       *domain = strtok_r(name, ".", &save_str);
+       *domain = strtok_r(NULL, ".", &save_str);
+       *domain = strtok_r(NULL, ".", &save_str);
+       *domain = strtok_r(NULL, ".", &save_str);
+}
+
+static int __dnssd_getaddrinfo(dnssd_handle_s *dnssd_handle, unsigned int flags,
+               unsigned int if_index, const char *host_name, char *service_name,
+               const char *fullname, const char *txt_record,
+               unsigned short txt_len, int port)
+{
+       DNSServiceErrorType ret;
+       dnssd_handle_s *local_handle = NULL;
+       char *domain = NULL;
+       int dns_protocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+
+       if (dnssd_handle == NULL) {
+               DNSSD_LOGD("Invalid browse handle");
+               __DNSSD_LOG_FUNC_EXIT__;
+               return DNSSD_ERROR_OUT_OF_MEMORY;
+       }
+
+       DNSSD_LOGD("dnssd_handle[%p] optype[%d]", dnssd_handle, dnssd_handle->op_type);
+       if (dnssd_handle->op_type == DNSSD_TYPE_BROWSE) {
+               __extract_domain_from_name(fullname, &domain);
+               local_handle = __create_found_service(dnssd_handle, DNSSD_TYPE_FOUND,
+                               flags, if_index, host_name, service_name, domain, port,
+                               txt_record, txt_len);
+       } else if (dnssd_handle->op_type == DNSSD_TYPE_FOUND_NOT_RESOLVED) {
+               local_handle = dnssd_handle;
+               dnssd_found_data_s *found = GET_FOUND_DATA_P(local_handle);
+               found->port = (int)ntohs(port);
+       } else {
+               DNSSD_LOGE("Invalid op_type[%d].", dnssd_handle->op_type);
+               return DNSSD_ERROR_OPERATION_FAILED;
+       }
+
+       if (!local_handle) {
+               DNSSD_LOGE("Failed to get local_handle");
+               return DNSSD_ERROR_OUT_OF_MEMORY;
+       }
+
        ret = DNSServiceGetAddrInfo(&(local_handle->sd_ref), flags, if_index,
                        dns_protocol, host_name,
                        __dnssd_getaddrinfo_reply_cb, local_handle);
@@ -1301,7 +1342,6 @@ static int __dnssd_resolve_dns_service(dnssd_handle_s *dnssd_handle,
        data->dnssd_handle = dnssd_handle;
        data->watch_id = 0;
        data->service_name = g_strdup(service_name);
-
        resolve_handle_list = g_slist_prepend(resolve_handle_list, data);
 
        ret = DNSServiceResolve(&(data->sd_ref), flags, if_index, service_name,
@@ -1365,6 +1405,8 @@ static void __dnssd_browse_reply_cb(DNSServiceRef sd_ref, unsigned int flags,
        GSList *list;
        void *data;
 
+       int do_resolving = POINTER_TO_INT(user_data);
+
        DNSSD_LOGD("Received Browse Reply");
 
        if (error_code != kDNSServiceErr_NoError) {
@@ -1394,11 +1436,22 @@ static void __dnssd_browse_reply_cb(DNSServiceRef sd_ref, unsigned int flags,
 
                        if (flags & kDNSServiceFlagsAdd) {
                                /* Resolve address and send callback later */
-                               __dnssd_resolve_dns_service(dnssd_handle, flags,
-                                               if_index, service_name,
-                                               service_type, domain);
+                               if (do_resolving) {
+                                       __dnssd_resolve_dns_service(dnssd_handle, flags,
+                                                       if_index, service_name,
+                                                       service_type, domain);
+                               } else {
+                                       dnssd_browse_data_s *browse = GET_BROWSE_DATA_P(dnssd_handle);
+                                       if (browse->callback) {
+                                               dnssd_handle_s *found_service = __create_found_service(dnssd_handle,
+                                                               DNSSD_TYPE_FOUND_NOT_RESOLVED, flags,
+                                                               if_index, NULL, service_name, domain, -1, NULL, 0);
+                                               if (found_service)
+                                                       browse->callback(DNSSD_SERVICE_STATE_AVAILABLE,
+                                                                       (dnssd_service_h)found_service, browse->user_data);
+                                       }
+                               }
                        } else {
-
                                dnssd_browse_data_s *browse = NULL;
                                dnssd_found_cb callback;
                                dnssd_handle_s *found_handle;
@@ -1424,25 +1477,24 @@ static void __dnssd_browse_reply_cb(DNSServiceRef sd_ref, unsigned int flags,
        __DNSSD_LOG_FUNC_EXIT__;
 }
 
-EXPORT_API int dnssd_start_browsing_service(const char *service_type,
-               dnssd_browser_h *dnssd_service, dnssd_found_cb found_cb,
-               void *user_data)
+static int _dnssd_browse_service(const char *service_type, const char *interface, int do_resolving,
+               dnssd_browser_h *browser, dnssd_found_cb found_cb, void *user_data)
 {
        __DNSSD_LOG_FUNC_ENTER__;
        DNSServiceErrorType ret;
        dnssd_handle_s *local_handle;
        dnssd_browse_data_s *browse;
        unsigned int handler;
+       unsigned int if_index;
 
        CHECK_FEATURE_SUPPORTED(NETWORK_SERVICE_DISCOVERY_FEATURE);
        DNSSD_LOCK;
 
        CHECK_PERMISSION();
-
        CHECK_INITIALIZED();
 
-       if (found_cb == NULL || dnssd_service == NULL || service_type == NULL ||
-                       __dnssd_get_struct_from_handle(*dnssd_service) != NULL) {
+       if (found_cb == NULL || browser == NULL || service_type == NULL ||
+                       __dnssd_get_struct_from_handle(*browser) != NULL) {
                DNSSD_LOGE("Invalid Parameter");
                DNSSD_UNLOCK;
                __DNSSD_LOG_FUNC_EXIT__;
@@ -1457,8 +1509,19 @@ EXPORT_API int dnssd_start_browsing_service(const char *service_type,
                return DNSSD_ERROR_OUT_OF_MEMORY;       //LCOV_EXCL_LINE
        }
 
+       if (interface && (if_index = if_nametoindex(interface)) == 0) {
+               DNSSD_LOGE("Invalid interface name");
+               g_free(local_handle);
+               DNSSD_UNLOCK;
+               __DNSSD_LOG_FUNC_EXIT__;
+               return DNSSD_ERROR_INVALID_PARAMETER;
+       } else {
+               if_index = kDNSServiceInterfaceIndexAny;
+       }
+       DNSSD_LOGD("Interface index: %u", if_index);
+
        handler = (uintptr_t)local_handle & 0xffffffff;
-       *dnssd_service = handler;
+       *browser = handler;
        local_handle->service_handler = handler;
        local_handle->op_type = DNSSD_TYPE_BROWSE;
        local_handle->service_type = g_strdup(service_type);
@@ -1468,12 +1531,12 @@ EXPORT_API int dnssd_start_browsing_service(const char *service_type,
        browse = GET_BROWSE_DATA_P(local_handle);
 
        DNSSD_LOGD("New browse handle created [%p]->[%u] type %s", local_handle,
-                       *dnssd_service, local_handle->service_type);
+                       *browser, local_handle->service_type);
 
        ret = DNSServiceBrowse(&(local_handle->sd_ref), local_handle->flags,
-                       kDNSServiceInterfaceIndexAny, local_handle->service_type,
+                       if_index, local_handle->service_type,
                        local_handle->domain, __dnssd_browse_reply_cb,
-                       NULL);
+                       INT_TO_POINTER(do_resolving));
        if (ret != kDNSServiceErr_NoError) {
                DNSSD_LOGE("Failed to browse for dns service, error[%s]",       //LCOV_EXCL_LINE
                                dnssd_error_to_string(ret));    //LCOV_EXCL_LINE
@@ -1495,84 +1558,81 @@ EXPORT_API int dnssd_start_browsing_service(const char *service_type,
        return DNSSD_ERROR_NONE;
 }
 
+EXPORT_API int dnssd_start_browsing_service(const char *service_type,
+               dnssd_browser_h *dnssd_service, dnssd_found_cb found_cb,
+               void *user_data)
+{
+       return _dnssd_browse_service(service_type, NULL, 1, dnssd_service, found_cb, user_data);
+}
+
 EXPORT_API int dnssd_start_browsing_service_on_interface(const char *service_type, const char *interface,
                dnssd_browser_h *dnssd_service, dnssd_found_cb found_cb,
                void *user_data)
+{
+       if (interface == NULL)
+               return DNSSD_ERROR_INVALID_PARAMETER;
+
+       return _dnssd_browse_service(service_type, interface, 1, dnssd_service, found_cb, user_data);
+}
+
+EXPORT_API int dnssd_browse_service(const char *service_type, const char *interface,
+               dnssd_browser_h *browser, dnssd_found_cb found_cb, void *user_data)
+{
+       return _dnssd_browse_service(service_type, interface, 0, browser, found_cb, user_data);
+}
+
+EXPORT_API int dnssd_cancel_browse_service(dnssd_browser_h browser)
+{
+       return DNSSD_ERROR_NONE;
+}
+
+static int _dnssd_resolve_service(dnssd_handle_s *local_handle,
+               dnssd_resolved_cb resolved_cb, void *user_data)
+{
+       dnssd_found_data_s *found = GET_FOUND_DATA_P(local_handle);
+       if (!found)
+               return DNSSD_ERROR_OPERATION_FAILED;
+
+       found->callback.resolved_cb = resolved_cb;
+       found->user_data = user_data;
+
+       return __dnssd_resolve_dns_service(local_handle, local_handle->flags, found->if_index,
+                       found->service_name, local_handle->service_type, local_handle->domain);
+}
+
+EXPORT_API int dnssd_resolve_service(dnssd_service_h service,
+               dnssd_resolved_cb resolved_cb, void *user_data)
 {
        __DNSSD_LOG_FUNC_ENTER__;
-       DNSServiceErrorType ret;
-       dnssd_handle_s *local_handle;
-       dnssd_browse_data_s *browse;
-       unsigned int handler;
-       unsigned int if_index;
+       dnssd_handle_s *local_handle = NULL;
+       int res = DNSSD_ERROR_NONE;
 
        CHECK_FEATURE_SUPPORTED(NETWORK_SERVICE_DISCOVERY_FEATURE);
        DNSSD_LOCK;
 
-       CHECK_PERMISSION();
-
        CHECK_INITIALIZED();
 
-       if (found_cb == NULL || dnssd_service == NULL || service_type == NULL ||
-                       __dnssd_get_struct_from_handle(*dnssd_service) != NULL) {
-               DNSSD_LOGE("Invalid Parameter");
-               DNSSD_UNLOCK;
-               __DNSSD_LOG_FUNC_EXIT__;
-               return DNSSD_ERROR_INVALID_PARAMETER;
-       }
-
-       local_handle = (dnssd_handle_s *)g_try_malloc0(BROWSE_SIZE);
-       if (local_handle == NULL) {
-               DNSSD_LOGE("Failed to Allocate Memory");        //LCOV_EXCL_LINE
-               DNSSD_UNLOCK;
-               __DNSSD_LOG_FUNC_EXIT__;        //LCOV_EXCL_LINE
-               return DNSSD_ERROR_OUT_OF_MEMORY;       //LCOV_EXCL_LINE
-       }
-
-       if ((if_index = if_nametoindex(interface)) == 0) {
-               DNSSD_LOGE("Invalid interface name");
-               g_free(local_handle);
+       res = __get_valid_handle(service, &local_handle);
+       if (res != DNSSD_ERROR_NONE) {
                DNSSD_UNLOCK;
-               __DNSSD_LOG_FUNC_EXIT__;
-               return DNSSD_ERROR_INVALID_PARAMETER;
+               return res;
        }
-       DNSSD_LOGD("Interface index: %u", if_index);
-
-       handler = (uintptr_t)local_handle & 0xffffffff;
-       *dnssd_service = handler;
-       local_handle->service_handler = handler;
-       local_handle->op_type = DNSSD_TYPE_BROWSE;
-       local_handle->service_type = g_strdup(service_type);
-       g_strlcpy(local_handle->domain, "", sizeof(local_handle->domain));
-       local_handle->flags = 0;
-       local_handle->watch_id = 0;
-       browse = GET_BROWSE_DATA_P(local_handle);
 
-       DNSSD_LOGD("New browse handle created [%p]->[%u] type %s", local_handle,
-                       *dnssd_service, local_handle->service_type);
-
-       ret = DNSServiceBrowse(&(local_handle->sd_ref), local_handle->flags,
-                       if_index, local_handle->service_type,
-                       local_handle->domain, __dnssd_browse_reply_cb,
-                       NULL);
-       if (ret != kDNSServiceErr_NoError) {
-               DNSSD_LOGE("Failed to browse for dns service, error[%s]",       //LCOV_EXCL_LINE
-                               dnssd_error_to_string(ret));    //LCOV_EXCL_LINE
-               g_free(local_handle->service_type);     //LCOV_EXCL_LINE
-               g_free(local_handle);   //LCOV_EXCL_LINE
+       if (local_handle->op_type != DNSSD_TYPE_FOUND_NOT_RESOLVED) {
+               DNSSD_LOGD("Not matched type. [%d]", local_handle->op_type);
                DNSSD_UNLOCK;
-               __DNSSD_LOG_FUNC_EXIT__;        //LCOV_EXCL_LINE
-               return DNSSD_ERROR_OPERATION_FAILED;    //LCOV_EXCL_LINE
+               return DNSSD_ERROR_OPERATION_FAILED;
        }
 
-       browse->callback = found_cb;
-       browse->user_data = user_data;
-       dnssd_handle_list = g_slist_prepend(dnssd_handle_list, local_handle);
-       __dnssd_handle_add_event_handler(&(local_handle->watch_id), local_handle);
+       res = _dnssd_resolve_service(local_handle, resolved_cb, user_data);
 
-       DNSSD_LOGD("Succeeded to browse for dns service");
        DNSSD_UNLOCK;
        __DNSSD_LOG_FUNC_EXIT__;
+       return res;
+}
+
+EXPORT_API int dnssd_cancel_resolve_service(dnssd_service_h service)
+{
        return DNSSD_ERROR_NONE;
 }
 
index 4b48f7dffaef2cd0c1abec565c7d292529fd0ced..a4667ac1e08bed5bd8cef9571a39522149a25363 100644 (file)
@@ -41,6 +41,7 @@ ENDFOREACH()
 
 #Install
 INSTALL(TARGETS dns-sd-test RUNTIME DESTINATION ${BIN_DIR})
+INSTALL(TARGETS dns-sd-internal-test RUNTIME DESTINATION ${BIN_DIR})
 INSTALL(TARGETS ssdp-test RUNTIME DESTINATION ${BIN_DIR})
 
 SET(UNITTEST_NAME "tct-nsd-core")
diff --git a/tests/dns-sd-internal-test.c b/tests/dns-sd-internal-test.c
new file mode 100644 (file)
index 0000000..f70a227
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+* Copyright (c) 2021 Samsung Electronics Co., Ltd.
+*
+* 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.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib.h>
+
+#include "dns-sd.h"
+#include "dns-sd-internal.h"
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data);
+
+static bool test_get_user_string(const char *msg, char *buf, int buf_size)
+{
+       if (msg == NULL || buf == NULL || buf_size < 2)
+               return false;
+
+       int i = 0, c;
+       printf("%s\n", msg);
+       memset(buf, 0, buf_size);
+       while (true) {
+               c = getchar();
+               if (i == 0 && c == '\n')
+                       continue;
+
+               if (c == '\n' || c == EOF)
+                       break;
+
+               buf[i++] = c;
+               if (i == buf_size-1)
+                       break;
+       }
+
+       buf[i] = '\0';
+       return true;
+}
+
+static const char *dnssd_error_to_string(dnssd_error_e error)
+{
+       switch (error) {
+       case DNSSD_ERROR_NONE:
+               return "DNSSD_ERROR_NONE";
+       case DNSSD_ERROR_OUT_OF_MEMORY:
+               return "DNSSD_ERROR_OUT_OF_MEMORY";
+       case DNSSD_ERROR_INVALID_PARAMETER:
+               return "DNSSD_ERROR_INVALID_PARAMETER";
+       case DNSSD_ERROR_NOT_SUPPORTED:
+               return "DNSSD_ERROR_NOT_SUPPORTED";
+       case DNSSD_ERROR_NOT_INITIALIZED:
+               return "DNSSD_ERROR_NOT_INITIALIZED";
+       case DNSSD_ERROR_ALREADY_REGISTERED:
+               return "DNSSD_ERROR_ALREADY_REGISTERED";
+       case DNSSD_ERROR_NAME_CONFLICT:
+               return "DNSSD_ERROR_NAME_CONFLICT";
+       case DNSSD_ERROR_SERVICE_NOT_RUNNING:
+               return "DNSSD_ERROR_SERVICE_NOT_RUNNING";
+       case DNSSD_ERROR_OPERATION_FAILED:
+               return "DNSSD_ERROR_OPERATION_FAILED";
+       default:
+               return "UNSUPPORTED_ERROR";
+       }
+}
+
+static void show_txt_record(unsigned short txt_len, const unsigned char *txt_record)
+{
+       const unsigned char *ptr = txt_record;
+       const unsigned char *max = txt_record + txt_len;
+       while (ptr < max) {
+               const unsigned char *const end = ptr + 1 + ptr[0];
+               if (end > max) {
+                       printf("<< invalid data >>");
+                       break;
+               }
+               if (++ptr < end)
+                       printf(" ");   /* As long as string is non-empty, begin with a space */
+               while (ptr < end) {
+                       if (strchr(" &;`'\"|*?~<>^()[]{}$", *ptr))
+                               printf("\\");
+                       if (*ptr == '\\')
+                               printf("\\\\\\\\");
+                       else if (*ptr >= ' ')
+                               printf("%c", *ptr);
+                       else
+                               printf("\\\\x%02X", *ptr);
+                       ptr++;
+               }
+       }
+       printf("\n");
+}
+
+static void _resolve_cb(dnssd_error_e result, dnssd_service_h service, void *user_data)
+{
+       char *name = NULL;
+       char *type = NULL;
+       char *ip_v4_address = NULL;
+       char *ip_v6_address = NULL;
+       unsigned char *txt_record = NULL;
+       unsigned short txt_len = 0;
+       int port = 0;
+
+       printf("Resolve Service Callback\n");
+       int rv = dnssd_service_get_name(service, &name);
+       if (rv == DNSSD_ERROR_NONE && name != NULL)
+               printf("Service Name  : %s\n", name);
+
+       rv = dnssd_service_get_type(service, &type);
+       if (rv == DNSSD_ERROR_NONE && type != NULL)
+               printf("Service Type  : %s\n", type);
+
+       rv = dnssd_service_get_ip(service, &ip_v4_address, &ip_v6_address);
+       if (rv  == DNSSD_ERROR_NONE) {
+               if (ip_v4_address)
+                       printf("IPv4 Address  : %s\n", ip_v4_address);
+               if (ip_v6_address)
+                       printf("IPv6 Address  : %s\n", ip_v6_address);
+       }
+
+       rv = dnssd_service_get_port(service, &port);
+       printf("Port          : %d\n", port);
+
+       printf("TXT Record    : ");
+       dnssd_service_get_all_txt_record(service, &txt_len,
+                       (void *)&txt_record);
+       show_txt_record(txt_len, txt_record);
+       printf("\n");
+
+       g_free(ip_v4_address);
+       g_free(ip_v6_address);
+       g_free(txt_record);
+       g_free(name);
+       g_free(type);
+}
+
+static void _browse_cb(dnssd_service_state_e service_state,
+               dnssd_service_h service, void *user_data)
+{
+       printf("Browse Service Callback\n");
+       printf("Handler       : %u\n", service);
+       printf("State         : ");
+       switch (service_state) {
+       case DNSSD_SERVICE_STATE_AVAILABLE:
+               printf("Available\n");
+               break;
+       case DNSSD_SERVICE_STATE_UNAVAILABLE:
+               printf("Un-Available\n");
+               break;
+       case DNSSD_SERVICE_STATE_NAME_LOOKUP_FAILED:
+               printf("Lookup failure for service name\n");
+               break;
+       case DNSSD_SERVICE_STATE_HOST_NAME_LOOKUP_FAILED:
+               printf("Lookup failure for host name and port number\n");
+               break;
+       case DNSSD_SERVICE_STATE_ADDRESS_LOOKUP_FAILED:
+               printf("Lookup failure for IP address\n");
+               break;
+       default:
+               printf("Unknown Browse State\n");
+               break;
+       }
+
+       if (service_state == DNSSD_SERVICE_STATE_AVAILABLE) {
+               int rv = dnssd_resolve_service(service, _resolve_cb, NULL);
+               if (rv != DNSSD_ERROR_NONE)
+                       printf("Failed to resolve a service.\n");
+       }
+       printf("\n");
+}
+
+int test_dnssd_browse_service()
+{
+       dnssd_service_h service = 0;
+       char service_type[255];
+       int rv;
+
+       printf("Browse DNS Service\n");
+       test_get_user_string("Enter type:(Example : _http._tcp, "
+                       "_printer._tcp etc)", service_type, 255);
+
+       rv = dnssd_browse_service(service_type, NULL, &service, _browse_cb, NULL);
+       if (rv != DNSSD_ERROR_NONE) {
+               printf("Failed to browse for dns service, error %s",
+                               dnssd_error_to_string(rv));
+               return 0;
+       }
+
+       printf("Succeeded to browse for dns service[%u]\n", service);
+       return 1;
+}
+
+int test_dnssd_cancel_browse_service()
+{
+       dnssd_browser_h browser;
+       int rv;
+       printf("Enter Browse Service Handle:\n");
+       rv = scanf("%u", &browser);
+
+       rv = dnssd_cancel_browse_service(browser);
+       if (rv != DNSSD_ERROR_NONE) {
+               printf("Failed to stop browse dns service %s\n",
+                               dnssd_error_to_string(rv));
+               return 0;
+       }
+       printf("Successfully stopped browsing dns service\n");
+       return 1;
+}
+
+static void MenuScreen()
+{
+       printf("_____________________________________\n");
+       printf("|_____________MENU-SCREEN___________|\n");
+       printf("| 0 - EXIT                          |\n");
+       printf("| 1 - Browse DNS Service            |\n");
+       printf("| 2 - Cancel Browse DNS Service     |\n");
+       printf("|___________________________________|\n");
+}
+
+int test_thread(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+       int rv;
+       char a[10];
+       GMainLoop *mainloop = data;
+
+       printf("Event received from stdin\n");
+
+       rv = read(0, a, 10);
+       if (rv <= 0 || a[0] == '0') {
+               printf("Terminating  Test Application");
+               g_main_loop_quit(mainloop);
+               rv = 1;
+       }
+
+       if (a[0] == '\n' || a[0] == '\r') {
+               printf("\n\n mDNSResponder Test App\n\n");
+               printf("Options..\n");
+               MenuScreen();
+               printf("Press ENTER to show options menu.......\n");
+       }
+
+       switch (a[0]) {
+       case '1':
+               rv = test_dnssd_browse_service();
+               break;
+       case '2':
+               rv = test_dnssd_cancel_browse_service();
+               break;
+       }
+
+       if (rv == 1)
+               printf("\nOperation Succeeded!\n");
+       else
+               printf("\nOperation Failed!\n");
+
+       return TRUE;
+
+}
+
+int main(int argc, char **argv)
+{
+       GMainLoop *mainloop;
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       GIOChannel *channel = g_io_channel_unix_new(0);
+       g_io_add_watch(channel, (G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),
+                       test_thread, mainloop);
+
+       printf("Test Thread created...\n");
+
+       dnssd_initialize();
+
+       g_main_loop_run(mainloop);
+
+       dnssd_deinitialize();
+       printf("Test Application Terminated\n");
+       g_main_loop_unref(mainloop);
+
+       return 0;
+}