From: Seonah Moon Date: Thu, 27 May 2021 07:52:00 +0000 (+0900) Subject: First draft for internal browse/resovle API X-Git-Tag: submit/tizen/20210531.043146^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=0c1824c661f4ce66cbfe92f059b3f63c3640871f;p=platform%2Fcore%2Fapi%2Fnsd.git First draft for internal browse/resovle API Change-Id: Icb7196abdde5e165bcbcb89d46b6cd7f2d9e3754 --- diff --git a/include/dns-sd-internal.h b/include/dns-sd-internal.h index 51c158a..e21c8ba 100644 --- a/include/dns-sd-internal.h +++ b/include/dns-sd-internal.h @@ -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 diff --git a/packaging/capi-network-nsd.spec b/packaging/capi-network-nsd.spec index 589cba0..61c485c 100644 --- a/packaging/capi-network-nsd.spec +++ b/packaging/capi-network-nsd.spec @@ -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 diff --git a/src/dns-sd/dns-sd-util.h b/src/dns-sd/dns-sd-util.h index 4ef9f77..e2af923 100644 --- a/src/dns-sd/dns-sd-util.h +++ b/src/dns-sd/dns-sd-util.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #ifdef USE_DLOG @@ -95,6 +96,7 @@ typedef enum { DNSSD_TYPE_REGISTER = 1 /**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 .. - * 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 .. + * 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; } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4b48f7d..a4667ac 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -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 index 0000000..f70a227 --- /dev/null +++ b/tests/dns-sd-internal-test.c @@ -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 +#include +#include +#include +#include + +#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; +}