Merge pull request #49 from jktjkt/fix-ipv6

Use proper size for inet_ntop's buffer
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1ee8cb9..b4f2902 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -29,7 +29,7 @@
 # set version
 set(LIBNETCONF2_MAJOR_VERSION 0)
 set(LIBNETCONF2_MINOR_VERSION 11)
-set(LIBNETCONF2_MICRO_VERSION 3)
+set(LIBNETCONF2_MICRO_VERSION 4)
 set(LIBNETCONF2_VERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION}.${LIBNETCONF2_MICRO_VERSION})
 set(LIBNETCONF2_SOVERSION ${LIBNETCONF2_MAJOR_VERSION}.${LIBNETCONF2_MINOR_VERSION})
 
diff --git a/src/messages_server.c b/src/messages_server.c
index 9962af1..25a6eaa 100644
--- a/src/messages_server.c
+++ b/src/messages_server.c
@@ -361,7 +361,7 @@
 }
 
 API struct nc_server_error *
-nc_err_libyang(void)
+nc_err_libyang(struct ly_ctx *ctx)
 {
     struct nc_server_error *e;
     struct lyxml_elem *elem;
@@ -373,15 +373,15 @@
         /* LY_SUCCESS */
         return NULL;
     } else if (ly_errno == LY_EVALID) {
-        switch (ly_vecode) {
+        switch (ly_vecode(ctx)) {
         /* RFC 6020 section 13 errors */
         case LYVE_NOUNIQ:
             e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
             nc_err_set_app_tag(e, "data-not-unique");
-            nc_err_set_path(e, ly_errpath());
+            nc_err_set_path(e, ly_errpath(ctx));
 
             /* parse the message and get all the information we need */
-            str = ly_errmsg();
+            str = ly_errmsg(ctx);
             uniqi = strchr(str, '"');
             uniqi++;
             uniqj = strchr(uniqi, '"');
@@ -431,17 +431,17 @@
         case LYVE_NOMAX:
             e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
             nc_err_set_app_tag(e, "too-many-elements");
-            nc_err_set_path(e, ly_errpath());
+            nc_err_set_path(e, ly_errpath(ctx));
             break;
         case LYVE_NOMIN:
             e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
             nc_err_set_app_tag(e, "too-few-elements");
-            nc_err_set_path(e, ly_errpath());
+            nc_err_set_path(e, ly_errpath(ctx));
             break;
         case LYVE_NOMUST:
             e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
-            if (ly_errapptag()[0]) {
-                nc_err_set_app_tag(e, ly_errapptag());
+            if (ly_errapptag(ctx)) {
+                nc_err_set_app_tag(e, ly_errapptag(ctx));
             } else {
                 nc_err_set_app_tag(e, "must-violation");
             }
@@ -450,14 +450,14 @@
         case LYVE_NOLEAFREF:
             e = nc_err(NC_ERR_DATA_MISSING);
             nc_err_set_app_tag(e, "instance-required");
-            nc_err_set_path(e, ly_errpath());
+            nc_err_set_path(e, ly_errpath(ctx));
             break;
         case LYVE_NOMANDCHOICE:
             e = nc_err(NC_ERR_DATA_MISSING);
             nc_err_set_app_tag(e, "missing-choice");
-            nc_err_set_path(e, ly_errpath());
+            nc_err_set_path(e, ly_errpath(ctx));
 
-            str = ly_errmsg();
+            str = ly_errmsg(ctx);
             stri = strchr(str, '"');
             stri++;
             strj = strchr(stri, '"');
@@ -467,26 +467,26 @@
             }
             break;
         case LYVE_INELEM:
-            str = ly_errpath();
+            str = ly_errpath(ctx);
             if (!strcmp(str, "/")) {
                 e = nc_err(NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_APP);
                 /* keep default message */
                 return e;
             } else {
-                e = nc_err(NC_ERR_UNKNOWN_ELEM, NC_ERR_TYPE_PROT, ly_errpath());
+                e = nc_err(NC_ERR_UNKNOWN_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
             }
             break;
         case LYVE_MISSELEM:
         case LYVE_INORDER:
-            e = nc_err(NC_ERR_MISSING_ELEM, NC_ERR_TYPE_PROT, ly_errpath());
+            e = nc_err(NC_ERR_MISSING_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
             break;
         case LYVE_INVAL:
-            e = nc_err(NC_ERR_BAD_ELEM, NC_ERR_TYPE_PROT, ly_errpath());
+            e = nc_err(NC_ERR_BAD_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
             break;
         case LYVE_INATTR:
         case LYVE_MISSATTR:
         case LYVE_INMETA:
-            str = ly_errmsg();
+            str = ly_errmsg(ctx);
             stri = strchr(str, '"');
             stri++;
             if (!strncmp(stri, "<none>:", 7)) {
@@ -495,12 +495,12 @@
             strj = strchr(stri, '"');
             strj--;
             attr = strndup(stri, (strj - stri) + 1);
-            if (ly_vecode == LYVE_INATTR) {
-                e = nc_err(NC_ERR_UNKNOWN_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath());
-            } else if (ly_vecode == LYVE_MISSATTR) {
-                e = nc_err(NC_ERR_MISSING_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath());
+            if (ly_vecode(ctx) == LYVE_INATTR) {
+                e = nc_err(NC_ERR_UNKNOWN_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
+            } else if (ly_vecode(ctx) == LYVE_MISSATTR) {
+                e = nc_err(NC_ERR_MISSING_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
             } else { /* LYVE_INMETA */
-                e = nc_err(NC_ERR_BAD_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath());
+                e = nc_err(NC_ERR_BAD_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
             }
             free(attr);
             break;
@@ -508,8 +508,8 @@
         case LYVE_NOWHEN:
             e = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_PROT);
             /* LYVE_NOCONSTR (length, range, pattern) can have a specific error-app-tag */
-            if (ly_errapptag()[0]) {
-                nc_err_set_app_tag(e, ly_errapptag());
+            if (ly_errapptag(ctx)) {
+                nc_err_set_app_tag(e, ly_errapptag(ctx));
             }
             break;
         default:
@@ -520,7 +520,7 @@
         /* non-validation (internal) error */
         e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
     }
-    nc_err_set_msg(e, ly_errmsg(), "en");
+    nc_err_set_msg(e, ly_errmsg(ctx), "en");
     return e;
 }
 
diff --git a/src/messages_server.h b/src/messages_server.h
index 151e50c..9d9d9c2 100644
--- a/src/messages_server.h
+++ b/src/messages_server.h
@@ -169,9 +169,10 @@
  * The function should be used immediately when a libyang function fails to generate
  * NETCONF error structure based on internal libyang error information (ly_errno, ly_errmsg, ...)
  *
+ * @param[in] ctx Libyang context to read the error from.
  * @return Server error structure, NULL on error.
  */
-struct nc_server_error *nc_err_libyang(void);
+struct nc_server_error *nc_err_libyang(struct ly_ctx *ctx);
 
 /**
  * @brief Get the \<error-type\> of a server error.
diff --git a/src/session_client.c b/src/session_client.c
index 0222166..1cdf586 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -425,12 +425,68 @@
     return model_data;
 }
 
+static int
+nc_ctx_load_module(struct nc_session *session, const char *name, const char *revision, int implement,
+                   ly_module_imp_clb user_clb, void *user_data, const struct lys_module **mod)
+{
+    int ret = 0;
+    struct ly_err_item *eitem;
+
+    *mod = ly_ctx_get_module(session->ctx, name, revision, 0);
+    if (*mod) {
+        if (implement && !(*mod)->implemented) {
+            /* make the present module implemented */
+            if (lys_set_implemented(*mod)) {
+                ERR("Failed to implement model \"%s\".", (*mod)->name);
+                ret = -1;
+            }
+        }
+    } else if (!(*mod) && implement) {
+        /* missing implemented module, load it ... */
+
+        /* clear all the errors and just collect them for now */
+        ly_err_clean(session->ctx, NULL);
+        ly_log_options(LY_LOSTORE);
+
+        /* 1) using only searchpaths */
+        *mod = ly_ctx_load_module(session->ctx, name, revision);
+
+        /* 2) using user callback */
+        if (!(*mod) && user_clb) {
+            ly_ctx_set_module_imp_clb(session->ctx, user_clb, user_data);
+            *mod = ly_ctx_load_module(session->ctx, name, revision);
+        }
+
+        /* 3) using get-schema callback */
+        if (!(*mod)) {
+            ly_ctx_set_module_imp_clb(session->ctx, &getschema_module_clb, session);
+            *mod = ly_ctx_load_module(session->ctx, name, revision);
+        }
+
+        /* unset callback back to use searchpath */
+        ly_ctx_set_module_imp_clb(session->ctx, NULL, NULL);
+
+        /* print errors on definite failure */
+        if (!(*mod)) {
+            for (eitem = ly_err_first(session->ctx); eitem && eitem->next; eitem = eitem->next) {
+                ly_err_print(eitem);
+            }
+            ret = -1;
+        }
+
+        /* clean the errors and restore logging */
+        ly_err_clean(session->ctx, NULL);
+        ly_log_options(LY_LOLOG | LY_LOSTORE_LAST);
+    }
+
+    return ret;
+}
+
 /* SCHEMAS_DIR not used (implicitly) */
 static int
 nc_ctx_fill_cpblts(struct nc_session *session, ly_module_imp_clb user_clb, void *user_data)
 {
     int ret = 1;
-    LY_LOG_LEVEL verb;
     const struct lys_module *mod;
     char *ptr, *ptr2;
     const char *module_cpblt;
@@ -465,41 +521,9 @@
             revision = strndup(ptr, ptr2 - ptr);
         }
 
-        mod = ly_ctx_get_module(session->ctx, name, revision, 0);
-        if (mod) {
-            if (!mod->implemented) {
-                /* make the present module implemented */
-                if (lys_set_implemented(mod)) {
-                    ERR("Failed to implement model \"%s\".", mod->name);
-                    goto cleanup;
-                }
-            }
-        } else {
-            /* missing implemented module, load it ... */
-
-            /* expecting errors here */
-            verb = ly_verb(LY_LLSILENT);
-
-            /* 1) using only searchpaths */
-            mod = ly_ctx_load_module(session->ctx, name, revision);
-
-            /* 2) using user callback */
-            if (!mod && user_clb) {
-                ly_ctx_set_module_imp_clb(session->ctx, user_clb, user_data);
-                mod = ly_ctx_load_module(session->ctx, name, revision);
-            }
-
-            /* 3) using get-schema callback */
-            if (!mod) {
-                ly_ctx_set_module_imp_clb(session->ctx, &getschema_module_clb, session);
-                mod = ly_ctx_load_module(session->ctx, name, revision);
-            }
-
-            /* revert the changed verbosity level */
-            ly_verb(verb);
-
-            /* unset callback back to use searchpath */
-            ly_ctx_set_module_imp_clb(session->ctx, NULL, NULL);
+        if (nc_ctx_load_module(session, name, revision, 1, user_clb, user_data, &mod)) {
+            ret = 1;
+            goto cleanup;
         }
 
         if (!mod) {
@@ -513,8 +537,6 @@
             /* all loading ways failed, the schema will be ignored in the received data */
             WRN("Failed to load schema \"%s@%s\".", name, revision ? revision : "<latest>");
             session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
-
-            /* TODO: maybe re-print hidden error messages */
         } else {
             /* set features - first disable all to enable specified then */
             lys_features_disable(mod, "*");
@@ -566,7 +588,6 @@
 nc_ctx_fill_yl(struct nc_session *session, ly_module_imp_clb user_clb, void *user_data)
 {
     int ret = 1;
-    LY_LOG_LEVEL verb;
     struct nc_rpc *rpc = NULL;
     struct nc_reply *reply = NULL;
     struct nc_reply_error *error_rpl;
@@ -665,43 +686,13 @@
             }
         }
 
-        mod = ly_ctx_get_module(session->ctx, name, revision, 0);
-        if (mod) {
-            if (implemented && !mod->implemented) {
-                /* make the present module implemented */
-                if (lys_set_implemented(mod)) {
-                    ERR("Failed to implement model \"%s\".", mod->name);
-                    ret = -1; /* fatal error, not caused just by missing schema but by something in the context */
-                    goto cleanup;
-                }
-            }
-        } else if (!mod && implemented) {
-            /* missing implemented module, load it ... */
+        if (nc_ctx_load_module(session, name, revision, implemented, user_clb, user_data, &mod)) {
+            ret = -1;
+            goto cleanup;
+        }
 
-            /* expecting errors here */
-            verb = ly_verb(LY_LLSILENT);
-
-            /* 1) using only searchpaths */
-            mod = ly_ctx_load_module(session->ctx, name, revision);
-
-            /* 2) using user callback */
-            if (!mod && user_clb) {
-                ly_ctx_set_module_imp_clb(session->ctx, user_clb, user_data);
-                mod = ly_ctx_load_module(session->ctx, name, revision);
-            }
-
-            /* 3) using get-schema callback */
-            if (!mod) {
-                ly_ctx_set_module_imp_clb(session->ctx, &getschema_module_clb, session);
-                mod = ly_ctx_load_module(session->ctx, name, revision);
-            }
-
-            /* revert the changed verbosity level */
-            ly_verb(verb);
-
-            /* unset callback back to use searchpath */
-            ly_ctx_set_module_imp_clb(session->ctx, NULL, NULL);
-        } else { /* !mod && !implemented - will be loaded automatically, but remember to set features in the end */
+        if (!mod) { /* !mod && !implemented - will be loaded automatically, but remember to set features in the end */
+            assert(!implemented);
             if (imports_flag) {
                 ERR("Module \"%s@%s\" is supposed to be imported, but no other module imports it.",
                     name, revision ? revision : "<latest>");
@@ -716,8 +707,6 @@
             /* all loading ways failed, the schema will be ignored in the received data */
             WRN("Failed to load schema \"%s@%s\".", name, revision ? revision : "<latest>");
             session->flags |= NC_SESSION_CLIENT_NOT_STRICT;
-
-            /* TODO: maybe re-print hidden error messages */
         } else {
             /* set features - first disable all to enable specified then */
             lys_features_disable(mod, "*");
diff --git a/src/session_server.c b/src/session_server.c
index 1515fe5..73126f3 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -1031,7 +1031,7 @@
                                      LYD_OPT_RPC | LYD_OPT_DESTRUCT | LYD_OPT_NOEXTDEPS | LYD_OPT_STRICT, NULL);
         if (!(*rpc)->tree) {
             /* parsing RPC failed */
-            reply = nc_server_reply_err(nc_err_libyang());
+            reply = nc_server_reply_err(nc_err_libyang(server_opts.ctx));
             ret = nc_write_msg(session, NC_MSG_REPLY, xml, reply);
             nc_server_reply_free(reply);
             if (ret == -1) {