webrtc_dns: Add support for registering DNS service 70/286070/8
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 23 Dec 2022 06:31:10 +0000 (15:31 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Tue, 3 Jan 2023 02:33:05 +0000 (11:33 +0900)
This patch uses dns_sd.h of mdnsresponder to register DNS service
and to publish hostname for private IP address.

[Version] 0.3.276
[Issue type] New feature

Change-Id: I9a9d64c367b2a49f2fe6e2ca7d1cd3ceca91770d
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
CMakeLists.txt
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc_dns.c [new file with mode: 0644]

index dc637db6d17589b25039f05fa5e37e4a68fb909d..44bd99ee63eb4f87b3f704daf45c433e21f0719b 100644 (file)
@@ -13,7 +13,7 @@ INCLUDE_DIRECTORIES(${INC_DIR})
 SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-webrtc-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \
                 gstreamer-allocators-1.0 libpulse json-glib-1.0 iniparser mm-common mm-display-interface capi-media-tool \
                 libtbm libwebsockets cynara-client libsmack capi-system-info libsoup-2.4 bundle capi-media-sound-manager \
-                mm-fileinfo mmutil-common mmutil-imgp mmutil-jpeg mmutil-magick")
+                mm-fileinfo mmutil-common mmutil-imgp mmutil-jpeg mmutil-magick dns_sd")
 IF(NOT TIZEN_PROFILE_TV)
     SET(dependents "${dependents} mm-resource-manager")
     IF(TIZEN_FEATURE_UI)
index 9f3c468dbb1844fd74184935d6a6cfc726d2b3dc..cc863585e6ffa2e16043f6ad885260443c1ace14 100644 (file)
@@ -32,6 +32,7 @@
 #include <tbm_bufmgr.h>
 #include <libwebsockets.h>
 #include <libsoup/soup.h>
+#include <dns_sd.h>
 
 #include "webrtc_internal.h"
 
@@ -513,6 +514,11 @@ typedef struct _webrtc_s {
                GAsyncQueue *queue;
        } snapshot;
 
+       struct {
+               DNSServiceRef client;
+               DNSServiceRef client_pa; /* proxy address record */
+       } dns;
+
        guint idle_cb_event_source_ids[IDLE_CB_TYPE_NUM];
 
        webrtc_callbacks_s error_cb;
@@ -840,6 +846,10 @@ void _destroy_tbm_bo_list(webrtc_tbm_s *tbm);
 void *_get_unused_tbm_bo(webrtc_tbm_s *tbm, unsigned int timeout_sec);
 void _release_tbm_bo(webrtc_tbm_s *tbm, void *bo);
 
+/* DNS */
+int _register_dns_service(webrtc_s *webrtc);
+void _unregister_dns_service(webrtc_s *webrtc);
+
 /* websocket*/
 typedef int (*_websocket_cb)(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
 webrtc_websocket_s *_alloc_websocket(const int port, const char *ssl_cert_path, const char *ssl_private_key_path, const char *ssl_ca_path, _websocket_cb callback, void *user_data);
index ed2e87cdd00493e81ac5ebdebad9cf60c02900e4..bd0c0934fc11219eba247c7920525e281d511556 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.275
+Version:    0.3.276
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
@@ -39,6 +39,7 @@ BuildRequires:  pkgconfig(mmutil-common)
 BuildRequires:  pkgconfig(mmutil-imgp)
 BuildRequires:  pkgconfig(mmutil-jpeg)
 BuildRequires:  pkgconfig(mmutil-magick)
+BuildRequires:  pkgconfig(dns_sd)
 %if "%{tizen_profile_name}" != "tv"
 BuildRequires:  pkgconfig(mm-resource-manager)
 BuildRequires:  pkgconfig(capi-system-sensor)
diff --git a/src/webrtc_dns.c b/src/webrtc_dns.c
new file mode 100644 (file)
index 0000000..fc6aa09
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "webrtc_private.h"
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <ifaddrs.h>
+#include <arpa/inet.h>
+
+#define DNSS_REGISTER_NAME "nativeWebRTC"
+#define DNSS_REGISTER_HOST "nativewebrtc.local"
+
+//LCOV_EXCL_START
+static void __dns_service_register_record_cb(DNSServiceRef service, DNSRecordRef record, const DNSServiceFlags flags, DNSServiceErrorType error_type,
+       void *context)
+{
+       char *hostname = (char *)context;
+       LOG_DEBUG("service[%p] record[%p] flags[0x%x] error_type[0x%x] hostname[%s]", service, record, flags, error_type, hostname);
+
+       switch (error_type) {
+       case kDNSServiceErr_NoError:
+               LOG_INFO("name now registered and active");
+               break;
+       case kDNSServiceErr_NameConflict:
+               LOG_ERROR("name in use, please choose another");
+               break;
+       default:
+               LOG_ERROR("error %d", error_type);
+               break;
+       }
+}
+
+static void __dns_service_register_reply_cb(DNSServiceRef service, DNSServiceFlags flags, DNSServiceErrorType error_type, const char *name,
+       const char *regtype, const char *domain, void *context)
+{
+       LOG_DEBUG("service[%p] flags[0x%x] error_type[0x%x] name[%s] regtype[%s] domain[%s] context[%p]",
+               service, flags, error_type, name, regtype, domain, context);
+
+       switch (error_type) {
+       case kDNSServiceErr_NoError:
+               LOG_INFO("name now registered and active");
+               break;
+       case kDNSServiceErr_NameConflict:
+               LOG_ERROR("name in use, please choose another");
+               break;
+       default:
+               LOG_ERROR("error %d", error_type);
+               break;
+       }
+}
+
+static gchar *__get_my_private_ip(void)
+{
+       struct ifaddrs *ifaddr = NULL;
+       struct ifaddrs *ifaddr_ptr = NULL;
+       void *sin_addr = NULL;
+       char addressBuffer[INET_ADDRSTRLEN];
+       gchar *ip = NULL;
+
+       getifaddrs(&ifaddr);
+
+       for (ifaddr_ptr = ifaddr; ifaddr_ptr != NULL; ifaddr_ptr = ifaddr_ptr->ifa_next) {
+               if (!ifaddr_ptr->ifa_addr)
+                       continue;
+
+               if (ifaddr_ptr->ifa_addr->sa_family != AF_INET) /* TODO: IPv6 */
+                       continue;
+
+               sin_addr = &((struct sockaddr_in *)ifaddr_ptr->ifa_addr)->sin_addr;
+               inet_ntop(AF_INET, sin_addr, addressBuffer, INET_ADDRSTRLEN);
+               if (!g_str_has_prefix(addressBuffer, "192.168."))
+                       continue;
+
+               LOG_DEBUG("%s IPv4 Address %s", (const char *)ifaddr_ptr->ifa_name, addressBuffer);
+               ip = g_strdup(addressBuffer);
+               break;
+       }
+
+       if (ifaddr)
+               freeifaddrs(ifaddr);
+
+       return ip;
+}
+
+int _register_dns_service(webrtc_s *webrtc)
+{
+       int ret;
+       struct sockaddr_storage hostaddr;
+       struct addrinfo *addrs = NULL;
+       static DNSRecordRef record = NULL;
+       gchar *ip;
+       const char *host = DNSS_REGISTER_HOST;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(webrtc->dns.client_pa != NULL, WEBRTC_ERROR_INVALID_OPERATION, "client_pa has been already registered");
+       RET_VAL_IF(webrtc->dns.client != NULL, WEBRTC_ERROR_INVALID_OPERATION, "client_pa has been already registered");
+
+       ip = __get_my_private_ip();
+       RET_VAL_IF(ip == NULL, WEBRTC_ERROR_INVALID_OPERATION, "ip is NULL");
+
+       ret = DNSServiceCreateConnection(&webrtc->dns.client_pa);
+       if (ret != kDNSServiceErr_NoError) {
+               LOG_ERROR("failed to DNSServiceCreateConnection(), ret[0x%x]", ret);
+               goto error;
+       }
+
+       memset(&hostaddr, 0, sizeof(hostaddr));
+       ret = getaddrinfo((const char *)ip, NULL, NULL, &addrs);
+       if (ret) {
+               LOG_ERROR("failed to getaddrinfo(), error %d for %s", ret, ip);
+               goto error;
+       }
+       memcpy(&hostaddr, addrs->ai_addr, sizeof(struct sockaddr_in));
+       freeaddrinfo(addrs);
+
+       if (hostaddr.ss_family != AF_INET) { /* ToDO: support IPv6 */
+               LOG_ERROR("hostaddr.ss_family is not AF_INET");
+               goto error;
+       }
+
+       ret = DNSServiceRegisterRecord(webrtc->dns.client_pa, &record, kDNSServiceFlagsUnique, kDNSServiceInterfaceIndexAny, host,
+               kDNSServiceType_A, kDNSServiceClass_IN, 4, &((struct sockaddr_in *)&hostaddr)->sin_addr, 240, __dns_service_register_record_cb, (void*)host);
+       if (ret != kDNSServiceErr_NoError) {
+               LOG_ERROR("failed to DNSServiceRegisterRecord(), ret[0x%x]", ret);
+               goto error;
+       }
+
+       ret = DNSServiceRegister(&webrtc->dns.client,
+               kDNSServiceFlagsUnique,  /* flags */
+               0,                       /* interfaceIndex */
+               DNSS_REGISTER_NAME,      /* name */
+               "_http._tcp",            /* regtype */
+               "",                      /* domain */
+               host,                    /* host */
+               htons(80),               /* port */
+               0,                       /* txtLen */
+               NULL,                    /* txtRecord */
+               __dns_service_register_reply_cb, /* callback */
+               NULL                     /* context */
+               );
+       if (ret != kDNSServiceErr_NoError) {
+               LOG_ERROR("failed to DNSServiceRegister(), ret[0x%x]", ret);
+               goto error;
+       }
+
+       LOG_INFO("client_pa[%p] client[%p] name[%s] host[%s] ip[%s]", webrtc->dns.client_pa, webrtc->dns.client, DNSS_REGISTER_NAME, host, ip);
+
+       g_free(ip);
+
+       return WEBRTC_ERROR_NONE;
+
+error:
+       g_free(ip);
+       if (webrtc->dns.client_pa) {
+               DNSServiceRefDeallocate(webrtc->dns.client_pa);
+               webrtc->dns.client_pa = NULL;
+       }
+       if (webrtc->dns.client) {
+               DNSServiceRefDeallocate(webrtc->dns.client);
+               webrtc->dns.client = NULL;
+       }
+       return WEBRTC_ERROR_INVALID_OPERATION;
+}
+
+void _unregister_dns_service(webrtc_s *webrtc)
+{
+       RET_IF(webrtc == NULL, "webrtc is NULL");
+       RET_IF(webrtc->dns.client_pa == NULL, "client_pa is NULL");
+       RET_IF(webrtc->dns.client == NULL, "client is NULL");
+
+       LOG_INFO("client_pa[%p] client[%p]", webrtc->dns.client_pa, webrtc->dns.client);
+
+       DNSServiceRefDeallocate(webrtc->dns.client_pa);
+       DNSServiceRefDeallocate(webrtc->dns.client);
+       webrtc->dns.client_pa = NULL;
+       webrtc->dns.client = NULL;
+}
+//LCOV_EXCL_STOP