session CHANGE option store adjusted for ietf-netconf-server granularity
diff --git a/src/session_server.c b/src/session_server.c
index 4bc841f..608887c 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -40,7 +40,7 @@
 extern pthread_mutex_t tls_ch_opts_lock;
 
 struct nc_endpt *
-nc_server_endpt_lock(const char *name, NC_TRANSPORT_IMPL ti)
+nc_server_endpt_lock(const char *name, uint16_t *idx)
 {
     uint16_t i;
     struct nc_endpt *endpt = NULL;
@@ -49,7 +49,7 @@
     pthread_rwlock_rdlock(&server_opts.endpt_array_lock);
 
     for (i = 0; i < server_opts.endpt_count; ++i) {
-        if ((server_opts.binds[i].ti == ti) && !strcmp(server_opts.endpts[i].name, name)) {
+        if (!strcmp(server_opts.endpts[i].name, name)) {
             endpt = &server_opts.endpts[i];
             break;
         }
@@ -65,6 +65,10 @@
     /* ENDPT LOCK */
     pthread_mutex_lock(&endpt->endpt_lock);
 
+    if (idx) {
+        *idx = i;
+    }
+
     return endpt;
 }
 
@@ -390,7 +394,7 @@
     pthread_spin_destroy(&server_opts.sid_lock);
 
 #if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
-    nc_server_del_endpt(NULL, 0);
+    nc_server_del_endpt(NULL);
 #endif
     nc_destroy();
 }
@@ -1226,24 +1230,20 @@
 
 #if defined(NC_ENABLED_SSH) || defined(NC_ENABLED_TLS)
 
-int
-nc_server_add_endpt_listen(const char *name, const char *address, uint16_t port, NC_TRANSPORT_IMPL ti)
+API int
+nc_server_add_endpt(const char *name)
 {
-    int sock;
     uint16_t i;
 #ifdef NC_ENABLED_SSH
-    struct nc_server_ssh_opts *ssh_opts;
+    uint16_t bind_ssh_idx;
+#endif
+#ifdef NC_ENABLED_TLS
+    uint16_t bind_tls_idx;
 #endif
 
     if (!name) {
         ERRARG("name");
         return -1;
-    } else if (!address) {
-        ERRARG("address");
-        return -1;
-    } else if (!port) {
-        ERRARG("port");
-        return -1;
     }
 
     /* WRITE LOCK */
@@ -1251,7 +1251,7 @@
 
     /* check name uniqueness */
     for (i = 0; i < server_opts.endpt_count; ++i) {
-        if ((server_opts.binds[i].ti == ti) && !strcmp(server_opts.endpts[i].name, name)) {
+        if (!strcmp(server_opts.endpts[i].name, name)) {
             ERR("Endpoint \"%s\" already exists.", name);
             /* WRITE UNLOCK */
             pthread_rwlock_unlock(&server_opts.endpt_array_lock);
@@ -1259,63 +1259,71 @@
         }
     }
 
-    sock = nc_sock_listen(address, port);
-    if (sock == -1) {
-        /* WRITE UNLOCK */
-        pthread_rwlock_unlock(&server_opts.endpt_array_lock);
-        return -1;
-    }
-
     ++server_opts.endpt_count;
-    server_opts.binds = nc_realloc(server_opts.binds, server_opts.endpt_count * sizeof *server_opts.binds);
     server_opts.endpts = nc_realloc(server_opts.endpts, server_opts.endpt_count * sizeof *server_opts.endpts);
-    if (!server_opts.binds || !server_opts.endpts) {
+    if (!server_opts.endpts) {
         ERRMEM;
         /* WRITE UNLOCK */
         pthread_rwlock_unlock(&server_opts.endpt_array_lock);
-        close(sock);
+        return -1;
+    }
+    server_opts.endpts[server_opts.endpt_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
+
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+    server_opts.binds = nc_realloc(server_opts.binds, 2 * server_opts.endpt_count * sizeof *server_opts.binds);
+    bind_ssh_idx = (server_opts.endpt_count - 1) * 2;
+    bind_tls_idx = (server_opts.endpt_count - 1) * 2 + 1;
+#else
+    server_opts.binds = nc_realloc(server_opts.binds, server_opts.endpt_count * sizeof *server_opts.binds);
+#   ifdef NC_ENABLED_SSH
+    bind_ssh_idx = server_opts.endpt_count - 1;
+#   endif
+#   ifdef NC_ENABLED_TLS
+    bind_tls_idx = server_opts.endpt_count - 1;
+#   endif
+#endif
+    if (!server_opts.binds) {
+        ERRMEM;
+        /* WRITE UNLOCK */
+        pthread_rwlock_unlock(&server_opts.endpt_array_lock);
         return -1;
     }
 
-    server_opts.endpts[server_opts.endpt_count - 1].name = lydict_insert(server_opts.ctx, name, 0);
-    server_opts.binds[server_opts.endpt_count - 1].address = lydict_insert(server_opts.ctx, address, 0);
-    server_opts.binds[server_opts.endpt_count - 1].port = port;
-    server_opts.binds[server_opts.endpt_count - 1].sock = sock;
-    server_opts.binds[server_opts.endpt_count - 1].ti = ti;
-    switch (ti) {
 #ifdef NC_ENABLED_SSH
-    case NC_TI_LIBSSH:
-        ssh_opts = calloc(1, sizeof *ssh_opts);
-        if (!ssh_opts) {
-            ERRMEM;
-            /* WRITE UNLOCK */
-            pthread_rwlock_unlock(&server_opts.endpt_array_lock);
-            return -1;
-        }
-        /* set default values */
-        ssh_opts->auth_methods = NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE;
-        ssh_opts->auth_attempts = 3;
-        ssh_opts->auth_timeout = 10;
+    server_opts.binds[bind_ssh_idx].address = NULL;
+    server_opts.binds[bind_ssh_idx].port = 0;
+    server_opts.binds[bind_ssh_idx].sock = -1;
+    server_opts.binds[bind_ssh_idx].ti = NC_TI_LIBSSH;
 
-        server_opts.endpts[server_opts.endpt_count - 1].ti_opts = ssh_opts;
-        break;
-#endif
-#ifdef NC_ENABLED_TLS
-    case NC_TI_OPENSSL:
-        server_opts.endpts[server_opts.endpt_count - 1].ti_opts = calloc(1, sizeof(struct nc_server_tls_opts));
-        if (!server_opts.endpts[server_opts.endpt_count - 1].ti_opts) {
-            ERRMEM;
-            /* WRITE UNLOCK */
-            pthread_rwlock_unlock(&server_opts.endpt_array_lock);
-            return -1;
-        }
-        break;
-#endif
-    default:
-        ERRINT;
-        server_opts.endpts[server_opts.endpt_count - 1].ti_opts = NULL;
-        break;
+    server_opts.endpts[server_opts.endpt_count - 1].ssh_opts = calloc(1, sizeof(struct nc_server_ssh_opts));
+    if (!server_opts.endpts[server_opts.endpt_count - 1].ssh_opts) {
+        ERRMEM;
+        /* WRITE UNLOCK */
+        pthread_rwlock_unlock(&server_opts.endpt_array_lock);
+        return -1;
     }
+    /* set default values */
+    server_opts.endpts[server_opts.endpt_count - 1].ssh_opts->auth_methods =
+        NC_SSH_AUTH_PUBLICKEY | NC_SSH_AUTH_PASSWORD | NC_SSH_AUTH_INTERACTIVE;
+    server_opts.endpts[server_opts.endpt_count - 1].ssh_opts->auth_attempts = 3;
+    server_opts.endpts[server_opts.endpt_count - 1].ssh_opts->auth_timeout = 10;
+#endif
+
+#ifdef NC_ENABLED_TLS
+    server_opts.binds[bind_tls_idx].address = NULL;
+    server_opts.binds[bind_tls_idx].port = 0;
+    server_opts.binds[bind_tls_idx].sock = -1;
+    server_opts.binds[bind_tls_idx].ti = NC_TI_OPENSSL;
+
+    server_opts.endpts[server_opts.endpt_count - 1].tls_opts = calloc(1, sizeof(struct nc_server_tls_opts));
+    if (!server_opts.endpts[server_opts.endpt_count - 1].tls_opts) {
+        ERRMEM;
+        /* WRITE UNLOCK */
+        pthread_rwlock_unlock(&server_opts.endpt_array_lock);
+        return -1;
+    }
+#endif
+
     pthread_mutex_init(&server_opts.endpts[server_opts.endpt_count - 1].endpt_lock, NULL);
 
     /* WRITE UNLOCK */
@@ -1330,7 +1338,7 @@
     struct nc_endpt *endpt;
     struct nc_bind *bind = NULL;
     uint16_t i;
-    int sock;
+    int sock = -1, set_addr;
 
     if (!endpt_name) {
         ERRARG("endpt_name");
@@ -1343,42 +1351,70 @@
         return -1;
     }
 
+    if (address) {
+        set_addr = 1;
+    } else {
+        set_addr = 0;
+    }
+
     /* LOCK */
-    endpt = nc_server_endpt_lock(endpt_name, ti);
+    endpt = nc_server_endpt_lock(endpt_name, &i);
     if (!endpt) {
         return -1;
     }
 
-    /* we need to learn the index, to get the bind :-/ */
-    for (i = 0; i < server_opts.endpt_count; ++i) {
-        if (&server_opts.endpts[i] == endpt) {
-            bind = &server_opts.binds[i];
-        }
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+    if (ti == NC_TI_LIBSSH) {
+        bind = &server_opts.binds[2 * i];
+    } else {
+        bind = &server_opts.binds[2 * i + 1];
     }
+#else
+    bind = &server_opts.binds[i];
+    assert(bind->ti == ti);
+#endif
     if (!bind) {
         ERRINT;
         goto fail;
     }
 
-    if (address) {
-        sock = nc_sock_listen(address, bind->port);
+    if (set_addr) {
+        port = bind->port;
     } else {
-        sock = nc_sock_listen(bind->address, port);
-    }
-    if (sock == -1) {
-        goto fail;
+        address = bind->address;
     }
 
-    /* close old socket, update parameters */
-    close(bind->sock);
-    bind->sock = sock;
-    if (address) {
+    /* we have all the information we need to create a listening socket */
+    if (address && port) {
+        /* create new socket, close the old one */
+        sock = nc_sock_listen(address, port);
+        if (sock == -1) {
+            goto fail;
+        }
+
+        if (bind->sock > -1) {
+            close(bind->sock);
+        }
+        bind->sock = sock;
+    } /* else we are just setting address or port */
+
+    if (set_addr) {
         lydict_remove(server_opts.ctx, bind->address);
         bind->address = lydict_insert(server_opts.ctx, address, 0);
     } else {
         bind->port = port;
     }
 
+    if (sock > -1) {
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+        VRB("Listening on %s:%u for %s connections.", address, port, (ti == NC_TI_LIBSSH ? "SSH" : "TLS"));
+#elif defined(NC_ENABLED_SSH)
+        VRB("Listening on %s:%u for SSH connections.", address, port);
+#else
+        VRB("Listening on %s:%u for TLS connections.", address, port);
+#endif
+    }
+
     /* UNLOCK */
     nc_server_endpt_unlock(endpt);
     return 0;
@@ -1389,8 +1425,8 @@
     return -1;
 }
 
-int
-nc_server_del_endpt(const char *name, NC_TRANSPORT_IMPL ti)
+API int
+nc_server_del_endpt(const char *name)
 {
     uint32_t i;
     int ret = -1;
@@ -1398,71 +1434,90 @@
     /* WRITE LOCK */
     pthread_rwlock_wrlock(&server_opts.endpt_array_lock);
 
-    if (!name && !ti) {
-        /* remove all */
+    if (!name) {
+        /* remove all endpoints */
         for (i = 0; i < server_opts.endpt_count; ++i) {
             lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
-            lydict_remove(server_opts.ctx, server_opts.binds[i].address);
-
-            close(server_opts.binds[i].sock);
             pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
-            switch (server_opts.binds[i].ti) {
 #ifdef NC_ENABLED_SSH
-            case NC_TI_LIBSSH:
-                nc_server_ssh_clear_opts(server_opts.endpts[i].ti_opts);
-                break;
+            nc_server_ssh_clear_opts(server_opts.endpts[i].ssh_opts);
+            free(server_opts.endpts[i].ssh_opts);
 #endif
 #ifdef NC_ENABLED_TLS
-            case NC_TI_OPENSSL:
-                nc_server_tls_clear_opts(server_opts.endpts[i].ti_opts);
-                break;
+            nc_server_tls_clear_opts(server_opts.endpts[i].tls_opts);
+            free(server_opts.endpts[i].tls_opts);
 #endif
-            default:
-                ERRINT;
-                break;
-            }
-            free(server_opts.endpts[i].ti_opts);
-
             ret = 0;
         }
-        free(server_opts.binds);
-        server_opts.binds = NULL;
         free(server_opts.endpts);
         server_opts.endpts = NULL;
+
+        /* remove all binds */
+        for (i = 0; i < server_opts.endpt_count; ++i) {
+            lydict_remove(server_opts.ctx, server_opts.binds[i].address);
+            if (server_opts.binds[i].sock > -1) {
+                close(server_opts.binds[i].sock);
+            }
+        }
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+        for (; i < 2 * server_opts.endpt_count; ++i) {
+            lydict_remove(server_opts.ctx, server_opts.binds[i].address);
+            if (server_opts.binds[i].sock > -1) {
+                close(server_opts.binds[i].sock);
+            }
+        }
+#endif
+        free(server_opts.binds);
+        server_opts.binds = NULL;
+
         server_opts.endpt_count = 0;
 
     } else {
-        /* remove one name endpoint or all ti endpoints */
+        /* remove one endpoint with bind(s) */
         for (i = 0; i < server_opts.endpt_count; ++i) {
-            if ((server_opts.binds[i].ti == ti) &&
-                    (!name || !strcmp(server_opts.endpts[i].name, name))) {
-
+            if (!strcmp(server_opts.endpts[i].name, name)) {
+                /* remove endpt */
                 lydict_remove(server_opts.ctx, server_opts.endpts[i].name);
-                lydict_remove(server_opts.ctx, server_opts.binds[i].address);
-                close(server_opts.binds[i].sock);
                 pthread_mutex_destroy(&server_opts.endpts[i].endpt_lock);
-                switch (server_opts.binds[i].ti) {
 #ifdef NC_ENABLED_SSH
-                case NC_TI_LIBSSH:
-                    nc_server_ssh_clear_opts(server_opts.endpts[i].ti_opts);
-                    break;
+                nc_server_ssh_clear_opts(server_opts.endpts[i].ssh_opts);
+                free(server_opts.endpts[i].ssh_opts);
 #endif
 #ifdef NC_ENABLED_TLS
-                case NC_TI_OPENSSL:
-                    nc_server_tls_clear_opts(server_opts.endpts[i].ti_opts);
-                    break;
+                nc_server_tls_clear_opts(server_opts.endpts[i].tls_opts);
+                free(server_opts.endpts[i].tls_opts);
 #endif
-                default:
-                    ERRINT;
-                    break;
-                }
-                free(server_opts.endpts[i].ti_opts);
 
+                /* remove bind(s) */
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+                i *= 2;
+                lydict_remove(server_opts.ctx, server_opts.binds[i].address);
+                if (server_opts.binds[i].sock > -1) {
+                    close(server_opts.binds[i].sock);
+                }
+                ++i;
+#endif
+                lydict_remove(server_opts.ctx, server_opts.binds[i].address);
+                if (server_opts.binds[i].sock > -1) {
+                    close(server_opts.binds[i].sock);
+                }
+
+                /* move last endpt and bind(s) to the empty space */
                 --server_opts.endpt_count;
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+                --i;
+                i /= 2;
+                if (i < server_opts.endpt_count) {
+                    memcpy(&server_opts.binds[2 * i], &server_opts.binds[2 * server_opts.endpt_count], 2 * sizeof *server_opts.binds);
+                    memcpy(&server_opts.endpts[i], &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
+                }
+#else
                 if (i < server_opts.endpt_count) {
                     memcpy(&server_opts.binds[i], &server_opts.binds[server_opts.endpt_count], sizeof *server_opts.binds);
                     memcpy(&server_opts.endpts[i], &server_opts.endpts[server_opts.endpt_count], sizeof *server_opts.endpts);
-                } else if (!server_opts.endpt_count) {
+                }
+#endif
+                else if (!server_opts.endpt_count) {
                     free(server_opts.binds);
                     server_opts.binds = NULL;
                     free(server_opts.endpts);
@@ -1470,11 +1525,7 @@
                 }
 
                 ret = 0;
-
-                if (name) {
-                    /* one name endpoint removed, they are unique, we're done */
-                    break;
-                }
+                break;
             }
         }
     }
@@ -1491,7 +1542,7 @@
     NC_MSG_TYPE msgtype;
     int sock, ret;
     char *host = NULL;
-    uint16_t port, idx;
+    uint16_t port, endpt_idx, bind_idx;
 
     if (!server_opts.ctx) {
         ERRINIT;
@@ -1513,7 +1564,7 @@
         return NC_MSG_ERROR;
     }
 
-    ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, timeout, &host, &port, &idx);
+    ret = nc_sock_accept_binds(server_opts.binds, server_opts.endpt_count, timeout, &host, &port, &bind_idx);
 
     if (ret < 1) {
         /* WRITE UNLOCK */
@@ -1551,11 +1602,19 @@
     }
     pthread_mutex_init((*session)->ti_lock, NULL);
 
-    (*session)->data = server_opts.endpts[idx].ti_opts;
+    endpt_idx = bind_idx;
+    /* transform index as needed */
+#if defined(NC_ENABLED_SSH) && defined(NC_ENABLED_TLS)
+    if (server_opts.binds[bind_idx].ti == NC_TI_OPENSSL) {
+        --endpt_idx;
+    }
+    endpt_idx /= 2;
+#endif
 
     /* sock gets assigned to session or closed */
 #ifdef NC_ENABLED_SSH
-    if (server_opts.binds[idx].ti == NC_TI_LIBSSH) {
+    if (server_opts.binds[bind_idx].ti == NC_TI_LIBSSH) {
+        (*session)->data = server_opts.endpts[endpt_idx].ssh_opts;
         ret = nc_accept_ssh_session(*session, sock, timeout);
         if (ret < 0) {
             msgtype = NC_MSG_ERROR;
@@ -1567,7 +1626,8 @@
     } else
 #endif
 #ifdef NC_ENABLED_TLS
-    if (server_opts.binds[idx].ti == NC_TI_OPENSSL) {
+    if (server_opts.binds[bind_idx].ti == NC_TI_OPENSSL) {
+        (*session)->data = server_opts.endpts[endpt_idx].tls_opts;
         ret = nc_accept_tls_session(*session, sock, timeout);
         if (ret < 0) {
             msgtype = NC_MSG_ERROR;