notifications FEATURE basic support for sending notifications from server side
diff --git a/src/io.c b/src/io.c
index 40fe815..a9afb58 100644
--- a/src/io.c
+++ b/src/io.c
@@ -964,6 +964,7 @@
const char *attrs;
struct lyd_node *content;
struct lyxml_elem *rpc_elem;
+ struct nc_server_notif *notif;
struct nc_server_reply *reply;
struct nc_server_reply_error *error_rpl;
char *buf = NULL;
@@ -1057,8 +1058,13 @@
break;
case NC_MSG_NOTIF:
- nc_write_clb((void *)&arg, "<notification xmlns=\""NC_NS_NOTIF"\"/>", 21 + 47 + 3, 0);
- /* TODO content */
+ notif = va_arg(ap, struct nc_server_notif *);
+
+ nc_write_clb((void *)&arg, "<notification xmlns=\""NC_NS_NOTIF"\">", 21 + 47 + 2, 0);
+ nc_write_clb((void *)&arg, "<eventTime>", 11, 0);
+ nc_write_clb((void *)&arg, notif->eventtime, strlen(notif->eventtime), 0);
+ nc_write_clb((void *)&arg, "</eventTime>", 12, 0);
+ lyd_print_clb(nc_write_xmlclb, (void *)&arg, notif->tree, LYD_XML, 0);
nc_write_clb((void *)&arg, "</notification>", 12, 0);
break;
diff --git a/src/messages_p.h b/src/messages_p.h
index ca171f7..e832b08 100644
--- a/src/messages_p.h
+++ b/src/messages_p.h
@@ -68,6 +68,11 @@
struct lyd_node *tree; /**< libyang data tree of the message (NETCONF operation) */
};
+struct nc_server_notif {
+ char *eventtime; /**< eventTime of the notification */
+ struct lyd_node *tree; /**< libyang data tree of the message */
+};
+
struct nc_client_reply_error {
NC_RPL type;
struct nc_err *err;
diff --git a/src/messages_server.c b/src/messages_server.c
index 20e805d..1d7aec4 100644
--- a/src/messages_server.c
+++ b/src/messages_server.c
@@ -19,8 +19,8 @@
#include <libyang/libyang.h>
-#include "session_server.h"
#include "libnetconf.h"
+#include "session_server.h"
extern struct nc_server_opts server_opts;
@@ -802,3 +802,39 @@
free(err->other);
free(err);
}
+
+API struct nc_server_notif *
+nc_server_notif_new(struct lyd_node* event, char *eventtime, int eventtime_const)
+{
+ struct nc_server_notif *ntf;
+
+ if (!event || event->schema->nodetype != LYS_NOTIF) {
+ ERRARG("event");
+ return NULL;
+ } else if (!eventtime) {
+ ERRARG("eventtime");
+ return NULL;
+ }
+
+ ntf = malloc(sizeof *ntf);
+ if (eventtime_const) {
+ ntf->eventtime = strdup(eventtime);
+ } else {
+ ntf->eventtime = eventtime;
+ }
+ ntf->tree = event;
+
+ return ntf;
+}
+
+API void
+nc_server_notif_free(struct nc_server_notif *notif)
+{
+ if (!notif) {
+ return;
+ }
+
+ lyd_free(notif->tree);
+ free(notif->eventtime);
+ free(notif);
+}
diff --git a/src/messages_server.h b/src/messages_server.h
index 733fe5c..feb5bdc 100644
--- a/src/messages_server.h
+++ b/src/messages_server.h
@@ -18,6 +18,7 @@
#include <stdint.h>
#include "netconf.h"
+#include "session.h"
/**
* @brief Enumeration of NETCONF errors
@@ -62,6 +63,11 @@
struct nc_server_reply;
/**
+ * @brief NETCONF server Event Notification object
+ */
+struct nc_server_notif;
+
+/**
* @brief NETCONF server error structure
*/
struct nc_server_error;
@@ -278,4 +284,41 @@
*/
void nc_err_free(struct nc_server_error *err);
+/**
+ * @brief Create Event Notification object to be sent to the subscribed client(s).
+ *
+ * @param[in] event Notification data tree (valid as LYD_OPT_NOTIF) from libyang. The tree is directly used in created
+ * object, so the caller is supposed to not free the tree on its own, but only via freeng the created object.
+ * @param[in] eventtime YANG dateTime format value of the time when the event was generated by the event source.
+ * Caller can use nc_time2datetime() to create the value from the time_t value. By default, the \p eventtime is handled
+ * the same way as the \p event tree - it is directly used in the created object and caller is supposed to avoid any
+ * further manipulation of the string. This can be changed by the \p eventtime_const parameter, which (set to nonzero)
+ * cause to make copy of the provided \p eventtime instead of using it directly.
+ * @param[in] eventtime_const Flag for changing the \p eventtime handling.
+ * @return Newly created structure of the Event Notification object to be sent to the clients via nc_server_send_notif()
+ * and freed using nc_server_notif_free().
+ */
+struct nc_server_notif *nc_server_notif_new(struct lyd_node* event, char *eventtime, int eventtime_const);
+
+/**
+ * @brief Send NETCONF Event Notification via the session.
+ *
+ * @param[in] session NETCONF session where the Event Notification will be written.
+ * @param[in] notif NETCOFN Notification object to send via specified session. Object can be created by
+ * nc_notif_new() function.
+ * @param[in] timeout Timeout for writing in milliseconds. Use negative value for infinite
+ * waiting and 0 for return if data cannot be sent immediately.
+ * @return #NC_MSG_NOTIF on success,
+ * #NC_MSG_WOULDBLOCK in case of a busy session, and
+ * #NC_MSG_ERROR on error.
+ */
+NC_MSG_TYPE nc_server_notif_send(struct nc_session *session, struct nc_server_notif *notif, int timeout);
+
+/**
+ * @brief Free a server Event Notification object.
+ *
+ * @param[in] notif Server Event Notification object to free.
+ */
+void nc_server_notif_free(struct nc_server_notif *notif);
+
#endif /* NC_MESSAGES_SERVER_H_ */
diff --git a/src/session_p.h b/src/session_p.h
index 09936a8..3491089 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -226,7 +226,6 @@
/* NETCONF data */
uint32_t id; /**< NETCONF session ID (session-id-type) */
NC_VERSION version; /**< NETCONF protocol version */
- volatile pthread_t *ntf_tid; /**< running notifications thread - TODO client-side only for now */
/* Transport implementation */
NC_TRANSPORT_IMPL ti_type; /**< transport implementation type to select items from ti union */
@@ -266,6 +265,7 @@
const char **cpblts; /**< list of server's capabilities on client side */
struct nc_msg_cont *replies; /**< queue for RPC replies received instead of notifications */
struct nc_msg_cont *notifs; /**< queue for notifications received instead of RPC reply */
+ volatile pthread_t *ntf_tid; /**< running notifications receiving thread */
/* server side only data */
time_t session_start; /**< time the session was created */
diff --git a/src/session_server.c b/src/session_server.c
index 0de6b1a..4e0de9c 100644
--- a/src/session_server.c
+++ b/src/session_server.c
@@ -851,7 +851,7 @@
* NC_PSPOLL_RPC
*/
static int
-nc_recv_rpc(struct nc_session *session, struct nc_server_rpc **rpc)
+nc_server_recv_rpc(struct nc_session *session, struct nc_server_rpc **rpc)
{
struct lyxml_elem *xml = NULL;
NC_MSG_TYPE msgtype;
@@ -924,6 +924,39 @@
return NC_PSPOLL_ERROR;
}
+API NC_MSG_TYPE
+nc_server_notif_send(struct nc_session *session, struct nc_server_notif *notif, int timeout)
+{
+ NC_MSG_TYPE result = NC_MSG_NOTIF;
+ int ret;
+
+ /* check parameters */
+ if (!session) {
+ ERRARG("session");
+ return NC_MSG_ERROR;
+ } else if (!notif || !notif->tree || !notif->eventtime) {
+ ERRARG("notif");
+ return NC_MSG_ERROR;
+ }
+
+ /* reading an RPC and sending a reply must be atomic (no other RPC should be read) */
+ ret = nc_timedlock(session->ti_lock, timeout);
+ if (ret < 0) {
+ return NC_MSG_ERROR;
+ } else if (!ret) {
+ return NC_MSG_WOULDBLOCK;
+ }
+
+ ret = nc_write_msg(session, NC_MSG_NOTIF, notif);
+ if (ret == -1) {
+ ERR("Session %u: failed to write notification.", session->id);
+ result = NC_MSG_ERROR;
+ }
+ pthread_mutex_unlock(session->ti_lock);
+
+ return result;
+}
+
/* must be called holding the session lock!
* returns: NC_PSPOLL_ERROR,
* NC_PSPOLL_ERROR | NC_PSPOLL_REPLY_ERROR,
@@ -931,7 +964,7 @@
* 0
*/
static int
-nc_send_reply(struct nc_session *session, struct nc_server_rpc *rpc)
+nc_server_send_reply(struct nc_session *session, struct nc_server_rpc *rpc)
{
nc_rpc_clb clb;
struct nc_server_reply *reply;
@@ -1155,7 +1188,7 @@
goto finish;
}
- ret = nc_recv_rpc(cur_session, &rpc);
+ ret = nc_server_recv_rpc(cur_session, &rpc);
if (ret & (NC_PSPOLL_ERROR | NC_PSPOLL_BAD_RPC)) {
pthread_mutex_unlock(cur_session->ti_lock);
if (cur_session->status != NC_STATUS_RUNNING) {
@@ -1167,7 +1200,7 @@
cur_session->last_rpc = time(NULL);
/* process RPC */
- ret |= nc_send_reply(cur_session, rpc);
+ ret |= nc_server_send_reply(cur_session, rpc);
pthread_mutex_unlock(cur_session->ti_lock);
if (cur_session->status != NC_STATUS_RUNNING) {
diff --git a/tests/test_io.c b/tests/test_io.c
index 6ad68ad..5b23b1c 100644
--- a/tests/test_io.c
+++ b/tests/test_io.c
@@ -27,9 +27,9 @@
#include <cmocka.h>
#include <libyang/libyang.h>
+#include <messages_p.h>
#include <session_p.h>
#include <session_client.h>
-#include <messages_p.h>
#include "config.h"
struct wr {