UNIX socket UPDATE configurable with YANG data

Implemented the ability to create a UNIX socket server with YANG
data. Additionally all new tests timeouts are now unified.
diff --git a/modules/libnetconf2-netconf-server.yang b/modules/libnetconf2-netconf-server.yang
index f9b7625..9d8bbb9 100644
--- a/modules/libnetconf2-netconf-server.yang
+++ b/modules/libnetconf2-netconf-server.yang
@@ -32,4 +32,24 @@
       }
     }
   }
+
+  augment "/ncs:netconf-server/ncs:listen/ncs:endpoint/ncs:transport" {
+    case unix-socket {
+      container unix-socket {
+        leaf path {
+          type string;
+          mandatory true;
+        }
+        leaf mode {
+          type uint16;
+        }
+        leaf uid {
+          type uint16;
+        }
+        leaf gid {
+          type uint16;
+        }
+      }
+    }
+  }
 }
diff --git a/src/config_server.c b/src/config_server.c
index 2c41ee0..50e3c1b 100644
--- a/src/config_server.c
+++ b/src/config_server.c
@@ -479,6 +479,35 @@
 }
 
 void
+nc_server_del_unix_socket(struct nc_bind *bind, struct nc_server_unix_opts *opts)
+{
+    if (bind->sock > -1) {
+        close(bind->sock);
+    }
+
+    free(bind->address);
+    free(opts->address);
+
+    free(opts);
+    opts = NULL;
+}
+
+void
+nc_server_del_endpt_unix_socket(struct nc_endpt *endpt, struct nc_bind *bind)
+{
+    nc_server_del_endpt_name(endpt);
+    nc_server_del_unix_socket(bind, endpt->opts.unixsock);
+
+    server_opts.endpt_count--;
+    if (!server_opts.endpt_count) {
+        free(server_opts.endpts);
+        free(server_opts.binds);
+        server_opts.endpts = NULL;
+        server_opts.binds = NULL;
+    }
+}
+
+void
 nc_server_config_del_keystore(void)
 {
     int i, j;
@@ -520,7 +549,13 @@
 
     if (op == NC_OP_DELETE) {
         for (i = 0; i < server_opts.endpt_count; i++) {
-            nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
+            if (server_opts.endpts[i].ti == NC_TI_LIBSSH) {
+                nc_server_del_endpt_ssh(&server_opts.endpts[i], &server_opts.binds[i]);
+            } else if (server_opts.endpts[i].ti == NC_TI_OPENSSL) {
+                /* todo */
+            } else {
+                nc_server_del_endpt_unix_socket(&server_opts.endpts[i], &server_opts.binds[i]);
+            }
         }
     }
 
@@ -676,7 +711,7 @@
 {
     int sock = -1, set_addr, ret = 0;
 
-    assert((address && !port) || (!address && port));
+    assert((address && !port) || (!address && port) || (endpt->ti == NC_TI_UNIX));
 
     if (address) {
         set_addr = 1;
@@ -690,15 +725,15 @@
         address = bind->address;
     }
 
-    if (!set_addr && (endpt->ti == NC_TI_UNIX)) {
-        ret = 1;
-        goto cleanup;
-    }
-
     /* we have all the information we need to create a listening socket */
-    if (address && port) {
+    if ((address && port) || (endpt->ti == NC_TI_UNIX)) {
         /* create new socket, close the old one */
-        sock = nc_sock_listen_inet(address, port, &endpt->ka);
+        if (endpt->ti == NC_TI_UNIX) {
+            sock = nc_sock_listen_unix(endpt->opts.unixsock);
+        } else {
+            sock = nc_sock_listen_inet(address, port, &endpt->ka);
+        }
+
         if (sock == -1) {
             ret = 1;
             goto cleanup;
@@ -712,6 +747,9 @@
 
     if (sock > -1) {
         switch (endpt->ti) {
+        case NC_TI_UNIX:
+            VRB(NULL, "Listening on %s for UNIX connections.", endpt->opts.unixsock->address);
+            break;
 #ifdef NC_ENABLED_SSH
         case NC_TI_LIBSSH:
             VRB(NULL, "Listening on %s:%u for SSH connections.", address, port);
@@ -1911,6 +1949,92 @@
 }
 
 static int
+nc_server_create_unix_socket(struct nc_endpt *endpt)
+{
+    endpt->ti = NC_TI_UNIX;
+    endpt->opts.unixsock = calloc(1, sizeof *endpt->opts.unixsock);
+    if (!endpt->opts.unixsock) {
+        ERRMEM;
+        return 1;
+    }
+
+    /* set default values */
+    endpt->opts.unixsock->mode = -1;
+    endpt->opts.unixsock->uid = -1;
+    endpt->opts.unixsock->gid = -1;
+
+    return 0;
+}
+
+static int
+nc_server_configure_unix_socket(const struct lyd_node *node, NC_OPERATION op)
+{
+    int ret = 0;
+    uint32_t prev_lo;
+    struct nc_endpt *endpt;
+    struct nc_bind *bind;
+    struct nc_server_unix_opts *opts;
+    struct lyd_node *data = NULL;
+
+    assert(!strcmp(LYD_NAME(node), "unix-socket"));
+
+    if (nc_server_get_endpt(node, &endpt, &bind)) {
+        ret = 1;
+        goto cleanup;
+    }
+
+    if (op == NC_OP_CREATE) {
+        if (nc_server_create_unix_socket(endpt)) {
+            ret = 1;
+            goto cleanup;
+        }
+
+        opts = endpt->opts.unixsock;
+
+        lyd_find_path(node, "path", 0, &data);
+        assert(data);
+
+        opts->address = strdup(lyd_get_value(data));
+        bind->address = strdup(lyd_get_value(data));
+        if (!opts->address || !bind->address) {
+            ERRMEM;
+            ret = 1;
+            goto cleanup;
+        }
+
+        /* silently search for non-mandatory parameters */
+        prev_lo = ly_log_options(0);
+        ret = lyd_find_path(node, "mode", 0, &data);
+        if (!ret) {
+            opts->mode = strtol(lyd_get_value(data), NULL, 8);
+        }
+
+        ret = lyd_find_path(node, "uid", 0, &data);
+        if (!ret) {
+            opts->uid = strtol(lyd_get_value(data), NULL, 10);
+        }
+
+        ret = lyd_find_path(node, "gid", 0, &data);
+        if (!ret) {
+            opts->gid = strtol(lyd_get_value(data), NULL, 10);
+        }
+
+        /* reset the logging options */
+        ly_log_options(prev_lo);
+
+        ret = nc_server_config_set_address_port(endpt, bind, NULL, 0);
+        if (ret) {
+            goto cleanup;
+        }
+    } else if (op == NC_OP_DELETE) {
+        nc_server_del_unix_socket(bind, endpt->opts.unixsock);
+    }
+
+cleanup:
+    return ret;
+}
+
+static int
 nc_server_configure(const struct lyd_node *node, NC_OPERATION op)
 {
     const char *name = LYD_NAME(node);
@@ -2027,6 +2151,10 @@
         if (nc_server_configure_mac_alg(node, op)) {
             goto error;
         }
+    } else if (!strcmp(name, "unix-socket")) {
+        if (nc_server_configure_unix_socket(node, op)) {
+            goto error;
+        }
     } else if (!strcmp(name, "cert-data")) {} else if (!strcmp(name, "expiration-date")) {} else if (!strcmp(name, "asymmetric-key")) {} else if (!strcmp(name, "certificate")) {} else if (!strcmp(name, "key-format")) {} else if (!strcmp(name,
             "cleartext-key")) {} else if (!strcmp(name, "hidden-key")) {} else if (!strcmp(name, "id_hint")) {} else if (!strcmp(name, "external-identity")) {} else if (!strcmp(name, "hash")) {} else if (!strcmp(name, "context")) {} else if (!strcmp(name,
             "target-protocol")) {} else if (!strcmp(name, "target-kdf")) {} else if (!strcmp(name, "client-authentication")) {} else if (!strcmp(name, "ca-certs")) {} else if (!strcmp(name, "ee-certs")) {} else if (!strcmp(name,
diff --git a/src/session_p.h b/src/session_p.h
index 6818ed1..e75dc34 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -234,6 +234,7 @@
 
 /* ACCESS unlocked */
 struct nc_server_unix_opts {
+    char *address;
     mode_t mode;
     uid_t uid;
     gid_t gid;
@@ -756,11 +757,10 @@
 /**
  * @brief Create a listening socket (AF_UNIX).
  *
- * @param[in] address UNIX address to listen on.
- * @param[in] opts The server options (unix permissions).
+ * @param[in] opts The server options (unix permissions and address of the socket).
  * @return Listening socket, -1 on error.
  */
-int nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts);
+int nc_sock_listen_unix(const struct nc_server_unix_opts *opts);
 
 /**
  * @brief Accept a new connection on a listening socket.
diff --git a/src/session_server.c b/src/session_server.c
index 9f01303..e0514e6 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -282,13 +282,13 @@
 }
 
 int
-nc_sock_listen_unix(const char *address, const struct nc_server_unix_opts *opts)
+nc_sock_listen_unix(const struct nc_server_unix_opts *opts)
 {
     struct sockaddr_un sun;
     int sock = -1;
 
-    if (strlen(address) > sizeof(sun.sun_path) - 1) {
-        ERR(NULL, "Socket path \"%s\" is longer than maximum length %d.", address, (int)(sizeof(sun.sun_path) - 1));
+    if (strlen(opts->address) > sizeof(sun.sun_path) - 1) {
+        ERR(NULL, "Socket path \"%s\" is longer than maximum length %d.", opts->address, (int)(sizeof(sun.sun_path) - 1));
         goto fail;
     }
 
@@ -300,11 +300,11 @@
 
     memset(&sun, 0, sizeof(sun));
     sun.sun_family = AF_UNIX;
-    snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "%s", address);
+    snprintf(sun.sun_path, sizeof(sun.sun_path) - 1, "%s", opts->address);
 
     unlink(sun.sun_path);
     if (bind(sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
-        ERR(NULL, "Could not bind \"%s\" (%s).", address, strerror(errno));
+        ERR(NULL, "Could not bind \"%s\" (%s).", opts->address, strerror(errno));
         goto fail;
     }
 
@@ -323,7 +323,7 @@
     }
 
     if (listen(sock, NC_REVERSE_QUEUE) == -1) {
-        ERR(NULL, "Unable to start listening on \"%s\" (%s).", address, strerror(errno));
+        ERR(NULL, "Unable to start listening on \"%s\" (%s).", opts->address, strerror(errno));
         goto fail;
     }
 
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index ca85067..2a13145 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -9,7 +9,7 @@
 
 # list of all the tests in each directory
 #set(tests test_io test_fd_comm test_init_destroy_client test_init_destroy_server test_client_thread test_thread_messages)
-set(tests test_two_channels test_keystore)
+set(tests test_two_channels test_keystore test_unix_socket)
 
 # only enable PAM tests if the version of PAM is greater than 1.4
 if(LIBPAM_HAVE_CONFDIR)
diff --git a/tests/test_auth.c b/tests/test_auth.c
index 29b22b1..5511da9 100644
--- a/tests/test_auth.c
+++ b/tests/test_auth.c
@@ -31,13 +31,12 @@
 
 #include "tests/config.h"
 
-#define NC_ACCEPT_TIMEOUT 100
-#define NC_PS_POLL_TIMEOUT 100
+#define NC_ACCEPT_TIMEOUT 2000
+#define NC_PS_POLL_TIMEOUT 2000
 
 struct ly_ctx *ctx;
 
 struct test_state {
-    // bariera
     pthread_barrier_t barrier;
 };
 
diff --git a/tests/test_keystore.c b/tests/test_keystore.c
index 5f583ad..c7e8af8 100644
--- a/tests/test_keystore.c
+++ b/tests/test_keystore.c
@@ -31,13 +31,12 @@
 
 #include "tests/config.h"
 
-#define NC_ACCEPT_TIMEOUT 100
-#define NC_PS_POLL_TIMEOUT 100
+#define NC_ACCEPT_TIMEOUT 2000
+#define NC_PS_POLL_TIMEOUT 2000
 
 struct ly_ctx *ctx;
 
 struct test_state {
-    // bariera
     pthread_barrier_t barrier;
 };
 
diff --git a/tests/test_nc3.c b/tests/test_nc3.c
deleted file mode 100644
index f74ab25..0000000
--- a/tests/test_nc3.c
+++ /dev/null
@@ -1,243 +0,0 @@
-/**
- * @file test_pam.c
- * @author Roman Janota <xjanot04@fit.vutbr.cz>
- * @brief libnetconf2 Linux PAM keyboard-interactive authentication test
- *
- * @copyright
- * Copyright (c) 2022 CESNET, z.s.p.o.
- *
- * This source code is licensed under BSD 3-Clause License (the "License").
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://opensource.org/licenses/BSD-3-Clause
- */
-
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <libyang/libyang.h>
-#include <log.h>
-#include <session_client.h>
-#include <session_server.h>
-#include "config_server.h"
-
-#include "tests/config.h"
-
-#define nc_assert(cond) if (!(cond)) { fprintf(stderr, "assert failed (%s:%d)\n", __FILE__, __LINE__); abort(); }
-
-#define NC_ACCEPT_TIMEOUT 5000
-#define NC_PS_POLL_TIMEOUT 5000
-
-const char *data =
-        "<netconf-server xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-server\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">"
-        "<listen yang:operation=\"create\">"
-        "<idle-timeout>10</idle-timeout>"
-        "<endpoint>"
-        "<name>default-ssh</name>"
-        "<ssh>"
-        "<tcp-server-parameters>"
-        "<local-address>127.0.0.1</local-address>"
-        "<local-port>10005</local-port>"
-        "</tcp-server-parameters>"
-        "<ssh-server-parameters>"
-        "<server-identity>"
-        "<host-key>"
-        "<name>key</name>"
-        "<public-key>"
-        "<local-definition>"
-        "<public-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:ssh-public-key-format</public-key-format>"
-        "<public-key>MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA6ojtjfDmvyQP1ZkIwBpr"
-        "97eKDuebvpoglRHRdvVuTpf/gU1VArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeV"
-        "n6KyvsX0HhsQtXwqPqwka5UCv6alwf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FT"
-        "irzQkjrDZUd3meDhNQTruCalGV4gfNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6w"
-        "NmsSqpwGxUhYLoSaM7b0dLmqP+ZczSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCU"
-        "UGkp6YCTL4Z2CeBEaJABWjDIDH+dKYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrz"
-        "ARDsfLjwUNxQJse1QSArjAytf0FKtGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rf"
-        "WZOAu44fUvPCaXDE6zXXeaVgoKCo4VHlho36erUcjlEBM+jk28IykbZGtBb6igKv"
-        "Ya1tPSgeYm/zJoFVjQcnr14uci/ft1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3"
-        "u7ZiuQEJTNm6+3cE4+lfwaBCBqBToE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMa"
-        "OQxmE0v9OmR/pL/PWIflVF4Zz5yVONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMh"
-        "jufl2qE2Q7fQIaav/1NqBVkCAwEAAQ==</public-key>"
-        "<private-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:rsa-private-key-format</private-key-format>"
-        "<cleartext-private-key>MIIJKAIBAAKCAgEA6ojtjfDmvyQP1ZkIwBpr97eKDuebvpoglRHRdvVuTpf/gU1V"
-        "ArAQmwGh05i6lm8TkVl1noMlIxLJDcWslaeVn6KyvsX0HhsQtXwqPqwka5UCv6al"
-        "wf/ivAvcNpcX1j0t/uIGCI4dSiKnzQCyf0FTirzQkjrDZUd3meDhNQTruCalGV4g"
-        "fNWIq3e1oGuwAn1tLlu9oTrE4HzMpgbNEU6wNmsSqpwGxUhYLoSaM7b0dLmqP+Zc"
-        "zSS0Uac0PFNkehGQ2CYIT80f580o4XGtoLCUUGkp6YCTL4Z2CeBEaJABWjDIDH+d"
-        "KYIUBqUpz4Th12gXAP+h+3qI6+9eppeHrfrzARDsfLjwUNxQJse1QSArjAytf0FK"
-        "tGHrORc7W0TiCFvR0zaoUNLTKk7enTiRQ9rfWZOAu44fUvPCaXDE6zXXeaVgoKCo"
-        "4VHlho36erUcjlEBM+jk28IykbZGtBb6igKvYa1tPSgeYm/zJoFVjQcnr14uci/f"
-        "t1+Na+hOIEoEEiKxcAPk2b2vBKNlRIW7WLJ3u7ZiuQEJTNm6+3cE4+lfwaBCBqBT"
-        "oE+dpzvoUXoMyFFReUFd1O5axu4fXgt00jMaOQxmE0v9OmR/pL/PWIflVF4Zz5yV"
-        "ONYaDVc7l+veY0oEZruEPJ0hlEgxuCzLrcMhjufl2qE2Q7fQIaav/1NqBVkCAwEA"
-        "AQKCAgAeRZw75Oszoqj0jfMmMILdD3Cfad+dY3FvLESYESeyt0XAX8XoOed6ymQj"
-        "1qPGxQGGkkBvPEgv1b3jrC8Rhfb3Ct39Z7mRpTar5iHhwwBUboBTUmQ0vR173iAH"
-        "X8sw2Oa17mCO/CDlr8Fu4Xcom7r3vlVBepo72VSjpPYMjN0MANjwhEi3NCyWzTXB"
-        "RgUK3TuZbzfzto0w2Irlpx0S7dAqxfk70jXBgwv2vSDWKfg1lL1X0BkMVX98xpMk"
-        "cjMW2muSqp4KBtTma4GqT6z0f7Y1Bs3lGLZmvPlBXxQVVvkFtiQsENCtSd/h17Gk"
-        "2mb4EbReaaBzwCYqJdRWtlpJ54kzy8U00co+Yn//ZS7sbbIDkqHPnXkpdIr+0rED"
-        "MlOw2Y3vRZCxqZFqfWCW0uzhwKqk2VoYqtDL+ORKG/aG/KTBQ4Y71Uh+7aabPwj5"
-        "R+NaVMjbqmrVeH70eKjoNVgcNYY1C9rGVF1d+LQEm7UsqS0DPp4wN9QKLAqIfuar"
-        "AhQBhZy1R7Sj1r5macD9DsGxsurM4mHZV0LNmYLZiFHjTUb6iRSPD5RBFW80vcNt"
-        "xZ0cxmkLtxrj/DVyExV11Cl0SbZLLa9mScYvxdl/qZutXt3PQyab0NiYxGzCD2Rn"
-        "LkCyxkh1vuHHjhvIWYfbd2VgZB/qGr+o9T07FGfMCu23//fugQKCAQEA9UH38glH"
-        "/rAjZ431sv6ryUEFY8I2FyLTijtvoj9CNGcQn8vJQAHvUPfMdyqDoum6wgcTmG+U"
-        "XA6mZzpGQCiY8JW5CoItgXRoYgNzpvVVe2aLf51QGtNLLEFpNDMpCtI+I+COpAmG"
-        "vWAukku0pZfRjm9eb1ydvTpHlFC9+VhVUsLzw3VtSC5PVW6r65mZcYcB6SFVPap+"
-        "31ENP/9jOMFoymh57lSMZJMxTEA5b0l2miFb9Rp906Zqiud5zv2jIqF6gL70giW3"
-        "ovVxR7LGKKTKIa9pxawHwB6Ithygs7YoJkjF2dm8pZTMZKsQN92K70XGj07SmYRL"
-        "ZpkVD7i+cqbbKQKCAQEA9M6580Rcw6W0twfcy0/iB4U5ZS52EcCjW8vHlL+MpUo7"
-        "YvXadSgV1ZaM28zW/ZGk3wE0zy1YT5s30SQkm0NiWN3t/J0l19ccAOxlPWfjhF7v"
-        "IQZr7XMo5HeaK0Ak5+68J6bx6KgcXmlJOup7INaE8DyGXB6vd4K6957IXyqs3/bf"
-        "JAUmz49hnveCfLFdTVVT/Uq4IoPKfQSbSZc0BvPBsnBCF164l4jllGBaWS302dhg"
-        "W4cgxzG0SZGgNwow4AhB+ygiiS8yvOa7UcHfUObVrzWeeq9mYSQ1PkvUTjkWR2/Y"
-        "8xy7WP0TRBdJOVSs90H51lerEDGNQWvQvI97S9ZOsQKCAQB59u9lpuXtqwxAQCFy"
-        "fSFSuQoEHR2nDcOjF4GhbtHum15yCPaw5QVs/33nuPWze4ZLXReKk9p0mTh5V0p+"
-        "N3IvGlXl+uzEVu5d55eI7LIw5sLymHmwjWjxvimiMtrzLbCHSPHGc5JU9NLUH9/b"
-        "BY/JxGpy+NzcsHHOOQTwTdRIjviIOAo7fgQn2RyX0k+zXE8/7zqjqvji9zyemdNu"
-        "8we4uJICSntyvJwkbj/hrufTKEnBrwXpzfVn1EsH+6w32ZPBGLUhT75txJ8r56SR"
-        "q7l1XPU9vxovmT+lSMFF/Y0j1MbHWnds5H1shoFPNtYTvWBL/gfPHjIc+H23zsiu"
-        "3XlZAoIBAC2xB/Pnpoi9vOUMiqFH36AXtYa1DURy+AqCFlYlClMvb7YgvQ1w1eJv"
-        "nwrHSLk7HdKhnwGsLPduuRRH8q0n/osnoOutSQroE0n41UyIv2ZNccRwNmSzQcai"
-        "rBu2dSz02hlsh2otNl5IuGpOqXyPjXBpW4qGD6n2tH7THALnLC0BHtTSQVQsJsRM"
-        "3gX39LoiWvLDp2qJvplm6rTpi8Rgap6rZSqHe1yNKIxxD2vlr/WY9SMgLXYASO4S"
-        "SBz9wfGOmQIPk6KXNJkdV4kC7nNjIi75iwLLCgjHgUiHTrDq5sWekpeNnUoWsinb"
-        "Tsdsjnv3zHG9GyiClyLGxMbs4M5eyYECggEBAKuC8ZMpdIrjk6tERYB6g0LnQ7mW"
-        "8XYbDFAmLYMLs9yfG2jcjVbsW9Kugsr+3poUUv/q+hNO3jfY4HazhZDa0MalgNPo"
-        "Swr/VNRnkck40x2ovFb989J7yl++zTrnIrax9XRH1V0cNu+Kj7OMwZ2RRfbNv5JB"
-        "dOZPvkfqyIKFmbQgYbtD66rHuzNOfJpzqr/WVLO57/zzW8245NKG2B6B0oXkei/K"
-        "qDY0DAbHR3i3EOj1NPtVI1FC/xX8R9BREaid458bqoHJKuInrGcBjaUI9Cvymv8T"
-        "bstUgD6NPbJR4Sm6vrLeUqzjWZP3t1+Z6DjXmnpR2vvhMU/FWb//21p/88o=</cleartext-private-key>"
-        "</local-definition>"
-        "</public-key>"
-        "</host-key>"
-        "</server-identity>"
-        "<client-authentication>"
-        "<users>"
-        "<user>"
-        "<name>test</name>"
-        "<public-keys>"
-        "<local-definition>"
-        "<public-key>"
-        "<name>client</name>"
-        "<public-key-format xmlns:ct=\"urn:ietf:params:xml:ns:yang:ietf-crypto-types\">ct:ssh-public-key-format</public-key-format>"
-        "<public-key>MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvpKj6gy/Rm1pqlUIaeKp"
-        "WuL2KOJBbodhxuPG+0S6f+Jf4LopOB76tmg1RQ/bAXLNxXkG46Cx9UOHaFK/Ixul"
-        "cCbH6LxOUg90/HVS7NnbaVtDsl03HG9CPZTlQzM+n+iFAXv5ub5PFzW3VCCNDSfM"
-        "tXUOdVR93u/OAc7uz0nWjGhWnOH5MPJCQPS8ZFpL9hQxQuyAXFY0YLW/9eRMDgx/"
-        "OPTuvlTxIF+YHaMzY+Wy+Oaygwb78dCow+3RQRgCB20o5o6exx2nX2Cqr7UJzG/N"
-        "30XCusKIcTT978td8AU7UjpbzoNehm/tmQdDq+8IDsNfWbxCHDYLMD8IR32UDXGD"
-        "DVSwrtNgUs8HWNNCBKjTNCeQf1v/yiRd7hRf2aj+w9sDu8PI+VC9pabsRe2KxnnD"
-        "U9Sq+4IB3ZM3C5XpJDbu8DVigGZSevim7p/D6mW2phlyxtlK9WmQ5Misg/Z8jM7E"
-        "Z3gJcTvh20IS6I4plG7DJvsIC/Pc3IS2JC/w0prCZa8gOKob8x2mjjQcOA1eVIUm"
-        "yw6WbV1X65/jAJvIS6an/oFAk4bBTfJA6fYfU4Pb9NWovYxm/eNR5BbRmFFh0uXa"
-        "0s92S50iOotf8CnW7PZ7PWKgzKqtnN9Ob+Ye7WjDdG+NCrhkiDBOCuHDrHXwqaxW"
-        "BmUICo2mnUMK7JuJNSZe5DMCAwEAAQ==</public-key>"
-        "</public-key>"
-        "</local-definition>"
-        "</public-keys>"
-        "<none/>"
-        "</user>"
-        "</users>"
-        "</client-authentication>"
-        "<transport-params>"
-        "<host-key>"
-        "<host-key-alg xmlns:sshpka=\"urn:ietf:params:xml:ns:yang:iana-ssh-public-key-algs\">sshpka:ssh-rsa</host-key-alg>"
-        "<host-key-alg xmlns:sshpka=\"urn:ietf:params:xml:ns:yang:iana-ssh-public-key-algs\">sshpka:rsa-sha2-512</host-key-alg>"
-        "</host-key>"
-        "<key-exchange>"
-        "<key-exchange-alg xmlns:sshkea=\"urn:ietf:params:xml:ns:yang:iana-ssh-key-exchange-algs\">sshkea:diffie-hellman-group18-sha512</key-exchange-alg>"
-        "</key-exchange>"
-        "<encryption>"
-        "<encryption-alg xmlns:sshea=\"urn:ietf:params:xml:ns:yang:iana-ssh-encryption-algs\">sshea:aes256-cbc</encryption-alg>"
-        "</encryption>"
-        "<mac>"
-        "<mac-alg xmlns:sshma=\"urn:ietf:params:xml:ns:yang:iana-ssh-mac-algs\">sshma:hmac-sha1</mac-alg>"
-        "</mac>"
-        "</transport-params>"
-        "</ssh-server-parameters>"
-        "</ssh>"
-        "</endpoint>"
-        "</listen>"
-        "</netconf-server>";
-
-static int
-setup(struct ly_ctx *ctx)
-{
-    int i;
-    const char *all_features[] = {"*", NULL};
-    /* no ssh-x509-certs */
-    const char *ssh_common_features[] = {"transport-params", "public-key-generation", NULL};
-    /* no ssh-server-keepalives and local-user-auth-hostbased */
-    const char *ssh_server_features[] = {"local-users-supported", "local-user-auth-publickey", "local-user-auth-password", "local-user-auth-none", NULL};
-    /* no private-key-encryption and csr-generation */
-    const char *crypto_types_features[] = {
-        "one-symmetric-key-format", "one-asymmetric-key-format", "symmetrically-encrypted-value-format",
-        "asymmetrically-encrypted-value-format", "cms-enveloped-data-format", "cms-encrypted-data-format",
-        "p10-based-csrs", "certificate-expiration-notification", "hidden-keys", "password-encryption",
-        "symmetric-key-encryption", NULL
-    };
-
-    const char *module_names[] = {
-        "ietf-netconf-server", "ietf-tls-common", "ietf-tls-server", "ietf-truststore", "iana-crypt-hash", "ietf-keystore",
-        "ietf-tcp-server", "ietf-tcp-common", "ietf-tcp-client", "iana-ssh-public-key-algs",
-        "iana-ssh-key-exchange-algs", "iana-ssh-encryption-algs", "iana-ssh-mac-algs", NULL
-    };
-
-    for (i = 0; module_names[i] != NULL; i++) {
-        if (!ly_ctx_load_module(ctx, module_names[i], NULL, all_features)) {
-            fprintf(stderr, "Loading module (%s) failed.\n", module_names[i]);
-            goto error;
-        }
-    }
-
-    if (!ly_ctx_load_module(ctx, "ietf-ssh-common", NULL, ssh_common_features)) {
-        fprintf(stderr, "Loading module (ietf-ssh-common) failed.\n");
-        goto error;
-    }
-    if (!ly_ctx_load_module(ctx, "ietf-ssh-server", NULL, ssh_server_features)) {
-        fprintf(stderr, "Loading module (ietf-ssh-server) failed.\n");
-        goto error;
-    }
-    if (!ly_ctx_load_module(ctx, "ietf-crypto-types", NULL, crypto_types_features)) {
-        fprintf(stderr, "Loading module (ietf-crypto-types) failed.\n");
-        goto error;
-    }
-
-    return 0;
-
-error:
-    return 1;
-}
-
-int
-main(void)
-{
-    int ret;
-    struct ly_ctx *ctx;
-    struct lyd_node *tree;
-
-    nc_verbosity(NC_VERB_VERBOSE);
-
-    ret = ly_ctx_new("/home/roman/Downloads/yang", 0, &ctx);
-    nc_assert(!ret);
-
-    ret = setup(ctx);
-    nc_assert(!ret);
-
-    ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
-    nc_assert(!ret);
-
-    ret = nc_server_config_setup(tree);
-    nc_assert(!ret);
-
-    nc_server_init();
-
-    nc_server_destroy();
-    lyd_free_all(tree);
-    ly_ctx_destroy(ctx);
-    return 0;
-}
diff --git a/tests/test_two_channels.c b/tests/test_two_channels.c
index 37ac20c..ac7550e 100644
--- a/tests/test_two_channels.c
+++ b/tests/test_two_channels.c
@@ -32,8 +32,8 @@
 
 #include "tests/config.h"
 
-#define NC_ACCEPT_TIMEOUT 5000
-#define NC_PS_POLL_TIMEOUT 500
+#define NC_ACCEPT_TIMEOUT 2000
+#define NC_PS_POLL_TIMEOUT 2000
 #define BACKOFF_TIMEOUT_USECS 100
 
 struct ly_ctx *ctx;
diff --git a/tests/test_unix_socket.c b/tests/test_unix_socket.c
new file mode 100644
index 0000000..56c1f12
--- /dev/null
+++ b/tests/test_unix_socket.c
@@ -0,0 +1,198 @@
+/**
+ * @file test_keystore.c
+ * @author Roman Janota <xjanot04@fit.vutbr.cz>
+ * @brief libnetconf2 Linux PAM keyboard-interactive authentication test
+ *
+ * @copyright
+ * Copyright (c) 2022 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://opensource.org/licenses/BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <pthread.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <cmocka.h>
+
+#include <config_server.h>
+#include <libnetconf.h>
+#include <libyang/libyang.h>
+#include <log.h>
+#include <session_client.h>
+#include <session_server.h>
+
+#include "tests/config.h"
+
+#define NC_ACCEPT_TIMEOUT 2000
+#define NC_PS_POLL_TIMEOUT 2000
+
+struct ly_ctx *ctx;
+
+struct test_state {
+    pthread_barrier_t barrier;
+};
+
+const char *data =
+        "<netconf-server xmlns=\"urn:ietf:params:xml:ns:yang:ietf-netconf-server\" xmlns:yang=\"urn:ietf:params:xml:ns:yang:1\" yang:operation=\"none\">\n"
+        "    <listen yang:operation=\"create\">\n"
+        "        <idle-timeout>10</idle-timeout>\n"
+        "        <endpoint>\n"
+        "            <name>default-unix-socket</name>\n"
+        "            <unix-socket xmlns=\"urn:cesnet:libnetconf2-netconf-server\">\n"
+        "                <path>/tmp/nc2_test_unix_sock</path>\n"
+        "            </unix-socket>\n"
+        "        </endpoint>\n"
+        "    </listen>\n"
+        "</netconf-server>\n";
+
+static void *
+server_thread(void *arg)
+{
+    int ret;
+    NC_MSG_TYPE msgtype;
+    struct nc_session *session;
+    struct nc_pollsession *ps;
+    struct test_state *state = arg;
+
+    ps = nc_ps_new();
+    assert_non_null(ps);
+
+    /* accept a session and add it to the poll session structure */
+    pthread_barrier_wait(&state->barrier);
+    msgtype = nc_accept(NC_ACCEPT_TIMEOUT, ctx, &session);
+    assert_int_equal(msgtype, NC_MSG_HELLO);
+
+    ret = nc_ps_add_session(ps, session);
+    assert_int_equal(ret, 0);
+
+    do {
+        ret = nc_ps_poll(ps, NC_PS_POLL_TIMEOUT, NULL);
+        assert_int_equal(ret & NC_PSPOLL_RPC, NC_PSPOLL_RPC);
+    } while (!(ret & NC_PSPOLL_SESSION_TERM));
+
+    nc_ps_clear(ps, 1, NULL);
+    nc_ps_free(ps);
+    nc_thread_destroy();
+    return NULL;
+}
+
+static void *
+client_thread(void *arg)
+{
+    struct nc_session *session = NULL;
+    struct test_state *state = arg;
+
+    pthread_barrier_wait(&state->barrier);
+    session = nc_connect_unix("/tmp/nc2_test_unix_sock", NULL);
+    assert_non_null(session);
+
+    nc_session_free(session, NULL);
+    nc_thread_destroy();
+    return NULL;
+}
+
+static void
+test_nc_connect_unix_socket(void **state)
+{
+    int ret, i;
+    pthread_t tids[2];
+
+    assert_non_null(state);
+
+    ret = pthread_create(&tids[0], NULL, client_thread, *state);
+    assert_int_equal(ret, 0);
+    ret = pthread_create(&tids[1], NULL, server_thread, *state);
+    assert_int_equal(ret, 0);
+
+    for (i = 0; i < 2; i++) {
+        pthread_join(tids[i], NULL);
+    }
+}
+
+static int
+setup_f(void **state)
+{
+    int ret;
+    struct lyd_node *tree;
+    struct test_state *test_state;
+
+    nc_verbosity(NC_VERB_VERBOSE);
+
+    /* init barrier */
+    test_state = malloc(sizeof *test_state);
+    assert_non_null(test_state);
+
+    ret = pthread_barrier_init(&test_state->barrier, NULL, 2);
+    assert_int_equal(ret, 0);
+
+    *state = test_state;
+
+    ret = ly_ctx_new(MODULES_DIR, 0, &ctx);
+    assert_int_equal(ret, 0);
+
+    /* initialize context */
+    ret = nc_server_init_ctx(&ctx);
+    assert_int_equal(ret, 0);
+
+    /* load ietf-netconf-server module and it's dependencies into context */
+    ret = nc_server_config_load_modules(&ctx);
+    assert_int_equal(ret, 0);
+
+    /* parse yang data */
+    ret = lyd_parse_data_mem(ctx, data, LYD_XML, LYD_PARSE_NO_STATE | LYD_PARSE_STRICT, LYD_VALIDATE_NO_STATE, &tree);
+    assert_int_equal(ret, 0);
+
+    /* configure the server based on the data */
+    ret = nc_server_config_setup(tree);
+    assert_int_equal(ret, 0);
+
+    /* initialize client */
+    nc_client_init();
+
+    /* initialize server */
+    ret = nc_server_init();
+    assert_int_equal(ret, 0);
+
+    lyd_free_all(tree);
+
+    return 0;
+}
+
+static int
+teardown_f(void **state)
+{
+    int ret = 0;
+    struct test_state *test_state;
+
+    assert_non_null(state);
+    test_state = *state;
+
+    ret = pthread_barrier_destroy(&test_state->barrier);
+    assert_int_equal(ret, 0);
+
+    free(*state);
+    nc_client_destroy();
+    nc_server_destroy();
+    ly_ctx_destroy(ctx);
+
+    return 0;
+}
+
+int
+main(void)
+{
+    const struct CMUnitTest tests[] = {
+        cmocka_unit_test_setup_teardown(test_nc_connect_unix_socket, setup_f, teardown_f),
+    };
+
+    setenv("CMOCKA_TEST_ABORT", "1", 1);
+    return cmocka_run_group_tests(tests, NULL, NULL);
+}