BUGFIX err_reply object should not be shared
moved into thread specific
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index 5093f67..1cc502b 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -116,6 +116,30 @@
static pthread_key_t notif_history_key;
+static pthread_key_t err_reply_key;
+
+#define GETSPEC_ERR_REPLY json_object *err_reply = *((json_object **) pthread_getspecific(err_reply_key));
+
+#define CHECK_ERR_SET_REPLY \
+if (reply == NULL) { \
+ GETSPEC_ERR_REPLY \
+ if (err_reply != NULL) { \
+ /* use filled err_reply from libnetconf's callback */ \
+ reply = err_reply; \
+ } \
+}
+
+#define CHECK_ERR_SET_REPLY_ERR(errmsg) \
+if (reply == NULL) { \
+ GETSPEC_ERR_REPLY \
+ if (err_reply == NULL) { \
+ reply = create_error(errmsg); \
+ } else { \
+ /* use filled err_reply from libnetconf's callback */ \
+ reply = err_reply; \
+ } \
+}
+
volatile int isterminated = 0;
static char* password;
@@ -189,7 +213,6 @@
return;
}
-static json_object *err_reply = NULL;
void netconf_callback_error_process(const char* tag,
const char* type,
const char* severity,
@@ -201,8 +224,12 @@
const char* ns,
const char* sid)
{
+ json_object **err_reply_p = (json_object **) pthread_getspecific(err_reply_key);
+ json_object *err_reply = *err_reply_p;
+
json_object *array = NULL;
if (err_reply == NULL) {
+ DEBUG("error calback: empty error list");
pthread_mutex_lock(&json_lock);
err_reply = json_object_new_object();
array = json_object_new_array();
@@ -212,8 +239,9 @@
json_object_array_add(array, json_object_new_string(message));
}
pthread_mutex_unlock(&json_lock);
- return;
+ (*err_reply_p) = err_reply;
} else {
+ DEBUG("error calback: nonempty error list");
pthread_mutex_lock(&json_lock);
array = json_object_object_get(err_reply, "errors");
if (array != NULL) {
@@ -223,6 +251,7 @@
}
pthread_mutex_unlock(&json_lock);
}
+ pthread_setspecific(err_reply_key, err_reply_p);
return;
}
@@ -1093,6 +1122,8 @@
nc_cpblts_free(cpblts);
}
+ GETSPEC_ERR_REPLY
+
pthread_mutex_lock(&json_lock);
if (session_key_hash == NULL) {
/* negative reply */
@@ -1131,14 +1162,7 @@
pthread_mutex_unlock(&json_lock);
if ((data = netconf_get(session_key, filter, &reply)) == NULL) {
- if (reply == NULL) {
- if (err_reply == NULL) {
- reply = create_error("Get information failed.");
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+ CHECK_ERR_SET_REPLY_ERR("Get information failed.")
} else {
reply = create_data(data);
free(data);
@@ -1168,14 +1192,7 @@
}
if ((data = netconf_getconfig(session_key, ds_type_s, filter, &reply)) == NULL) {
- if (reply == NULL) {
- if (err_reply == NULL) {
- reply = create_error("Get configuration operation failed.");
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+ CHECK_ERR_SET_REPLY_ERR("Get configuration operation failed.")
} else {
reply = create_data(data);
free(data);
@@ -1204,14 +1221,7 @@
DEBUG("get-schema(version: %s, format: %s)", version, format);
if ((data = netconf_getschema(session_key, identifier, version, format, &reply)) == NULL) {
- if (reply == NULL) {
- if (err_reply == NULL) {
- reply = create_error("Get models operation failed.");
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+ CHECK_ERR_SET_REPLY_ERR("Get models operation failed.")
} else {
reply = create_data(data);
free(data);
@@ -1301,12 +1311,9 @@
}
reply = netconf_editconfig(session_key, ds_type_s, ds_type_t, defop_type, erropt_type, testopt_type, config);
- if (reply == NULL) {
- if (err_reply != NULL) {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+
+ CHECK_ERR_SET_REPLY
+
return reply;
}
@@ -1367,12 +1374,9 @@
}
}
reply = netconf_copyconfig(session_key, ds_type_s, ds_type_t, config, uri_src, uri_trg);
- if (reply == NULL) {
- if (err_reply != NULL) {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+
+ CHECK_ERR_SET_REPLY
+
return reply;
}
@@ -1395,6 +1399,7 @@
/* TODO */
reply = netconf_generic(session_key, config, &data);
if (reply == NULL) {
+ GETSPEC_ERR_REPLY
if (err_reply != NULL) {
/* use filled err_reply from libnetconf's callback */
reply = err_reply;
@@ -1419,17 +1424,9 @@
DEBUG("Request: Disconnect session %s", session_key);
if (netconf_close(session_key, &reply) != EXIT_SUCCESS) {
- if (reply == NULL) {
- if (err_reply == NULL) {
- reply = create_error("Get configuration information from device failed.");
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+ CHECK_ERR_SET_REPLY_ERR("Get configuration information from device failed.")
} else {
- reply = json_object_new_object();
- json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+ reply = create_ok();
}
return reply;
}
@@ -1450,12 +1447,9 @@
}
reply = netconf_killsession(session_key, sid);
- if (reply == NULL) {
- if (err_reply != NULL) {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
- }
- }
+
+ CHECK_ERR_SET_REPLY
+
return reply;
}
@@ -1714,12 +1708,12 @@
DEBUG("Request: validate datastore");
if ((reply = netconf_op(session_key, rpc, NULL)) == NULL) {
- if (err_reply == NULL) {
+
+ CHECK_ERR_SET_REPLY
+
+ if (reply == NULL) {
DEBUG("Request: validation ok.");
reply = create_ok();
- } else {
- /* use filled err_reply from libnetconf's callback */
- reply = err_reply;
}
}
nc_rpc_free (rpc);
@@ -1747,6 +1741,15 @@
char *buffer = NULL;
+ /* init thread specific err_reply memory */
+ json_object **err_reply = calloc(1, sizeof(json_object **));
+ if (err_reply == NULL) {
+ DEBUG("Allocation of err_reply storage failed!");
+ isterminated = 1;
+ }
+ if (pthread_setspecific(err_reply_key, err_reply) != 0) {
+ DEBUG("notif_history: cannot set thread-specific hash value.");
+ }
while (!isterminated) {
fds.fd = client;
fds.events = POLLIN;
@@ -1817,7 +1820,7 @@
}
/* null global JSON error-reply */
- err_reply = NULL;
+ (*err_reply) = NULL;
/* prepare reply envelope */
if (reply != NULL) {
@@ -1884,7 +1887,7 @@
}
if (reply == NULL) {
- if (err_reply == NULL) {
+ if (*err_reply == NULL) {
/** \todo more clever error message wanted */
pthread_mutex_lock(&json_lock);
reply = json_object_new_object();
@@ -1892,7 +1895,7 @@
pthread_mutex_unlock(&json_lock);
} else {
/* use filled err_reply from libnetconf's callback */
- reply = err_reply;
+ reply = *err_reply;
}
}
break;
@@ -1951,20 +1954,36 @@
free(buffer);
buffer = NULL;
}
- if (err_reply != NULL) {
- json_object_put(err_reply);
- err_reply = NULL;
+ if ((err_reply != NULL) && (*err_reply != NULL)) {
+ json_object_put(*err_reply);
+ *err_reply = NULL;
}
pthread_mutex_unlock(&json_lock);
} else {
pthread_mutex_unlock(&json_lock);
DEBUG("Reply is NULL, shouldn't be...");
+ if (*err_reply == NULL) {
+ DEBUG("No error was set - really strange situation");
+ } else {
+ DEBUG("Error was set but it was not sent.");
+ }
continue;
}
}
}
free (arg);
+ err_reply = (json_object **) pthread_getspecific(err_reply_key);
+ if (err_reply != NULL) {
+ if (*err_reply != NULL) {
+ pthread_mutex_lock(&json_lock);
+ json_object_put(*err_reply);
+ pthread_mutex_unlock(&json_lock);
+ }
+ free(err_reply);
+ err_reply = NULL;
+ }
+
return retval;
}
@@ -2177,6 +2196,10 @@
if (pthread_key_create(¬if_history_key, NULL) != 0) {
DEBUG("init of notif_history_key failed");
}
+ DEBUG("init of err_reply_key.");
+ if (pthread_key_create(&err_reply_key, NULL) != 0) {
+ DEBUG("init of err_reply_key failed");
+ }
fcntl(lsock, F_SETFL, fcntl(lsock, F_GETFL, 0) | O_NONBLOCK);
while (isterminated == 0) {