From 7f6a8eb963dff0c6110137b70eb4f8d1d34e5511 Mon Sep 17 00:00:00 2001
From: "pavel.uhanov" <pavel.uhanov@demlabs.net>
Date: Mon, 22 Jan 2024 14:42:38 +0000
Subject: [PATCH] [*] merge from develop

---
 core/src/dap_list.c                           |   8 +-
 io/dap_events_socket.c                        |   5 +-
 io/dap_server.c                               | 300 +++++++++++-------
 io/include/dap_events_socket.h                |  19 +-
 io/include/dap_server.h                       |  20 +-
 net/server/notify_server/src/dap_notify_srv.c |  22 +-
 6 files changed, 222 insertions(+), 152 deletions(-)

diff --git a/core/src/dap_list.c b/core/src/dap_list.c
index 58c1f1849..250264ff8 100755
--- a/core/src/dap_list.c
+++ b/core/src/dap_list.c
@@ -69,8 +69,11 @@ void dap_list_free_full(dap_list_t *a_list, dap_callback_destroyed_t a_free_func
  *
  * Returns: either @list or the new start of the DapList if @list was %NULL
  */
-dap_list_t *dap_list_append(dap_list_t *a_list, void* a_data)
+dap_list_t *dap_list_append(dap_list_t *a_list, void *a_data)
 {
+// sanity check
+    dap_return_val_if_pass(!a_data, a_list);
+//func work
     dap_list_t *l_el = DAP_NEW_Z(dap_list_t);
     if (!l_el) {
         log_it(L_CRITICAL, "Out of memory");
@@ -106,6 +109,9 @@ dap_list_t *dap_list_append(dap_list_t *a_list, void* a_data)
  */
 dap_list_t *dap_list_prepend(dap_list_t *a_list, void *a_data)
 {
+// sanity check
+    dap_return_val_if_pass(!a_data, a_list);
+//func work
     dap_list_t *l_el = DAP_NEW_Z(dap_list_t);
     if (!l_el) {
         log_it(L_CRITICAL, "Out of memory");
diff --git a/io/dap_events_socket.c b/io/dap_events_socket.c
index f80752bbc..3d80658bb 100644
--- a/io/dap_events_socket.c
+++ b/io/dap_events_socket.c
@@ -1376,7 +1376,7 @@ void dap_events_socket_delete_mt(dap_worker_t * a_worker, dap_events_socket_uuid
  * @param a_callbacks
  * @return
  */
-dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, dap_events_socket_callbacks_t *a_callbacks)
+dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, SOCKET a_sock, dap_events_socket_callbacks_t *a_callbacks)
 {
     if (!a_callbacks || !a_server) {
         log_it(L_CRITICAL, "Invalid arguments in dap_events_socket_wrap_listener");
@@ -1386,10 +1386,9 @@ dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, dap
     if (!l_es)
         return NULL;
 
-    l_es->socket = a_server->socket_listener;
+    l_es->socket = a_sock;
     l_es->server = a_server;
     l_es->callbacks = *a_callbacks;
-    l_es->_inheritor = a_server;
     switch (a_server->type) {
     case DAP_SERVER_UDP:
         l_es->type = DESCRIPTOR_TYPE_SOCKET_UDP;
diff --git a/io/dap_server.c b/io/dap_server.c
index 9f8519fd8..4cc5fd532 100644
--- a/io/dap_server.c
+++ b/io/dap_server.c
@@ -70,12 +70,13 @@
 #include "dap_server.h"
 #include "dap_worker.h"
 #include "dap_events.h"
+#include "dap_strfuncs.h"
 
 #define LOG_TAG "dap_server"
 
 static dap_events_socket_t * s_es_server_create(int a_sock,
                                              dap_events_socket_callbacks_t * a_callbacks, dap_server_t * a_server);
-static int s_server_run(dap_server_t * a_server, dap_events_socket_callbacks_t *a_callbacks );
+static int s_server_run(dap_server_t * a_server);
 static void s_es_server_accept(dap_events_socket_t *a_es_listener, SOCKET a_remote_socket, struct sockaddr_storage *a_remote_addr);
 static void s_es_server_error(dap_events_socket_t *a_es, int a_arg);
 static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg);
@@ -115,11 +116,20 @@ dap_server_t* dap_server_get_default()
  */
 void dap_server_delete(dap_server_t *a_server)
 {
+// sanity check
+    dap_return_if_pass(!a_server);
+// func work
+    while (a_server->es_listeners) {
+        dap_events_socket_t *l_es = (dap_events_socket_t *)a_server->es_listeners->data;
+        dap_events_socket_remove_and_delete_mt(l_es->worker, l_es->uuid); // TODO unsafe moment. Replace storage to uuids
+        dap_list_t *l_tmp = a_server->es_listeners;
+        a_server->es_listeners = l_tmp->next;
+        DAP_DELETE(l_tmp);
+    }
     if(a_server->delete_callback)
         a_server->delete_callback(a_server,NULL);
 
-    if( a_server->_inheritor )
-        DAP_DELETE( a_server->_inheritor );
+    DAP_DEL_Z( a_server->_inheritor );
 
     pthread_mutex_destroy(&a_server->started_mutex);
     pthread_cond_destroy(&a_server->started_cond);
@@ -128,149 +138,211 @@ void dap_server_delete(dap_server_t *a_server)
 }
 
 /**
- * @brief dap_server_new_local
- * @param a_events
- * @param a_path
- * @param a_mode
- * @param a_callbacks
+ * @brief add listen addr to server
+ * @param a_server - server to add addr
+ * @param a_addr - addr or path to local
+ * @param a_port - port or read mode
+ * @param a_callbacks - pointer to callbacks
  * @return
  */
-dap_server_t *dap_server_new_local(const char *a_path, const char *a_mode, dap_events_socket_callbacks_t *a_callbacks)
+int dap_server_listen_addr_add(dap_server_t *a_server, const char *a_addr, uint16_t a_port, dap_events_socket_callbacks_t *a_callbacks)
 {
-#ifdef DAP_OS_UNIX
-    mode_t l_listen_unix_socket_permissions = 0770;
-    if (a_mode)
-        sscanf(a_mode,"%ou", &l_listen_unix_socket_permissions );
-    return dap_server_new(a_path, l_listen_unix_socket_permissions, DAP_SERVER_LOCAL, a_callbacks);
-#else
-    log_it(L_ERROR, "Local server is not implemented for your platform");
-    return NULL;
-#endif
-}
-
-/**
- * @brief dap_server_new
- * @param a_events
- * @param a_addr
- * @param a_port
- * @param a_type
- * @return
- */
-dap_server_t* dap_server_new(const char * a_addr, uint16_t a_port, dap_server_type_t a_type, dap_events_socket_callbacks_t *a_callbacks)
-{
-    dap_server_t *l_server =  DAP_NEW_Z(dap_server_t);
-    if (!l_server) {
-        log_it(L_CRITICAL, "Memory allocation error");
-        return NULL;
+// sanity check
+    dap_return_val_if_pass(!a_server, -1);
+    if (!a_addr || !a_port) {
+        log_it(L_ERROR, "Listener addr %s %u unspecified", a_addr, a_port);
+        return -4;;
     }
-    l_server->type = a_type;
-    if (l_server->type != DAP_SERVER_LOCAL)
-        l_server->port = a_port;
-    // Create socket
-    l_server->socket_listener = INVALID_SOCKET;
-    switch (l_server->type) {
+// preparing
+    SOCKET l_socket_listener = INVALID_SOCKET;
+    switch (a_server->type) {
     case DAP_SERVER_TCP:
-        l_server->socket_listener = socket(AF_INET, SOCK_STREAM, 0);
+        l_socket_listener = socket(AF_INET, SOCK_STREAM, 0);
         break;
     case DAP_SERVER_TCP_V6:
-        l_server->socket_listener = socket(AF_INET6, SOCK_STREAM, 0);
+        l_socket_listener = socket(AF_INET6, SOCK_STREAM, 0);
         break;
     case DAP_SERVER_UDP:
-        l_server->socket_listener = socket(AF_INET, SOCK_DGRAM, 0);
+        l_socket_listener = socket(AF_INET, SOCK_DGRAM, 0);
         break;
 #ifdef DAP_OS_UNIX
     case DAP_SERVER_LOCAL:
-        l_server->socket_listener = socket(AF_LOCAL, SOCK_STREAM, 0);
+        l_socket_listener = socket(AF_LOCAL, SOCK_STREAM, 0);
         break;
 #endif
     default:
         log_it(L_ERROR, "Specified server type %s is not implemented for your platform",
-               dap_server_type_str(l_server->type));
-        DAP_DELETE(l_server);
-        return NULL;
+               dap_server_type_str(a_server->type));
+        return -1;
     }
 #ifdef DAP_OS_WINDOWS
-    if (l_server->socket_listener == INVALID_SOCKET) {
+    if (l_socket_listener == INVALID_SOCKET) {
         log_it(L_ERROR, "Socket error: %d", WSAGetLastError());
 #else
-    if (l_server->socket_listener < 0) {
+    if (l_socket_listener < 0) {
         int l_errno = errno;
         log_it (L_ERROR,"Socket error %s (%d)", strerror(l_errno), l_errno);
 #endif
-        DAP_DELETE(l_server);
-        return NULL;
+        return -2;
     }
+    log_it(L_NOTICE,"Listen socket %"DAP_FORMAT_SOCKET" created...", l_socket_listener);
+// func work
+    // Create socket
+    dap_events_socket_t *l_es = dap_events_socket_wrap_listener(a_server, l_socket_listener, a_callbacks);
+
+    if (a_server->type != DAP_SERVER_LOCAL)
+        l_es->listener_port = a_port;
+    else
+        l_es->permission = a_port;
 
-    log_it(L_NOTICE,"Listen socket %"DAP_FORMAT_SOCKET" created...", l_server->socket_listener);
     int reuse = 1;
-    if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
+    if (setsockopt(l_socket_listener, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse, sizeof(reuse)) < 0)
         log_it(L_WARNING, "Can't set up REUSEADDR flag to the socket");
     reuse = 1;
 #ifdef SO_REUSEPORT
-    if (setsockopt(l_server->socket_listener, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
+    if (setsockopt(l_socket_listener, SOL_SOCKET, SO_REUSEPORT, (const char*)&reuse, sizeof(reuse)) < 0)
         log_it(L_WARNING, "Can't set up REUSEPORT flag to the socket");
 #endif
 
     void *l_addr_ptr = NULL;
     const char *l_addr = a_addr;
-    switch (l_server->type) {
+    switch (a_server->type) {
     case DAP_SERVER_TCP:
     case DAP_SERVER_UDP:
-        if (!l_addr)
-            l_addr = "0.0.0.0";
-        l_server->listener_addr.sin_family = AF_INET;
-        l_server->listener_addr.sin_port = htons(l_server->port);
-        l_addr_ptr = &l_server->listener_addr.sin_addr;
+        l_es->listener_addr.sin_family = AF_INET;
+        l_es->listener_addr.sin_port = htons(l_es->listener_port);
+        l_addr_ptr = &l_es->listener_addr.sin_addr;
         break;
     case DAP_SERVER_TCP_V6:
-        if (!l_addr)
-            l_addr = "::0";
-        l_server->listener_addr_v6.sin6_family = AF_INET6;
-        l_server->listener_addr_v6.sin6_port = htons(l_server->port);
-        l_addr_ptr = &l_server->listener_addr_v6.sin6_addr;
+        l_es->listener_addr_v6.sin6_family = AF_INET6;
+        l_es->listener_addr_v6.sin6_port = htons(l_es->listener_port);
+        l_addr_ptr = &l_es->listener_addr_v6.sin6_addr;
     default:
         break;
     }
 
-    if (l_server->type != DAP_SERVER_LOCAL) {
+    if (a_server->type != DAP_SERVER_LOCAL) {
         if (inet_pton(AF_INET, l_addr, &l_addr_ptr) <= 0) {
             log_it(L_ERROR, "Can't convert address %s to digital form", l_addr);
             goto clean_n_quit;
         }
-        strncpy(l_server->address, l_addr, sizeof(l_server->address)); // If NULL we listen everything
+        strncpy(l_es->listener_addr_str, l_addr, sizeof(l_es->listener_addr_str)); // If NULL we listen everything
     }
 #ifdef DAP_OS_UNIX
     else {
-        if (!a_addr) {
-            log_it(L_ERROR, "Listener path unspecified");
-            goto clean_n_quit;
-        }
-        l_server->listener_path.sun_family = AF_UNIX;
-        strncpy(l_server->listener_path.sun_path, a_addr, sizeof(l_server->listener_path.sun_path) - 1);
-        if (access(l_server->listener_path.sun_path, R_OK) == -1) {
-            log_it(L_ERROR, "Listener path %s is unavailable", l_server->listener_path.sun_path);
+        l_es->listener_path.sun_family = AF_UNIX;
+        strncpy(l_es->listener_path.sun_path, a_addr, sizeof(l_es->listener_path.sun_path) - 1);
+        if (access(l_es->listener_path.sun_path, R_OK) == -1) {
+            log_it(L_ERROR, "Listener path %s is unavailable", l_es->listener_path.sun_path);
             goto clean_n_quit;
         }
-        unlink(l_server->listener_path.sun_path);
+        unlink(l_es->listener_path.sun_path);
     }
 #endif
 
-    if (s_server_run(l_server,a_callbacks))
+    a_server->es_listeners = dap_list_prepend(a_server->es_listeners, l_es);
+    if (s_server_run(a_server))
         goto clean_n_quit;
 
 #ifdef DAP_OS_UNIX
-    if (l_server->type == DAP_SERVER_LOCAL) {
-        mode_t l_listen_unix_socket_permissions = a_port;
-        chmod(l_server->listener_path.sun_path, l_listen_unix_socket_permissions);
+    if (a_server->type == DAP_SERVER_LOCAL) {
+        chmod(l_es->listener_path.sun_path, l_es->permission);
     }
 #endif
 
-    return l_server;
+    return 0;
 
 clean_n_quit:
-    closesocket(l_server->socket_listener);
-    DAP_DELETE(l_server);
-    return NULL;
+    a_server->es_listeners = dap_list_remove(a_server->es_listeners, l_es);
+    dap_events_socket_delete_unsafe(l_es, false);
+    return -3;
+}
+
+/**
+ * @brief dap_server_new
+ * @param a_events
+ * @param a_addr
+ * @param a_port
+ * @param a_type
+ * @return
+ */
+dap_server_t *dap_server_new(char **a_addrs, uint16_t a_count, dap_server_type_t a_type, dap_events_socket_callbacks_t *a_callbacks)
+{
+// sanity check
+    dap_return_val_if_pass(!a_addrs || !a_count, NULL);
+// memory alloc
+    dap_server_t *l_server =  DAP_NEW_Z(dap_server_t);
+    if (!l_server) {
+        log_it(L_CRITICAL, "Memory allocation error");
+        return NULL;
+    }
+// preparing
+    //create callback
+    dap_events_socket_callbacks_t l_callbacks = {0};
+    l_callbacks.new_callback = s_es_server_new;
+    l_callbacks.accept_callback = s_es_server_accept;
+    l_callbacks.error_callback = s_es_server_error;
+
+    if (a_callbacks) {
+        l_callbacks.read_callback = a_callbacks->read_callback;
+        l_callbacks.write_callback = a_callbacks->write_callback;
+        l_callbacks.error_callback = a_callbacks->error_callback;
+    }
+    l_server->type = a_type;
+    char l_curr_ip[INET6_ADDRSTRLEN] = {0};
+// func work
+    for(size_t i = 0; i < a_count; ++i) {
+        // parsing full addr
+        int l_ret = -1;
+        if (l_server->type != DAP_SERVER_LOCAL) {
+            const char *l_curr_port_str = strstr(a_addrs[i], ":");
+            uint16_t l_curr_port = 0;
+            if (l_curr_port_str) {
+                memset(l_curr_ip, 0, sizeof(l_curr_ip));
+                strncpy(l_curr_ip, a_addrs[i], dap_min((size_t)(l_curr_port_str - a_addrs[i]), sizeof(l_curr_ip) - 1));
+                l_curr_port = atol(++l_curr_port_str);
+            } else {
+                l_curr_port = atol(a_addrs[i]);
+            }
+            switch (l_server->type) {
+                case DAP_SERVER_TCP:
+                case DAP_SERVER_UDP:
+                    if (!l_curr_ip[0])
+                        strcpy(l_curr_ip, "0.0.0.0");  // If NULL we listen everything
+                    break;
+                case DAP_SERVER_TCP_V6:
+                    if (!l_curr_ip[0])
+                        strcpy(l_curr_ip, "::0");
+                    break;
+                default:
+                    break;
+            }
+            l_ret = dap_server_listen_addr_add(l_server, l_curr_ip, l_curr_port, &l_callbacks);
+        }
+#ifdef DAP_OS_UNIX
+        else {
+            char l_curr_path[MAX_PATH] = {0};
+            mode_t l_listen_unix_socket_permissions = 0770;
+            const char *l_curr_mode_str = strstr(a_addrs[i], ":");
+            if (!l_curr_mode_str) {
+                strncpy(l_curr_path, a_addrs[i], sizeof(l_curr_path) - 1);
+            } else {
+                l_curr_mode_str++;
+                strncpy(l_curr_path, a_addrs[i], dap_min((size_t)(l_curr_mode_str - a_addrs[i]), sizeof(l_curr_path) - 1));
+                sscanf(l_curr_mode_str,"%ou", &l_listen_unix_socket_permissions );
+            }
+            l_ret = dap_server_listen_addr_add(l_server, l_curr_path, l_listen_unix_socket_permissions, &l_callbacks);
+        }
+#endif
+        if (l_ret)
+            continue;
+    }
+    if (!l_server->es_listeners) {
+        log_it(L_ERROR, "Server not created");
+        DAP_DELETE(l_server);
+        return NULL;
+    }
+    return l_server;
 }
 
 /**
@@ -278,73 +350,61 @@ clean_n_quit:
  * @param a_server
  * @param a_callbacks
  */
-static int s_server_run(dap_server_t *a_server, dap_events_socket_callbacks_t *a_callbacks)
+static int s_server_run(dap_server_t *a_server)
 {
-    assert(a_server);
-
+// sanity check
+    dap_return_val_if_pass(!a_server || !a_server->es_listeners, -1);
+// func work
+    dap_events_socket_t *l_es = (dap_events_socket_t *)a_server->es_listeners->data;
     void *l_listener_addr = NULL;
     socklen_t l_listener_addr_len = 0;
     switch (a_server->type) {
     case DAP_SERVER_TCP:
     case DAP_SERVER_UDP:
-        l_listener_addr = &a_server->listener_addr;
-        l_listener_addr_len = sizeof(a_server->listener_addr);
+        l_listener_addr = &l_es->listener_addr;
+        l_listener_addr_len = sizeof(l_es->listener_addr);
         break;
     case DAP_SERVER_TCP_V6:
-        l_listener_addr = &a_server->listener_addr_v6;
-        l_listener_addr_len = sizeof(a_server->listener_addr_v6);
+        l_listener_addr = &l_es->listener_addr_v6;
+        l_listener_addr_len = sizeof(l_es->listener_addr_v6);
         break;
 #ifdef DAP_OS_UNIX
     case DAP_SERVER_LOCAL:
-        l_listener_addr = &a_server->listener_path;
-        l_listener_addr_len = sizeof(a_server->listener_path);
+        l_listener_addr = &l_es->listener_path;
+        l_listener_addr_len = sizeof(l_es->listener_path);
 #endif
     default:
         log_it(L_ERROR, "Can't run server: unsupported server type %s", dap_server_type_str(a_server->type));
     }
 
-    if (bind(a_server->socket_listener, (struct sockaddr *)l_listener_addr, l_listener_addr_len) < 0) {
+    if (bind(l_es->socket, (struct sockaddr *)l_listener_addr, l_listener_addr_len) < 0) {
 #ifdef DAP_OS_WINDOWS
         log_it(L_ERROR,"Bind error: %d", WSAGetLastError());
-        closesocket(a_server->socket_listener);
+        closesocket(l_es->socket);
 #else
         log_it(L_ERROR,"Bind error: %s",strerror(errno));
-        close(a_server->socket_listener);
+        close(l_es->socket);
         if ( errno == EACCES ) // EACCES=13
             log_it( L_ERROR, "Server can't start. Permission denied");
 #endif
-        DAP_DELETE(a_server);
         return -1;
     } else {
-        log_it(L_INFO, "Binded %s:%u", a_server->address, a_server->port);
-        listen(a_server->socket_listener, SOMAXCONN);
+        log_it(L_INFO,"Binded %s:%u", l_es->listener_addr_str, l_es->listener_port);
+        listen(l_es->socket, SOMAXCONN);
     }
 #ifdef DAP_OS_WINDOWS
      u_long l_mode = 1;
-     ioctlsocket(a_server->socket_listener, (long)FIONBIO, &l_mode);
+     ioctlsocket(l_es->socket, (long)FIONBIO, &l_mode);
 #else
-    fcntl( a_server->socket_listener, F_SETFL, O_NONBLOCK);
+    fcntl(l_es->socket, F_SETFL, O_NONBLOCK);
 #endif
     pthread_mutex_init(&a_server->started_mutex,NULL);
     pthread_cond_init(&a_server->started_cond,NULL);
 
-    dap_events_socket_callbacks_t l_callbacks;
-    memset(&l_callbacks,0,sizeof (l_callbacks));
-    l_callbacks.new_callback = s_es_server_new;
-    l_callbacks.accept_callback = s_es_server_accept;
-    l_callbacks.error_callback = s_es_server_error;
-
-    if (a_callbacks) {
-        l_callbacks.read_callback = a_callbacks->read_callback;
-        l_callbacks.write_callback = a_callbacks->write_callback;
-        l_callbacks.error_callback = a_callbacks->error_callback;
-    }
-
 #ifdef DAP_EVENTS_CAPS_EPOLL
     for(size_t l_worker_id = 0; l_worker_id < dap_events_thread_get_count() ; l_worker_id++){
         dap_worker_t *l_w = dap_events_worker_get(l_worker_id);
         assert(l_w);
-        dap_events_socket_t * l_es = dap_events_socket_wrap_listener(a_server, &l_callbacks);
         if (l_es) {
             l_es->type = a_server->type == DAP_SERVER_TCP ? DESCRIPTOR_TYPE_SOCKET_LISTENING : DESCRIPTOR_TYPE_SOCKET_UDP;
             // Prepare for multi thread listening
@@ -353,21 +413,19 @@ static int s_server_run(dap_server_t *a_server, dap_events_socket_callbacks_t *a
             // if we have poll exclusive
             l_es->ev_base_flags |= EPOLLET | EPOLLEXCLUSIVE;
 #endif
-            l_es->_inheritor = a_server;
             pthread_mutex_lock(&a_server->started_mutex);
             dap_worker_add_events_socket( l_w, l_es );
             while (!a_server->started)
                 pthread_cond_wait(&a_server->started_cond, &a_server->started_mutex);
             pthread_mutex_unlock(&a_server->started_mutex);
         } else{
-            log_it(L_WARNING, "Can't wrap event socket for %s:%u server", a_server->address, a_server->port);
+            log_it(L_WARNING, "Can't wrap event socket for %s:%u server", l_es->listener_addr_str6, l_es->listener_port);
             return -2;
         }
     }
 #else
     dap_worker_t *l_w = dap_events_worker_get_auto();
     assert(l_w);
-    dap_events_socket_t *l_es = dap_events_socket_wrap_listener(a_server, &l_callbacks);
     if (l_es) {
         pthread_mutex_lock(&a_server->started_mutex);
         dap_worker_add_events_socket( l_w, l_es );
@@ -389,8 +447,8 @@ static int s_server_run(dap_server_t *a_server, dap_events_socket_callbacks_t *a
  */
 static void s_es_server_new(dap_events_socket_t *a_es, void * a_arg)
 {
-    log_it(L_DEBUG, "Created server socket %p on worker %u", a_es, a_es->worker->id);
-    dap_server_t *l_server = (dap_server_t*) a_es->_inheritor;
+    log_it(L_DEBUG, "Created server socket %p on worker %u", a_es, a_es->worker->id);;
+    dap_server_t *l_server = a_es->server;
     pthread_mutex_lock( &l_server->started_mutex);
     l_server->started = true;
     pthread_cond_broadcast( &l_server->started_cond);
@@ -419,11 +477,11 @@ static void s_es_server_error(dap_events_socket_t *a_es, int a_arg)
  */
 static void s_es_server_accept(dap_events_socket_t *a_es_listener, SOCKET a_remote_socket, struct sockaddr_storage *a_remote_addr)
 {
-    dap_server_t *l_server = (dap_server_t*)a_es_listener->_inheritor;
+    dap_server_t *l_server = a_es_listener->server;
     assert(l_server);
 
     dap_events_socket_t * l_es_new = NULL;
-    log_it(L_DEBUG, "[es:%p] Listening socket (binded on %s:%u) got new incoming connection", a_es_listener, l_server->address, l_server->port);
+    log_it(L_DEBUG, "[es:%p] Listening socket (binded on %s:%u) got new incoming connection", a_es_listener, a_es_listener->listener_addr_str, a_es_listener->listener_port);
     if (a_remote_socket < 0) {
 #ifdef DAP_OS_WINDOWS
         log_it(L_ERROR, "Accept error: %d", WSAGetLastError());
diff --git a/io/include/dap_events_socket.h b/io/include/dap_events_socket.h
index fe0e04162..d216635ba 100644
--- a/io/include/dap_events_socket.h
+++ b/io/include/dap_events_socket.h
@@ -60,6 +60,7 @@ typedef int SOCKET;
     //#define DAP_EVENTS_CAPS_AIO
     //#define DAP_EVENTS_CAPS_AIO_THREADS
     #include <netinet/in.h>
+    #include <sys/un.h>
     #include <sys/eventfd.h>
     #include <mqueue.h>
     #include <sys/un.h>
@@ -69,6 +70,7 @@ typedef int SOCKET;
     #define DAP_EVENTS_CAPS_EVENT_KEVENT
     #define DAP_EVENTS_CAPS_QUEUE_KEVENT
     #include <netinet/in.h>
+    #include <sys/un.h>
     #include <sys/event.h>
     #include <sys/un.h>
 #elif defined (DAP_OS_UNIX)
@@ -254,13 +256,24 @@ typedef struct dap_events_socket {
     // Remote address, port and others
     union {
         struct sockaddr_in remote_addr;
+        struct sockaddr_in listener_addr;
         struct sockaddr_in6 remote_addr_v6;
+        struct sockaddr_in6 listener_addr_v6;
 #ifdef DAP_OS_UNIX
         struct sockaddr_un remote_path;
+        struct sockaddr_un listener_path; // Path to UNIX socket
 #endif
     };
-    char remote_addr_str[INET6_ADDRSTRLEN];
-    uint16_t remote_port;
+
+    union {
+        char remote_addr_str[INET6_ADDRSTRLEN];
+        char listener_addr_str[INET6_ADDRSTRLEN];   
+    };
+    union {
+        uint16_t  remote_port;
+        uint16_t  listener_port;
+        mode_t  permission;
+    };
 
     // Links to related objects
     dap_context_t *context;
@@ -348,7 +361,7 @@ void dap_events_socket_delete_unsafe( dap_events_socket_t * a_esocket , bool a_p
 void dap_events_socket_delete_mt(dap_worker_t * a_worker, dap_events_socket_uuid_t a_es_uuid);
 
 dap_events_socket_t *dap_events_socket_wrap_no_add(SOCKET a_sock, dap_events_socket_callbacks_t *a_callbacks);
-dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, dap_events_socket_callbacks_t *a_callbacks);
+dap_events_socket_t *dap_events_socket_wrap_listener(dap_server_t *a_server, SOCKET a_sock, dap_events_socket_callbacks_t *a_callbacks);
 
 void dap_events_socket_assign_on_worker_mt(dap_events_socket_t * a_es, struct dap_worker * a_worker);
 void dap_events_socket_assign_on_worker_inter(dap_events_socket_t * a_es_input, dap_events_socket_t * a_es);
diff --git a/io/include/dap_server.h b/io/include/dap_server.h
index 6a9bf43b3..7c05bb394 100644
--- a/io/include/dap_server.h
+++ b/io/include/dap_server.h
@@ -78,19 +78,11 @@ struct dap_server;
 typedef void (*dap_server_callback_t)( struct dap_server *,void * arg ); // Callback for specific server's operations
 
 typedef struct dap_server {
-    dap_server_type_t type;                     // Server's type
-    uint16_t port;                              // Listen port
-    char address[INET6_ADDRSTRLEN];             // Listen address
-    SOCKET socket_listener;
-    union {
-        struct sockaddr_in listener_addr;       // Kernel structure for listener's binded address
-        struct sockaddr_in6 listener_addr_v6;   // Kernel structure for listener's binded address IPv6
-#ifdef DAP_OS_UNIX
-        struct sockaddr_un listener_path;       // Path to UNIX socket
-#endif
-    };
 
-    void *_inheritor;                           // Pointer to the internal data, HTTP for example
+  dap_server_type_t type;                   // Server's type
+  dap_list_t *es_listeners;
+
+  void *_inheritor;
 
     dap_cpu_stats_t cpu_stats;
 
@@ -109,7 +101,7 @@ void  dap_server_deinit( void ); // Deinit server module
 void dap_server_set_default(dap_server_t* a_server);
 dap_server_t* dap_server_get_default();
 
-dap_server_t* dap_server_new(const char * a_addr, uint16_t a_port, dap_server_type_t a_type, dap_events_socket_callbacks_t *a_callbacks);
-dap_server_t* dap_server_new_local(const char * a_path, const char * a_mode, dap_events_socket_callbacks_t *a_callbacks);
+dap_server_t* dap_server_new(char **a_addrs, uint16_t a_count, dap_server_type_t a_type, dap_events_socket_callbacks_t *a_callbacks);
+int dap_server_listen_addr_add(dap_server_t *a_server, const char *a_addr, uint16_t a_port, dap_events_socket_callbacks_t *a_callbacks);
 
 void dap_server_delete(dap_server_t *a_server);
diff --git a/net/server/notify_server/src/dap_notify_srv.c b/net/server/notify_server/src/dap_notify_srv.c
index c9fec4d68..267278747 100644
--- a/net/server/notify_server/src/dap_notify_srv.c
+++ b/net/server/notify_server/src/dap_notify_srv.c
@@ -57,18 +57,20 @@ static void s_notify_server_callback_delete(dap_events_socket_t * a_es, void * a
  */
 int dap_notify_server_init()
 {
-    const char * l_notify_socket_path = dap_config_get_item_str_default(g_config, "notify_server", "listen_path",NULL);
-    const char * l_notify_socket_path_mode = dap_config_get_item_str_default(g_config, "notify_server", "listen_path_mode","0600");
+    const char *l_path = dap_config_get_item_str_default(g_config, "notify_server", "listen_path", NULL);
+    const char *l_path_mode = dap_config_get_item_str_default(g_config, "notify_server", "listen_path_mode","0600");
 
-    const char * l_notify_socket_address = dap_config_get_item_str_default(g_config, "notify_server", "listen_address",NULL);
-    uint16_t l_notify_socket_port = dap_config_get_item_uint16_default(g_config, "notify_server", "listen_port",0);
+    uint16_t l_notify_socket_count = 0;
+    char **l_notify_socket_address = dap_config_get_array_str(g_config, "notify_server", "listen_address", &l_notify_socket_count);
 
-    if(l_notify_socket_path){
-        s_notify_server = dap_server_new_local(l_notify_socket_path, l_notify_socket_path_mode, NULL);
-    }else if (l_notify_socket_address && l_notify_socket_port ){
-        s_notify_server = dap_server_new( l_notify_socket_address,
-                                            l_notify_socket_port, DAP_SERVER_TCP, NULL);
-    }else{
+    if(l_path){
+        char *l_path_and_mode = DAP_NEW_Z_SIZE(char, MAX_PATH + 5);
+        dap_snprintf(l_path_and_mode, MAX_PATH + 4, "%s%c%s", l_path, l_path_mode ? ':' : 0, l_path_mode ? l_path_mode : "\0");
+        s_notify_server = dap_server_new(&l_path_and_mode, 1, DAP_SERVER_LOCAL, NULL);
+        DAP_DELETE(l_path_and_mode);
+    } else if (l_notify_socket_address && l_notify_socket_count) {
+        s_notify_server = dap_server_new(l_notify_socket_address, l_notify_socket_count, DAP_SERVER_TCP, NULL);
+    } else {
         log_it(L_INFO,"Notify server is not configured, nothing to init but thats okay");
         return 0;
     }
-- 
GitLab