CHANGE remove httpd and apache dependencies
diff --git a/src/Makefile.am b/src/Makefile.am
index c8f6534..7867d7a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,18 +16,10 @@
all: mod_netconf.so webgui-backend
mod_netconf.so: mod_netconf.c notification-server.c
- $(APXS) $(LIBS) $(CFLAGS) -c -o $@ $(srcdir)/mod_netconf.c $(srcdir)/notification-server.c
-
-install-exec-local: mod_netconf.so
- if [ "x${httpdmoduledir}" == x ]; then \
- $(APXS) -i -a mod_netconf.la; else \
- { \
- mkdir -p "${httpdmoduledir}"; \
- $(APXS) -i -S LIBEXECDIR="${httpdmoduledir}" -a mod_netconf.la; } \
- fi
+ $(CC) $(CFLAGS) -o $@ $(srcdir)/mod_netconf.c $(srcdir)/notification-server.c $(LIBS)
webgui-backend$(EXEEXT): mod_netconf.c notification-server.c mod_netconf.h
- $(CC) $(LIBS) $(CFLAGS) -DHTTPD_INDEPENDENT `apr-1-config --cflags --cppflags --includes --link-ld` -I/usr/include/httpd -laprutil-1 -o $@ $(srcdir)/mod_netconf.c $(srcdir)/notification-server.c
+ $(CC) $(CFLAGS) -laprutil-1 -o $@ $(srcdir)/mod_netconf.c $(srcdir)/notification-server.c $(LIBS)
clean-local:
rm -rf .libs *.la *.lo *.slo test-client webgui-backend
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index 7c639c2..523dd85 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -43,29 +43,23 @@
* if advised of the possibility of such damage.
*
*/
+#define _GNU_SOURCE
#include <unistd.h>
#include <poll.h>
+#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/fcntl.h>
#include <pwd.h>
+#include <errno.h>
#include <grp.h>
+#include <signal.h>
#include <pthread.h>
#include <ctype.h>
-#include <unixd.h>
-#include <httpd.h>
-#include <http_log.h>
-#include <http_config.h>
-
-#include <apr_sha1.h>
-#include <apr_hash.h>
-#include <apr_signal.h>
-#include <apr_strings.h>
-
-#include <json/json.h>
+#include <libyang/libyang.h>
#include <libnetconf.h>
#include <libnetconf_ssh.h>
@@ -83,7 +77,6 @@
#define SOCKET_FILENAME "/var/run/mod_netconf.sock"
#define MAX_SOCKET_CL 10
#define BUFFER_SIZE 4096
-#define NOTIFICATION_QUEUE_SIZE 10
#define ACTIVITY_CHECK_INTERVAL 10 /**< timeout in seconds, how often activity is checked */
#define ACTIVITY_TIMEOUT (60*60) /**< timeout in seconds, after this time, session is automaticaly closed. */
@@ -94,8 +87,6 @@
#define offsetof(type, member) ((size_t) ((type *) 0)->member)
#endif
-server_rec *http_server = NULL;
-
/* timeout in msec */
struct timeval timeout = { 1, 0 };
@@ -109,14 +100,14 @@
#define MSG_ERROR 4
#define MSG_UNKNOWN 5
-module AP_MODULE_DECLARE_DATA netconf_module;
-
pthread_rwlock_t session_lock; /**< mutex protecting netconf_sessions_list from multiple access errors */
pthread_mutex_t ntf_history_lock; /**< mutex protecting notification history list */
pthread_mutex_t ntf_hist_clbc_mutex; /**< mutex protecting notification history list */
pthread_mutex_t json_lock; /**< mutex for protecting json-c calls */
-apr_hash_t *netconf_sessions_list = NULL;
+struct session_with_mutex *netconf_sessions_list = NULL;
+
+static const char *sockname;
static pthread_key_t notif_history_key;
@@ -136,67 +127,44 @@
}
}
-static char* gen_ncsession_hash( const char* hostname, const char* port, const char* sid)
-{
- unsigned char hash_raw[APR_SHA1_DIGESTSIZE];
- int i;
- char* hash;
-
- apr_sha1_ctx_t sha1_ctx;
- apr_sha1_init(&sha1_ctx);
- apr_sha1_update(&sha1_ctx, hostname, strlen(hostname));
- apr_sha1_update(&sha1_ctx, port, strlen(port));
- apr_sha1_update(&sha1_ctx, sid, strlen(sid));
- apr_sha1_final(hash_raw, &sha1_ctx);
-
- /* convert binary hash into hex string, which is printable */
- hash = malloc(sizeof(char) * ((2*APR_SHA1_DIGESTSIZE)+1));
- for (i = 0; i < APR_SHA1_DIGESTSIZE; i++) {
- snprintf(hash + (2*i), 3, "%02x", hash_raw[i]);
- }
- //hash[2*APR_SHA1_DIGESTSIZE] = 0;
-
- return (hash);
-}
-
-int netconf_callback_ssh_hostkey_check(const char* hostname, ssh_session session)
+int netconf_callback_ssh_hostkey_check(const char* UNUSED(hostname), ssh_session UNUSED(session))
{
/* always approve */
return (EXIT_SUCCESS);
}
-char *netconf_callback_sshauth_passphrase(const char *username, const char *hostname, const char *priv_key_file)
+char *netconf_callback_sshauth_passphrase(const char *UNUSED(username), const char *UNUSED(hostname), const char *UNUSED(priv_key_file))
{
char *buf;
buf = strdup(password);
return (buf);
}
-char *netconf_callback_sshauth_password(const char* username, const char* hostname)
+char *netconf_callback_sshauth_password(const char* UNUSED(username), const char* UNUSED(hostname))
{
char *buf;
buf = strdup(password);
return (buf);
}
-char *netconf_callback_sshauth_interactive(const char *name, const char *instruction,
- const char *prompt, int echo)
+char *netconf_callback_sshauth_interactive(const char *UNUSED(name), const char *UNUSED(instruction),
+ const char *UNUSED(prompt), int UNUSED(echo))
{
char *buf;
buf = strdup(password);
return (buf);
}
-void netconf_callback_error_process(const char *tag,
- const char *type,
- const char *severity,
- const char *apptag,
- const char *path,
+void netconf_callback_error_process(const char *UNUSED(tag),
+ const char *UNUSED(type),
+ const char *UNUSED(severity),
+ const char *UNUSED(apptag),
+ const char *UNUSED(path),
const char *message,
- const char *attribute,
- const char *element,
- const char *ns,
- const char *sid)
+ const char *UNUSED(attribute),
+ const char *UNUSED(element),
+ const char *UNUSED(ns),
+ const char *UNUSED(sid))
{
json_object **err_reply_p = (json_object **) pthread_getspecific(err_reply_key);
if (err_reply_p == NULL) {
@@ -386,11 +354,10 @@
*
* \warning Session_key hash is not bound with caller identification. This could be potential security risk.
*/
-static char* netconf_connect(apr_pool_t* pool, const char* host, const char* port, const char* user, const char* pass, struct nc_cpblts * cpblts)
+static const char *netconf_connect(const char* host, const char* port, const char* user, const char* pass, struct nc_cpblts * cpblts)
{
struct nc_session* session = NULL;
- struct session_with_mutex * locked_session;
- char *session_key;
+ struct session_with_mutex * locked_session, *last_session;
/* connect to the requested NETCONF server */
password = (char*)pass;
@@ -400,23 +367,16 @@
/* if connected successful, add session to the list */
if (session != NULL) {
- /* generate hash for the session */
- session_key = gen_ncsession_hash(
- (host==NULL) ? "localhost" : host,
- (port==NULL) ? "830" : port,
- nc_session_get_id(session));
-
- /** \todo allocate from apr_pool */
if ((locked_session = calloc(1, sizeof(struct session_with_mutex))) == NULL || pthread_mutex_init (&locked_session->lock, NULL) != 0) {
nc_session_free(session);
session = NULL;
free(locked_session);
locked_session = NULL;
ERROR("Creating structure session_with_mutex failed %d (%s)", errno, strerror(errno));
- return NULL;
+ return 0;
}
locked_session->session = session;
- locked_session->last_activity = apr_time_now();
+ locked_session->last_activity = time(NULL);
locked_session->hello_message = NULL;
locked_session->closed = 0;
pthread_mutex_init (&locked_session->lock, NULL);
@@ -427,12 +387,17 @@
nc_session_free(session);
free (locked_session);
ERROR("Error while locking rwlock: %d (%s)", errno, strerror(errno));
- return NULL;
+ return 0;
}
- locked_session->notifications = apr_array_make(pool, NOTIFICATION_QUEUE_SIZE, sizeof(notification_t));
locked_session->ntfc_subscribed = 0;
DEBUG("Add connection to the list");
- apr_hash_set(netconf_sessions_list, apr_pstrdup(pool, session_key), APR_HASH_KEY_STRING, (void *) locked_session);
+ if (!netconf_sessions_list) {
+ netconf_sessions_list = locked_session;
+ } else {
+ for (last_session = netconf_sessions_list; last_session->next; last_session = last_session->next);
+ last_session->next = locked_session;
+ locked_session->prev = last_session;
+ }
DEBUG("Before session_unlock");
/* lock session */
@@ -452,10 +417,10 @@
pthread_mutex_unlock(&locked_session->lock);
DEBUG("NETCONF session established");
- return (session_key);
+ return nc_session_get_id(session);
} else {
ERROR("Connection could not be established");
- return (NULL);
+ return 0;
}
}
@@ -486,7 +451,7 @@
/* session shouldn't be used by now */
/** \todo free all notifications from queue */
- apr_array_clear(locked_session->notifications);
+ free(locked_session->notifications);
pthread_mutex_destroy(&locked_session->lock);
if (locked_session->hello_message != NULL) {
/** \todo free hello_message */
@@ -500,11 +465,11 @@
return (EXIT_SUCCESS);
}
-static int netconf_close(const char* session_key, json_object **reply)
+static int netconf_close(const char *session_id, json_object **reply)
{
- struct session_with_mutex * locked_session;
+ struct session_with_mutex *locked_session;
- DEBUG("Key in hash to close: %s", session_key);
+ DEBUG("Session to close: %s", session_id);
/* get exclusive (write) access to sessions_list (conns) */
DEBUG("lock session lock.");
@@ -514,10 +479,26 @@
(*reply) = create_error("Internal: Error while locking.");
return EXIT_FAILURE;
}
- /* get session to close */
- locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
/* remove session from the active sessions list -> nobody new can now work with session */
- apr_hash_set(netconf_sessions_list, session_key, APR_HASH_KEY_STRING, NULL);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
+
+ if (!locked_session) {
+ ERROR("Could not find the session \"%s\" to close.", session_id);
+ (*reply) = create_error("Internal: Error while finding a session.");
+ return EXIT_FAILURE;
+ }
+
+ if (!locked_session->prev) {
+ netconf_sessions_list = netconf_sessions_list->next;
+ netconf_sessions_list->prev = NULL;
+ } else {
+ locked_session->prev->next = locked_session->next;
+ if (locked_session->next) {
+ locked_session->next->prev = locked_session->prev;
+ }
+ }
DEBUG("UNLOCK wrlock %s", __func__);
if (pthread_rwlock_unlock (&session_lock) != 0) {
@@ -539,12 +520,12 @@
* Test reply message type and return error message.
*
* \param[in] session nc_session internal struct
- * \param[in] session_key session key, NULL to disable disconnect on error
+ * \param[in] session_key session ID, 0 to disable disconnect on error
* \param[in] msgt RPC-REPLY message type
* \param[out] data
* \return NULL on success
*/
-json_object *netconf_test_reply(struct nc_session *session, const char *session_key, NC_MSG_TYPE msgt, nc_reply *reply, char **data)
+json_object *netconf_test_reply(struct nc_session *session, const char *session_id, NC_MSG_TYPE msgt, nc_reply *reply, char **data)
{
NC_REPLY_TYPE replyt;
json_object *err = NULL;
@@ -554,8 +535,8 @@
case NC_MSG_UNKNOWN:
if (nc_session_get_status(session) != NC_SESSION_STATUS_WORKING) {
ERROR("mod_netconf: receiving rpc-reply failed");
- if (session_key != NULL) {
- netconf_close(session_key, &err);
+ if (session_id) {
+ netconf_close(session_id, &err);
}
if (err != NULL) {
return err;
@@ -626,7 +607,7 @@
/* send the request and get the reply */
msgt = netconf_send_recv_timed(session, rpc, 5000, &reply);
/* process the result of the operation */
- return netconf_test_reply(session, NULL, msgt, reply, NULL);
+ return netconf_test_reply(session, 0, msgt, reply, NULL);
} else {
ERROR("Unknown session to process.");
return create_error("Internal error: Unknown session to process.");
@@ -636,12 +617,12 @@
/**
* Perform RPC method that returns data.
*
- * \param[in] session_key session identifier
+ * \param[in] session_id session identifier
* \param[in] rpc RPC message to perform
* \param[out] received_data received data string, can be NULL when no data expected, value can be set to NULL if no data received
* \return NULL on success, json object with error otherwise
*/
-static json_object *netconf_op(const char* session_key, nc_rpc* rpc, char **received_data)
+static json_object *netconf_op(const char *session_id, nc_rpc* rpc, char **received_data)
{
struct nc_session *session = NULL;
struct session_with_mutex * locked_session;
@@ -667,7 +648,9 @@
goto finished;
}
/* get session where send the RPC */
- locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
if (locked_session != NULL) {
session = locked_session->session;
}
@@ -692,7 +675,7 @@
res = create_error("Internal: Could not unlock.");
}
- locked_session->last_activity = apr_time_now();
+ locked_session->last_activity = time(NULL);
/* send the request and get the reply */
msgt = netconf_send_recv_timed(session, rpc, 5000, &reply);
@@ -702,7 +685,7 @@
pthread_mutex_unlock(&locked_session->lock);
/* end of critical section */
- res = netconf_test_reply(session, session_key, msgt, reply, &data);
+ res = netconf_test_reply(session, session_id, msgt, reply, &data);
} else {
/* release lock on failure */
DEBUG("UNLOCK wrlock %s", __func__);
@@ -748,11 +731,12 @@
/* tell server to show all elements even if they have default values */
#ifdef HAVE_WITHDEFAULTS_TAGGED
- if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED)) {
+ if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL_TAGGED))
#else
- if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET)) {
- //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL)) {
+ if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_NOTSET))
+ //if (nc_rpc_capability_attr(rpc, NC_CAP_ATTR_WITHDEFAULTS_MODE, NCWD_MODE_ALL))
#endif
+ {
ERROR("mod_netconf: setting withdefaults failed");
}
@@ -1161,7 +1145,7 @@
return res;
}
-json_object *handle_op_connect(apr_pool_t *pool, json_object *request)
+json_object *handle_op_connect(json_object *request)
{
char *host = NULL;
char *port = NULL;
@@ -1169,7 +1153,7 @@
char *pass = NULL;
json_object *capabilities = NULL;
json_object *reply = NULL;
- char *session_key_hash = NULL;
+ const char *session_id = NULL;
struct nc_cpblts* cpblts = NULL;
unsigned int len, i;
@@ -1198,10 +1182,10 @@
DEBUG("host: %s, port: %s, user: %s", host, port, user);
if ((host == NULL) || (user == NULL)) {
ERROR("Cannot connect - insufficient input.");
- session_key_hash = NULL;
+ session_id = NULL;
} else {
- session_key_hash = netconf_connect(pool, host, port, user, pass, cpblts);
- DEBUG("hash: %s", session_key_hash);
+ session_id = netconf_connect(host, port, user, pass, cpblts);
+ DEBUG("SID: %s", session_id);
}
if (cpblts != NULL) {
nc_cpblts_free(cpblts);
@@ -1210,7 +1194,7 @@
GETSPEC_ERR_REPLY
pthread_mutex_lock(&json_lock);
- if (session_key_hash == NULL) {
+ if (session_id == NULL) {
/* negative reply */
if (err_reply == NULL) {
reply = json_object_new_object();
@@ -1226,9 +1210,7 @@
/* positive reply */
reply = json_object_new_object();
json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
- json_object_object_add(reply, "session", json_object_new_string(session_key_hash));
-
- free(session_key_hash);
+ json_object_object_add(reply, "session", json_object_new_string(session_id));
}
memset(pass, 0, strlen(pass));
pthread_mutex_unlock(&json_lock);
@@ -1239,19 +1221,19 @@
return reply;
}
-json_object *handle_op_get(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_get(json_object *request, const char *session_id)
{
char *filter = NULL;
char *data = NULL;
json_object *reply = NULL;
- DEBUG("Request: get (session %s)", session_key);
+ DEBUG("Request: get (session %s)", session_id);
pthread_mutex_lock(&json_lock);
filter = get_param_string(request, "filter");
pthread_mutex_unlock(&json_lock);
- if ((data = netconf_get(session_key, filter, &reply)) == NULL) {
+ if ((data = netconf_get(session_id, filter, &reply)) == NULL) {
CHECK_ERR_SET_REPLY_ERR("Get information failed.")
} else {
reply = create_data(data);
@@ -1260,7 +1242,7 @@
return reply;
}
-json_object *handle_op_getconfig(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_getconfig(json_object *request, const char *session_id)
{
NC_DATASTORE ds_type_s = -1;
char *filter = NULL;
@@ -1268,7 +1250,7 @@
char *source = NULL;
json_object *reply = NULL;
- DEBUG("Request: get-config (session %s)", session_key);
+ DEBUG("Request: get-config (session %s)", session_id);
pthread_mutex_lock(&json_lock);
filter = get_param_string(request, "filter");
@@ -1279,12 +1261,12 @@
}
pthread_mutex_unlock(&json_lock);
- if (ds_type_s == -1) {
+ if ((int)ds_type_s == -1) {
reply = create_error("Invalid source repository type requested.");
goto finalize;
}
- if ((data = netconf_getconfig(session_key, ds_type_s, filter, &reply)) == NULL) {
+ if ((data = netconf_getconfig(session_id, ds_type_s, filter, &reply)) == NULL) {
CHECK_ERR_SET_REPLY_ERR("Get configuration operation failed.")
} else {
reply = create_data(data);
@@ -1296,7 +1278,7 @@
return reply;
}
-json_object *handle_op_getschema(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_getschema(json_object *request, const char *session_id)
{
char *data = NULL;
char *identifier = NULL;
@@ -1304,7 +1286,7 @@
char *format = NULL;
json_object *reply = NULL;
- DEBUG("Request: get-schema (session %s)", session_key);
+ DEBUG("Request: get-schema (session %s)", session_id);
pthread_mutex_lock(&json_lock);
identifier = get_param_string(request, "identifier");
version = get_param_string(request, "version");
@@ -1317,7 +1299,7 @@
}
DEBUG("get-schema(version: %s, format: %s)", version, format);
- if ((data = netconf_getschema(session_key, identifier, version, format, &reply)) == NULL) {
+ if ((data = netconf_getschema(session_id, identifier, version, format, &reply)) == NULL) {
CHECK_ERR_SET_REPLY_ERR("Get models operation failed.")
} else {
reply = create_data(data);
@@ -1330,7 +1312,7 @@
return reply;
}
-json_object *handle_op_editconfig(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_editconfig(json_object *request, const char *session_id)
{
NC_DATASTORE ds_type_s = -1;
NC_DATASTORE ds_type_t = -1;
@@ -1345,7 +1327,7 @@
char *testopt = NULL;
json_object *reply = NULL;
- DEBUG("Request: edit-config (session %s)", session_key);
+ DEBUG("Request: edit-config (session %s)", session_id);
pthread_mutex_lock(&json_lock);
/* get parameters */
@@ -1397,7 +1379,7 @@
erropt_type = 0;
}
- if (ds_type_t == -1) {
+ if ((int)ds_type_t == -1) {
reply = create_error("Invalid target repository type requested.");
goto finalize;
}
@@ -1418,7 +1400,7 @@
testopt_type = NC_EDIT_TESTOPT_TESTSET;
}
- reply = netconf_editconfig(session_key, ds_type_s, ds_type_t, defop_type, erropt_type, testopt_type, config);
+ reply = netconf_editconfig(session_id, ds_type_s, ds_type_t, defop_type, erropt_type, testopt_type, config);
CHECK_ERR_SET_REPLY
finalize:
@@ -1431,7 +1413,7 @@
return reply;
}
-json_object *handle_op_copyconfig(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_copyconfig(json_object *request, const char *session_id)
{
NC_DATASTORE ds_type_s = -1;
NC_DATASTORE ds_type_t = -1;
@@ -1443,7 +1425,7 @@
json_object *reply = NULL;
- DEBUG("Request: copy-config (session %s)", session_key);
+ DEBUG("Request: copy-config (session %s)", session_id);
/* get parameters */
pthread_mutex_lock(&json_lock);
@@ -1463,13 +1445,13 @@
/* source == NULL *//* no explicit source specified -> use config data */
ds_type_s = NC_DATASTORE_CONFIG;
}
- if (ds_type_s == -1) {
+ if ((int)ds_type_s == -1) {
/* source datastore specified, but it is invalid */
reply = create_error("Invalid source repository type requested.");
goto finalize;
}
- if (ds_type_t == -1) {
+ if ((int)ds_type_t == -1) {
/* invalid target datastore specified */
reply = create_error("Invalid target repository type requested.");
goto finalize;
@@ -1491,7 +1473,7 @@
uri_trg = "";
}
}
- reply = netconf_copyconfig(session_key, ds_type_s, ds_type_t, config, uri_src, uri_trg);
+ reply = netconf_copyconfig(session_id, ds_type_s, ds_type_t, config, uri_src, uri_trg);
CHECK_ERR_SET_REPLY
@@ -1505,19 +1487,19 @@
return reply;
}
-json_object *handle_op_generic(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_generic(json_object *request, const char *session_id)
{
json_object *reply = NULL;
char *config = NULL;
char *data = NULL;
- DEBUG("Request: generic request for session %s", session_key);
+ DEBUG("Request: generic request for session %s", session_id);
pthread_mutex_lock(&json_lock);
config = get_param_string(request, "content");
pthread_mutex_unlock(&json_lock);
- reply = netconf_generic(session_key, config, &data);
+ reply = netconf_generic(session_id, config, &data);
if (reply == NULL) {
GETSPEC_ERR_REPLY
if (err_reply != NULL) {
@@ -1539,12 +1521,12 @@
return reply;
}
-json_object *handle_op_disconnect(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_disconnect(json_object *UNUSED(request), const char *session_id)
{
json_object *reply = NULL;
- DEBUG("Request: Disconnect session %s", session_key);
+ DEBUG("Request: Disconnect session %s", session_id);
- if (netconf_close(session_key, &reply) != EXIT_SUCCESS) {
+ if (netconf_close(session_id, &reply) != EXIT_SUCCESS) {
CHECK_ERR_SET_REPLY_ERR("Get configuration information from device failed.")
} else {
reply = create_ok();
@@ -1552,12 +1534,12 @@
return reply;
}
-json_object *handle_op_kill(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_kill(json_object *request, const char *session_id)
{
json_object *reply = NULL;
char *sid = NULL;
- DEBUG("Request: kill-session, session %s", session_key);
+ DEBUG("Request: kill-session, session %s", session_id);
pthread_mutex_lock(&json_lock);
sid = get_param_string(request, "session-id");
@@ -1568,7 +1550,7 @@
goto finalize;
}
- reply = netconf_killsession(session_key, sid);
+ reply = netconf_killsession(session_id, sid);
CHECK_ERR_SET_REPLY
@@ -1577,12 +1559,12 @@
return reply;
}
-json_object *handle_op_reloadhello(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_reloadhello(json_object *UNUSED(request), const char *session_id)
{
struct nc_session *temp_session = NULL;
struct session_with_mutex * locked_session = NULL;
json_object *reply = NULL;
- DEBUG("Request: get info about session %s", session_key);
+ DEBUG("Request: get info about session %s", session_id);
DEBUG("LOCK wrlock %s", __func__);
if (pthread_rwlock_wrlock(&session_lock) != 0) {
@@ -1590,7 +1572,9 @@
return NULL;
}
- locked_session = (struct session_with_mutex *) apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
if ((locked_session != NULL) && (locked_session->hello_message != NULL)) {
DEBUG("LOCK mutex %s", __func__);
pthread_mutex_lock(&locked_session->lock);
@@ -1625,18 +1609,20 @@
return reply;
}
-json_object *handle_op_info(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_info(json_object *UNUSED(request), const char *session_id)
{
json_object *reply = NULL;
struct session_with_mutex * locked_session = NULL;
- DEBUG("Request: get info about session %s", session_key);
+ DEBUG("Request: get info about session %s", session_id);
DEBUG("LOCK wrlock %s", __func__);
if (pthread_rwlock_rdlock(&session_lock) != 0) {
ERROR("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
}
- locked_session = (struct session_with_mutex *) apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
if (locked_session != NULL) {
DEBUG("LOCK mutex %s", __func__);
pthread_mutex_lock(&locked_session->lock);
@@ -1684,7 +1670,7 @@
pthread_mutex_unlock(&json_lock);
}
-json_object *handle_op_ntfgethistory(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_ntfgethistory(json_object *request, const char *session_id)
{
json_object *reply = NULL;
json_object *js_tmp = NULL;
@@ -1696,7 +1682,7 @@
time_t stop = 0;
int64_t from = 0, to = 0;
- DEBUG("Request: get notification history, session %s", session_key);
+ DEBUG("Request: get notification history, session %s", session_id);
pthread_mutex_lock(&json_lock);
sid = get_param_string(request, "session");
@@ -1728,7 +1714,9 @@
goto finalize;
}
- locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
if (locked_session != NULL) {
DEBUG("LOCK mutex %s", __func__);
pthread_mutex_lock(&locked_session->lock);
@@ -1803,7 +1791,7 @@
return reply;
}
-json_object *handle_op_validate(apr_pool_t *pool, json_object *request, const char *session_key)
+json_object *handle_op_validate(json_object *request, const char *session_id)
{
json_object *reply = NULL;
char *sid = NULL;
@@ -1812,7 +1800,7 @@
nc_rpc *rpc = NULL;
NC_DATASTORE target_ds;
- DEBUG("Request: validate datastore, session %s", session_key);
+ DEBUG("Request: validate datastore, session %s", session_id);
pthread_mutex_lock(&json_lock);
sid = get_param_string(request, "session");
@@ -1843,7 +1831,7 @@
}
DEBUG("Request: validate datastore");
- if ((reply = netconf_op(session_key, rpc, NULL)) == NULL) {
+ if ((reply = netconf_op(session_id, rpc, NULL)) == NULL) {
CHECK_ERR_SET_REPLY
@@ -1871,11 +1859,10 @@
NC_DATASTORE ds_type_t = -1;
int status = 0;
const char *msgtext;
- char *session_key = NULL;
+ char *session_id = NULL;
char *target = NULL;
char *url = NULL;
char *chunked_out_msg = NULL;
- apr_pool_t * pool = ((struct pass_to_thread*)arg)->pool;
//server_rec * server = ((struct pass_to_thread*)arg)->server;
int client = ((struct pass_to_thread*)arg)->client;
@@ -1928,7 +1915,7 @@
continue;
}
- session_key = get_param_string(request, "session");
+ session_id = get_param_string(request, "session");
if (json_object_object_get_ex(request, "type", &js_tmp) == TRUE) {
operation = json_object_get_int(js_tmp);
json_object_put(js_tmp);
@@ -1940,9 +1927,9 @@
goto send_reply;
}
- DEBUG("operation %d session_key %s.", operation, session_key);
+ DEBUG("operation %d session_id %s.", operation, session_id);
/* DO NOT FREE session_key HERE, IT IS PART OF REQUEST */
- if (operation != MSG_CONNECT && session_key == NULL) {
+ if (operation != MSG_CONNECT && session_id == NULL) {
reply = create_error("Missing session specification.");
pthread_mutex_lock(&json_lock);
msgtext = json_object_to_json_string(reply);
@@ -1972,22 +1959,22 @@
/* process required operation */
switch (operation) {
case MSG_CONNECT:
- reply = handle_op_connect(pool, request);
+ reply = handle_op_connect(request);
break;
case MSG_GET:
- reply = handle_op_get(pool, request, session_key);
+ reply = handle_op_get(request, session_id);
break;
case MSG_GETCONFIG:
- reply = handle_op_getconfig(pool, request, session_key);
+ reply = handle_op_getconfig(request, session_id);
break;
case MSG_GETSCHEMA:
- reply = handle_op_getschema(pool, request, session_key);
+ reply = handle_op_getschema(request, session_id);
break;
case MSG_EDITCONFIG:
- reply = handle_op_editconfig(pool, request, session_key);
+ reply = handle_op_editconfig(request, session_id);
break;
case MSG_COPYCONFIG:
- reply = handle_op_copyconfig(pool, request, session_key);
+ reply = handle_op_copyconfig(request, session_id);
break;
case MSG_DELETECONFIG:
@@ -2001,25 +1988,25 @@
ds_type_t = parse_datastore(target);
}
- if (ds_type_t == -1) {
+ if ((int)ds_type_t == -1) {
reply = create_error("Invalid target repository type requested.");
break;
}
switch(operation) {
case MSG_DELETECONFIG:
- DEBUG("Request: delete-config (session %s)", session_key);
+ DEBUG("Request: delete-config (session %s)", session_id);
pthread_mutex_lock(&json_lock);
url = get_param_string(request, "url");
pthread_mutex_unlock(&json_lock);
- reply = netconf_deleteconfig(session_key, ds_type_t, url);
+ reply = netconf_deleteconfig(session_id, ds_type_t, url);
break;
case MSG_LOCK:
- DEBUG("Request: lock (session %s)", session_key);
- reply = netconf_lock(session_key, ds_type_t);
+ DEBUG("Request: lock (session %s)", session_id);
+ reply = netconf_lock(session_id, ds_type_t);
break;
case MSG_UNLOCK:
- DEBUG("Request: unlock (session %s)", session_key);
- reply = netconf_unlock(session_key, ds_type_t);
+ DEBUG("Request: unlock (session %s)", session_id);
+ reply = netconf_unlock(session_id, ds_type_t);
break;
default:
reply = create_error("Internal: Unknown request type.");
@@ -2032,25 +2019,25 @@
}
break;
case MSG_KILL:
- reply = handle_op_kill(pool, request, session_key);
+ reply = handle_op_kill(request, session_id);
break;
case MSG_DISCONNECT:
- reply = handle_op_disconnect(pool, request, session_key);
+ reply = handle_op_disconnect(request, session_id);
break;
case MSG_RELOADHELLO:
- reply = handle_op_reloadhello(pool, request, session_key);
+ reply = handle_op_reloadhello(request, session_id);
break;
case MSG_INFO:
- reply = handle_op_info(pool, request, session_key);
+ reply = handle_op_info(request, session_id);
break;
case MSG_GENERIC:
- reply = handle_op_generic(pool, request, session_key);
+ reply = handle_op_generic(request, session_id);
break;
case MSG_NTF_GETHISTORY:
- reply = handle_op_ntfgethistory(pool, request, session_key);
+ reply = handle_op_ntfgethistory(request, session_id);
break;
case MSG_VALIDATE:
- reply = handle_op_validate(pool, request, session_key);
+ reply = handle_op_validate(request, session_id);
break;
default:
DEBUG("Unknown mod_netconf operation requested (%d)", operation);
@@ -2058,7 +2045,6 @@
break;
}
/* free parameters */
- CHECK_AND_FREE(session_key);
CHECK_AND_FREE(url);
CHECK_AND_FREE(target);
request = NULL;
@@ -2123,17 +2109,10 @@
* During termination of mod_netconf, it is useful to close all remaining
* sessions. This function iterates over the list of sessions and close them
* all.
- *
- * \param[in] p apr pool needed for hash table iterating
- * \param[in] ht hash table of session_with_mutex structs
*/
-static void close_all_nc_sessions(apr_pool_t *p)
+static void close_all_nc_sessions(void)
{
- apr_hash_index_t *hi;
- void *val = NULL;
struct session_with_mutex *swm = NULL;
- const char *hashed_key = NULL;
- apr_ssize_t hashed_key_length;
int ret;
/* get exclusive access to sessions_list (conns) */
@@ -2142,20 +2121,11 @@
ERROR("Error while locking rwlock: %d (%s)", ret, strerror(ret));
return;
}
- for (hi = apr_hash_first(p, netconf_sessions_list); hi; hi = apr_hash_next(hi)) {
- apr_hash_this(hi, (const void **) &hashed_key, &hashed_key_length, &val);
- DEBUG("Closing NETCONF session (%s).", hashed_key);
- swm = (struct session_with_mutex *) val;
- if (swm != NULL) {
- DEBUG("LOCK mutex %s", __func__);
- pthread_mutex_lock(&swm->lock);
- apr_hash_set(netconf_sessions_list, hashed_key, APR_HASH_KEY_STRING, NULL);
- DEBUG("UNLOCK mutex %s", __func__);
- pthread_mutex_unlock(&swm->lock);
+ for (swm = netconf_sessions_list; swm; swm = swm->next) {
+ DEBUG("Closing NETCONF session (%s).", nc_session_get_id(swm->session));
- /* close_and_free_session handles locking on its own */
- close_and_free_session(swm);
- }
+ /* close_and_free_session handles locking on its own */
+ close_and_free_session(swm);
}
/* get exclusive access to sessions_list (conns) */
DEBUG("UNLOCK wrlock %s", __func__);
@@ -2164,15 +2134,11 @@
}
}
-static void check_timeout_and_close(apr_pool_t *p)
+static void check_timeout_and_close(void)
{
- apr_hash_index_t *hi;
- void *val = NULL;
struct nc_session *ns = NULL;
struct session_with_mutex *swm = NULL;
- const char *hashed_key = NULL;
- apr_ssize_t hashed_key_length;
- apr_time_t current_time = apr_time_now();
+ time_t current_time = time(NULL);
int ret;
/* get exclusive access to sessions_list (conns) */
@@ -2180,22 +2146,14 @@
DEBUG("Error while locking rwlock: %d (%s)", ret, strerror(ret));
return;
}
- for (hi = apr_hash_first(p, netconf_sessions_list); hi; hi = apr_hash_next(hi)) {
- apr_hash_this(hi, (const void **) &hashed_key, &hashed_key_length, &val);
- swm = (struct session_with_mutex *) val;
- if (swm == NULL) {
- continue;
- }
+ for (swm = netconf_sessions_list; swm; swm = swm->next) {
ns = swm->session;
if (ns == NULL) {
continue;
}
pthread_mutex_lock(&swm->lock);
- if ((current_time - swm->last_activity) > apr_time_from_sec(ACTIVITY_TIMEOUT)) {
- DEBUG("Closing NETCONF session (%s).", hashed_key);
- /* remove session from the active sessions list */
- apr_hash_set(netconf_sessions_list, hashed_key, APR_HASH_KEY_STRING, NULL);
- pthread_mutex_unlock(&swm->lock);
+ if ((current_time - swm->last_activity) > ACTIVITY_TIMEOUT) {
+ DEBUG("Closing NETCONF session (%s).", nc_session_get_id(swm->session));
/* close_and_free_session handles locking on its own */
close_and_free_session(swm);
@@ -2214,18 +2172,16 @@
* This is actually implementation of NETCONF client
* - requests are received from UNIX socket in the predefined format
* - results are replied through the same way
- * - the daemon run as a separate process, but it is started and stopped
- * automatically by Apache.
+ * - the daemon run as a separate process
*
*/
-static void forked_proc(apr_pool_t * pool, server_rec * server)
+static void forked_proc(void)
{
struct timeval tv;
struct sockaddr_un local, remote;
int lsock, client, ret, i, pthread_count = 0;
unsigned int olds = 0, timediff = 0;
socklen_t len;
- mod_netconf_cfg *cfg;
struct pass_to_thread * arg;
pthread_t * ptids = calloc(1, sizeof(pthread_t));
struct timespec maxtime;
@@ -2235,8 +2191,6 @@
char use_notifications = 0;
#endif
- http_server = server;
-
/* wait at most 5 seconds for every thread to terminate */
maxtime.tv_sec = 5;
maxtime.tv_nsec = 0;
@@ -2278,17 +2232,6 @@
# endif
#endif
- if (server != NULL) {
- cfg = ap_get_module_config(server->module_config, &netconf_module);
- if (cfg == NULL) {
- ERROR("Getting mod_netconf configuration failed");
- return;
- }
- sockname = cfg->sockname;
- } else {
- sockname = SOCKET_FILENAME;
- }
-
/* try to remove if exists */
unlink(sockname);
@@ -2336,10 +2279,9 @@
}
/* prepare internal lists */
- netconf_sessions_list = apr_hash_make(pool);
#ifdef WITH_NOTIFICATIONS
- if (notification_init(pool, server) == -1) {
+ if (notification_init() == -1) {
ERROR("libwebsockets initialization failed");
use_notifications = 0;
} else {
@@ -2388,14 +2330,14 @@
}
#endif
if (timediff > ACTIVITY_CHECK_INTERVAL) {
- check_timeout_and_close(pool);
+ check_timeout_and_close();
}
/* open incoming connection if any */
len = sizeof(remote);
client = accept(lsock, (struct sockaddr *) &remote, &len);
if (client == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
- apr_sleep(SLEEP_TIME);
+ sleep(SLEEP_TIME);
continue;
} else if (client == -1 && (errno == EINTR)) {
continue;
@@ -2407,10 +2349,8 @@
/* set client's socket as non-blocking */
//fcntl(client, F_SETFL, fcntl(client, F_GETFL, 0) | O_NONBLOCK);
- arg = malloc (sizeof(struct pass_to_thread));
+ arg = malloc(sizeof(struct pass_to_thread));
arg->client = client;
- arg->pool = pool;
- arg->server = server;
arg->netconf_sessions_list = netconf_sessions_list;
/* start new thread. It will serve this particular request and then terminate */
@@ -2448,7 +2388,7 @@
#endif
/* close all NETCONF sessions */
- close_all_nc_sessions(pool);
+ close_all_nc_sessions();
/* destroy rwlock */
pthread_rwlock_destroy(&session_lock);
@@ -2458,7 +2398,7 @@
free(ptids);
close(lsock);
- exit(APR_SUCCESS);
+ exit(0);
return;
error_exit:
close(lsock);
@@ -2466,118 +2406,25 @@
return;
}
-static void *mod_netconf_create_conf(apr_pool_t * pool, server_rec * s)
-{
- mod_netconf_cfg *config = apr_pcalloc(pool, sizeof(mod_netconf_cfg));
- apr_pool_create(&config->pool, pool);
- config->forkproc = NULL;
- config->sockname = SOCKET_FILENAME;
-
- return (void *)config;
-}
-
-#ifndef HTTPD_INDEPENDENT
-static int mod_netconf_master_init(apr_pool_t * pconf, apr_pool_t * ptemp,
- apr_pool_t * plog, server_rec * s)
-{
- mod_netconf_cfg *config;
- apr_status_t res;
-
- /* These two help ensure that we only init once. */
- void *data = NULL;
- const char *userdata_key = "netconf_ipc_init";
-
- /*
- * The following checks if this routine has been called before.
- * This is necessary because the parent process gets initialized
- * a couple of times as the server starts up.
- */
- apr_pool_userdata_get(&data, userdata_key, s->process->pool);
- if (!data) {
- apr_pool_userdata_set((const void *)1, userdata_key, apr_pool_cleanup_null, s->process->pool);
- return (OK);
- }
-
- DEBUG("creating mod_netconf daemon");
- config = ap_get_module_config(s->module_config, &netconf_module);
-
- if (config && config->forkproc == NULL) {
- config->forkproc = apr_pcalloc(config->pool, sizeof(apr_proc_t));
- res = apr_proc_fork(config->forkproc, config->pool);
- switch (res) {
- case APR_INCHILD:
- /* set signal handler */
- apr_signal_init(config->pool);
- apr_signal(SIGTERM, signal_handler);
-
- /* log start of the separated NETCONF communication process */
- DEBUG("mod_netconf daemon started (PID %d)", getpid());
-
- /* start main loop providing NETCONF communication */
- forked_proc(config->pool, s);
-
- /* I never should be here, wtf?!? */
- DEBUG("mod_netconf daemon unexpectedly stopped");
- exit(APR_EGENERAL);
- break;
- case APR_INPARENT:
- /* register child to be killed (SIGTERM) when the module config's pool dies */
- apr_pool_note_subprocess(config->pool, config->forkproc, APR_KILL_AFTER_TIMEOUT);
- break;
- default:
- ERROR("apr_proc_fork() failed");
- break;
- }
- } else {
- ERROR("mod_netconf misses configuration structure");
- }
-
- return OK;
-}
-#endif
-
-/**
- * Register module hooks
- */
-static void mod_netconf_register_hooks(apr_pool_t * p)
-{
-#ifndef HTTPD_INDEPENDENT
- ap_hook_post_config(mod_netconf_master_init, NULL, NULL, APR_HOOK_LAST);
-#endif
-}
-
-static const char* cfg_set_socket_path(cmd_parms* cmd, void* cfg, const char* arg)
-{
- ((mod_netconf_cfg*)cfg)->sockname = apr_pstrdup(cmd->pool, arg);
- return NULL;
-}
-
-static const command_rec netconf_cmds[] = {
- AP_INIT_TAKE1("NetconfSocket", cfg_set_socket_path, NULL, OR_ALL, "UNIX socket path for mod_netconf communication."),
- {NULL}
-};
-
-/* Dispatch list for API hooks */
-module AP_MODULE_DECLARE_DATA netconf_module = {
- STANDARD20_MODULE_STUFF,
- NULL, /* create per-dir config structures */
- NULL, /* merge per-dir config structures */
- mod_netconf_create_conf, /* create per-server config structures */
- NULL, /* merge per-server config structures */
- netconf_cmds, /* table of config file commands */
- mod_netconf_register_hooks /* register hooks */
-};
-
int main(int argc, char **argv)
{
- apr_pool_t *pool;
- apr_app_initialize(&argc, (char const *const **) &argv, NULL);
- apr_signal(SIGTERM, signal_handler);
- apr_signal(SIGINT, signal_handler);
- apr_pool_create(&pool, NULL);
- forked_proc(pool, NULL);
- apr_pool_destroy(pool);
- apr_terminate();
+ struct sigaction action;
+ sigset_t block_mask;
+
+ if (argc > 1) {
+ sockname = argv[1];
+ } else {
+ sockname = SOCKET_FILENAME;
+ }
+
+ sigfillset (&block_mask);
+ action.sa_handler = signal_handler;
+ action.sa_mask = block_mask;
+ action.sa_flags = 0;
+ sigaction(SIGINT, &action, NULL);
+ sigaction(SIGTERM, &action, NULL);
+
+ forked_proc();
DEBUG("Terminated");
return 0;
}
diff --git a/src/mod_netconf.h b/src/mod_netconf.h
index 215d6e4..173fe73 100644
--- a/src/mod_netconf.h
+++ b/src/mod_netconf.h
@@ -48,25 +48,16 @@
#define __MOD_NETCONF_COMMON_H
#include <pthread.h>
-#include <httpd.h>
-#include <http_log.h>
-#include <http_config.h>
-#include <apr_hash.h>
#include <json/json.h>
#include <libssh2.h>
+#define UNUSED(x) UNUSED_ ## x __attribute__((__unused__))
+
/**
* \brief Check if pointer is not NULL, free memory and set pointer to NULL
*/
#define CHECK_AND_FREE(pointer) if (pointer != NULL) { free(pointer); pointer = NULL; }
-struct pass_to_thread {
- int client; /**< opened socket */
- apr_pool_t * pool; /**< ?? */
- server_rec * server; /**< ?? */
- apr_hash_t * netconf_sessions_list; /**< ?? */
-};
-
typedef struct notification {
time_t eventtime;
char* content;
@@ -74,19 +65,22 @@
struct session_with_mutex {
struct nc_session * session; /**< netconf session */
- apr_array_header_t *notifications;
+ notification_t *notifications;
+ int notif_count;
json_object *hello_message;
char ntfc_subscribed; /**< 0 when notifications are not subscribed */
char closed; /**< 0 when session is terminated */
- apr_time_t last_activity;
+ time_t last_activity;
pthread_mutex_t lock; /**< mutex protecting the session from multiple access */
+
+ struct session_with_mutex *prev;
+ struct session_with_mutex *next;
};
-typedef struct {
- apr_pool_t *pool;
- apr_proc_t *forkproc;
- char* sockname;
-} mod_netconf_cfg;
+struct pass_to_thread {
+ int client; /**< opened socket */
+ struct session_with_mutex *netconf_sessions_list; /**< ?? */
+};
extern pthread_rwlock_t session_lock; /**< mutex protecting netconf_session_list from multiple access errors */
@@ -97,31 +91,14 @@
json_object *create_error(const char *errmess);
json_object *create_ok();
-extern server_rec *http_server;
-#ifndef HTTPD_INDEPENDENT
-# define APLOGDEBUG(...) ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, __VA_ARGS__);
-# define APLOGERROR(...) ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, __VA_ARGS__);
-#else
-# define APLOGDEBUG(...)
-# define APLOGERROR(...)
-#endif
-
#define DEBUG(...) do { \
- if (http_server != NULL) { \
- APLOGDEBUG(__VA_ARGS__); \
- } else { \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
} while (0);
#define ERROR(...) do { \
- if (http_server != NULL) { \
- APLOGERROR(__VA_ARGS__); \
- } else { \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
} while (0);
#define GETSPEC_ERR_REPLY \
diff --git a/src/notification-server.c b/src/notification-server.c
index b58bd3d..8c15e21 100644
--- a/src/notification-server.c
+++ b/src/notification-server.c
@@ -29,18 +29,15 @@
#include <fcntl.h>
#include <assert.h>
#include <pthread.h>
+#include <errno.h>
#include <libnetconf.h>
#include <libwebsockets.h>
+
#include "notification_module.h"
#include "mod_netconf.h"
+#include "../config.h"
-#ifndef TEST_NOTIFICATION_SERVER
-#include <httpd.h>
-#include <http_log.h>
-#include <apr_hash.h>
-#include <apr_tables.h>
-
-#else
+#ifdef TEST_NOTIFICATION_SERVER
static int force_exit = 0;
#endif
@@ -54,10 +51,10 @@
struct ntf_thread_config {
struct nc_session *session;
- char *session_hash;
+ char *session_id;
};
-extern apr_hash_t *netconf_sessions_list;
+extern struct session_with_mutex *netconf_sessions_list;
static pthread_key_t thread_key;
/*
@@ -115,7 +112,7 @@
static int callback_http(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
- void *in, size_t len)
+ void *in, size_t UNUSED(len))
{
char client_name[128];
char client_ip[128];
@@ -127,7 +124,7 @@
switch (reason) {
case LWS_CALLBACK_HTTP:
- for (n = 0; n < (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
+ for (n = 0; n < (signed) (sizeof(whitelist) / sizeof(whitelist[0]) - 1); n++)
if (in && strcmp((const char *)in, whitelist[n].urlpath) == 0)
break;
@@ -263,22 +260,24 @@
struct per_session_data__notif_client {
int number;
- char *session_key;
+ char *session_id;
struct nc_session *session;
};
-struct session_with_mutex *get_ncsession_from_key(const char *session_key)
+struct session_with_mutex *get_ncsession_from_key(const char *session_id)
{
struct session_with_mutex *locked_session = NULL;
- if (session_key == NULL) {
+ if (session_id == NULL) {
return (NULL);
}
- locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+ for (locked_session = netconf_sessions_list;
+ strcmp(nc_session_get_id(locked_session->session), session_id);
+ locked_session = locked_session->next);
return locked_session;
}
/* rpc parameter is freed after the function call */
-static int send_recv_process(struct nc_session *session, const char* operation, nc_rpc* rpc)
+static int send_recv_process(struct nc_session *session, const char* UNUSED(operation), nc_rpc* rpc)
{
nc_reply *reply = NULL;
char *data = NULL;
@@ -338,32 +337,35 @@
{
struct session_with_mutex *target_session = NULL;
notification_t *ntf = NULL;
- char *session_hash = NULL;
+ const char *session_id = NULL;
DEBUG("Accepted notif: %lu %s\n", (unsigned long int) eventtime, content);
- session_hash = pthread_getspecific(thread_key);
- DEBUG("notification: fileprint getspecific (%s)", session_hash);
+ session_id = pthread_getspecific(thread_key);
+ DEBUG("notification: fileprint getspecific (%s)", session_id);
if (pthread_rwlock_wrlock(&session_lock) != 0) {
ERROR("notifications: Error while locking rwlock");
return;
}
- DEBUG("Get session with mutex from key %s.", session_hash);
- target_session = get_ncsession_from_key(session_hash);
+ DEBUG("Get session with mutex from key %s.", session_id);
+ target_session = get_ncsession_from_key(session_id);
if (target_session == NULL) {
- ERROR("notifications: no session found last_session_key (%s)", session_hash);
+ ERROR("notifications: no session found last_session_key (%s)", session_id);
goto unlock_glob;
}
if (pthread_mutex_lock(&target_session->lock) != 0) {
ERROR("notifications: Error while locking rwlock");
}
- if (target_session->notifications == NULL) {
- ERROR("notifications: target_session->notifications is NULL");
- goto unlock_all;
- }
DEBUG("notification: ready to push to notifications queue");
- ntf = (notification_t *) apr_array_push(target_session->notifications);
+ if (target_session->notif_count < NOTIFICATION_QUEUE_SIZE) {
+ ++target_session->notif_count;
+ target_session->notifications = realloc(target_session->notifications,
+ target_session->notif_count * sizeof *target_session->notifications);
+ if (target_session->notifications) {
+ ntf = target_session->notifications + target_session->notif_count - 1;
+ }
+ }
if (ntf == NULL) {
ERROR("notifications: Failed to allocate element ");
goto unlock_all;
@@ -393,15 +395,15 @@
DEBUG("notifications: in thread for libnetconf notifications");
/* store hash identification of netconf session for notifications printing callback */
- if (pthread_setspecific(thread_key, config->session_hash) != 0) {
+ if (pthread_setspecific(thread_key, config->session_id) != 0) {
ERROR("notifications: cannot set thread-specific hash value.");
}
DEBUG("notifications: dispatching");
ncntf_dispatch_receive(config->session, notification_fileprint);
DEBUG("notifications: ended thread for libnetconf notifications");
- if (config->session_hash != NULL) {
- free(config->session_hash);
+ if (config->session_id != NULL) {
+ free(config->session_id);
}
if (config != NULL) {
free(config);
@@ -410,7 +412,7 @@
}
-int notif_subscribe(struct session_with_mutex *locked_session, const char *session_hash, time_t start_time, time_t stop_time)
+int notif_subscribe(struct session_with_mutex *locked_session, const char *session_id, time_t start_time, time_t stop_time)
{
time_t start = -1;
time_t stop = -1;
@@ -486,8 +488,8 @@
goto operation_failed;
}
tconfig->session = session;
- tconfig->session_hash = strdup(session_hash);
- DEBUG("notifications: creating libnetconf notification thread (%s).", tconfig->session_hash);
+ tconfig->session_id = strdup(session_id);
+ DEBUG("notifications: creating libnetconf notification thread (%s).", tconfig->session_id);
pthread_mutex_unlock(&locked_session->lock);
DEBUG("Create notification_thread.");
@@ -509,8 +511,7 @@
enum libwebsocket_callback_reasons reason,
void *user, void *in, size_t len)
{
- int n = 0;
- int m = 0;
+ int n = 0, m = 0, i;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 40960 + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
struct per_session_data__notif_client *pss = (struct per_session_data__notif_client *)user;
@@ -521,7 +522,7 @@
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
- if (pss->session_key == NULL) {
+ if (pss->session_id == NULL) {
return 0;
}
//DEBUG("Callback server writeable.");
@@ -531,7 +532,7 @@
return -1;
}
//DEBUG("get session_with_mutex for %s.", pss->session_key);
- struct session_with_mutex *ls = get_ncsession_from_key(pss->session_key);
+ struct session_with_mutex *ls = get_ncsession_from_key(pss->session_id);
if (ls == NULL) {
DEBUG("notification: session not found");
if (pthread_rwlock_unlock (&session_lock) != 0) {
@@ -556,45 +557,36 @@
}
//DEBUG("lock private lock.");
notification_t *notif = NULL;
- //DEBUG("check for uninitialized notification list.");
- if (ls->notifications == NULL) {
- DEBUG("notification: no notifications array");
- DEBUG("unlock private lock.");
- if (pthread_mutex_unlock(&ls->lock) != 0) {
- DEBUG("notification: cannot unlock session");
- }
- return -1;
- }
- //DEBUG("check for empty notification list.");
- if (!apr_is_empty_array(ls->notifications)) {
- DEBUG("notification: POP notifications for session");
- while ((notif = (notification_t *) apr_array_pop(ls->notifications)) != NULL) {
- n = 0;
- pthread_mutex_lock(&json_lock);
- json_object *notif_json = json_object_new_object();
- json_object_object_add(notif_json, "eventtime", json_object_new_int64(notif->eventtime));
- json_object_object_add(notif_json, "content", json_object_new_string(notif->content));
- pthread_mutex_unlock(&json_lock);
+ DEBUG("notification: POP notifications for session");
- const char *msgtext = json_object_to_json_string(notif_json);
+ for (i = 0; i < ls->notif_count; ++i) {
+ notif = ls->notifications + i;
- //n = sprintf((char *)p, "{\"eventtime\": \"%s\", \"content\": \"notification\"}", t);
- n = sprintf((char *)p, "%s", msgtext);
- DEBUG("ws send %dB in %lu", n, sizeof(buf));
- m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
- if (lws_send_pipe_choked(wsi)) {
- libwebsocket_callback_on_writable(context, wsi);
- break;
- }
+ n = 0;
+ pthread_mutex_lock(&json_lock);
+ json_object *notif_json = json_object_new_object();
+ json_object_object_add(notif_json, "eventtime", json_object_new_int64(notif->eventtime));
+ json_object_object_add(notif_json, "content", json_object_new_string(notif->content));
+ pthread_mutex_unlock(&json_lock);
- pthread_mutex_lock(&json_lock);
- json_object_put(notif_json);
- pthread_mutex_unlock(&json_lock);
- free(notif->content);
- }
- DEBUG("notification: POP notifications done");
- }
+ const char *msgtext = json_object_to_json_string(notif_json);
+
+ //n = sprintf((char *)p, "{\"eventtime\": \"%s\", \"content\": \"notification\"}", t);
+ n = sprintf((char *)p, "%s", msgtext);
+ DEBUG("ws send %dB in %lu", n, sizeof(buf));
+ m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
+ if (lws_send_pipe_choked(wsi)) {
+ libwebsocket_callback_on_writable(context, wsi);
+ break;
+ }
+
+ pthread_mutex_lock(&json_lock);
+ json_object_put(notif_json);
+ pthread_mutex_unlock(&json_lock);
+ free(notif->content);
+ }
+ DEBUG("notification: POP notifications done");
//DEBUG("unlock private lock");
if (pthread_mutex_unlock(&ls->lock) != 0) {
@@ -612,26 +604,26 @@
case LWS_CALLBACK_RECEIVE:
DEBUG("Callback receive.");
DEBUG("received: (%s)", (char *)in);
- if (pss->session_key == NULL) {
- char session_key_buf[41];
+ if (pss->session_id == NULL) {
+ char session_id_buf[41];
int start = -1;
time_t stop = time(NULL) + 30;
- strncpy((char *) session_key_buf, (const char *) in, 40);
- session_key_buf[40] = '\0';
- pss->session_key = strdup(session_key_buf);
+ strncpy((char *) session_id_buf, (const char *) in, 40);
+ session_id_buf[40] = '\0';
+ pss->session_id = strdup(session_id_buf);
sscanf(in+40, "%d %d", (int *) &start, (int *) &stop);
- DEBUG("notification: get key (%s) from (%s) (%i,%i)", pss->session_key, (char *) in, (int) start, (int) stop);
+ DEBUG("notification: get key (%s) from (%s) (%i,%i)", pss->session_id, (char *) in, (int) start, (int) stop);
DEBUG("lock session lock");
if (pthread_rwlock_rdlock (&session_lock) != 0) {
DEBUG("Error while locking rwlock: %d (%s)", errno, strerror(errno));
return -1;
}
- DEBUG("get session from key (%s)", pss->session_key);
- struct session_with_mutex *ls = get_ncsession_from_key(pss->session_key);
+ DEBUG("get session from key (%s)", pss->session_id);
+ struct session_with_mutex *ls = get_ncsession_from_key(pss->session_id);
if (ls == NULL) {
- DEBUG("notification: session_key not found (%s)", pss->session_key);
+ DEBUG("notification: session_key not found (%s)", pss->session_id);
DEBUG("unlock session lock");
if (pthread_rwlock_unlock (&session_lock) != 0) {
DEBUG("Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
@@ -667,7 +659,7 @@
pthread_mutex_unlock(&ls->lock);
/* notif_subscribe locks on its own */
- return notif_subscribe(ls, pss->session_key, (time_t) start, (time_t) stop);
+ return notif_subscribe(ls, pss->session_id, (time_t) start, (time_t) stop);
}
if (len < 6)
break;
@@ -708,21 +700,29 @@
callback_http, /* callback */
sizeof (struct per_session_data__http), /* per_session_data_size */
0, /* max frame size / rx buffer */
+ 0,
+ NULL,
+ NULL,
+ 0
},
{
"notification-protocol",
callback_notification,
sizeof(struct per_session_data__notif_client),
4000,
+ 0,
+ NULL,
+ NULL,
+ 0
},
- { NULL, NULL, 0, 0 } /* terminator */
+ { NULL, NULL, 0, 0, 0, NULL, NULL, 0 } /* terminator */
};
/**
* initialization of notification module
*/
-int notification_init(apr_pool_t * pool, server_rec * server)
+int notification_init(void)
{
//char cert_path[1024];
//char key_path[1024];
@@ -777,7 +777,7 @@
return 0;
}
-void notification_close()
+void notification_close(void)
{
if (context) {
libwebsocket_context_destroy(context);
diff --git a/src/notification_module.h b/src/notification_module.h
index 49a96cc..f99f6fa 100644
--- a/src/notification_module.h
+++ b/src/notification_module.h
@@ -1,6 +1,6 @@
/*!
* \file notification_module.h
- * \brief
+ * \brief
* \author Tomas Cejka <cejkat@cesnet.cz>
* \date 2013
*/
@@ -44,12 +44,7 @@
#define __NOTIFICATION_MODULE_H
#include <libwebsockets.h>
-#ifndef TEST_NOTIFICATION_SERVER
-#include <httpd.h>
-#include <http_log.h>
-#include <apr_hash.h>
-#else
-typedef struct p {} apr_pool_t;
+#ifdef TEST_NOTIFICATION_SERVER
typedef struct s {} server_rec;
#endif
@@ -59,12 +54,9 @@
/**
* \brief Notification module initialization
- * \param pool - apr_pool_t for memory allocation
- * \param server - server_rec for Apache logging
- * \param conns - apr_hash_t representing the list of netconf connections
* \return 0 on success
*/
-int notification_init(apr_pool_t * pool, server_rec * server);
+int notification_init();
/**
* \brief Handle method - passes execution into the libwebsocket library