--- /dev/null
+/*
+ * 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