mod_netconf: notification testing version

- refs #655
diff --git a/src/Makefile.in b/src/Makefile.in
index bbc80db..e899de3 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -28,9 +28,12 @@
 LIBS=@LIBS@
 
 SRCS=mod_netconf.c \
+     notification-server.c \
      test-client.c
 
-HDRS=message_type.h
+HDRS=message_type.h \
+     notification_module.h \
+     mod_netconf.h
 
 all: module client
 
diff --git a/src/VERSION b/src/VERSION
index 78bc1ab..d9df1bb 100644
--- a/src/VERSION
+++ b/src/VERSION
@@ -1 +1 @@
-0.10.0
+0.11.0
diff --git a/src/configure b/src/configure
index 5bce59a..d64ca9b 100755
--- a/src/configure
+++ b/src/configure
@@ -2995,8 +2995,8 @@
    { (exit 1); exit 1; }; }
 fi
 
-REQS="$REQS libnetconf"
-BUILDREQS="$BUILDREQS libnetconf-devel"
+REQS="$REQS libnetconf >= 0.4.0 libwebsockets"
+BUILDREQS="$BUILDREQS libnetconf-devel libwebsockets-devel"
 CPPFLAGS=""
 
 # Checks for header files.
diff --git a/src/configure.in b/src/configure.in
index 43e7ca2..26715ae 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -29,8 +29,8 @@
 
 # Checks for libraries.
 AC_SEARCH_LIBS([ncds_apply_rpc],[netconf], ,AC_MSG_ERROR([libnetconf not found!]))
-REQS="$REQS libnetconf"
-BUILDREQS="$BUILDREQS libnetconf-devel"
+REQS="$REQS libnetconf >= 0.4.0 libwebsockets"
+BUILDREQS="$BUILDREQS libnetconf-devel libwebsockets-devel"
 CPPFLAGS=""
 
 # Checks for header files.
diff --git a/src/libwebsockets.h b/src/libwebsockets.h
deleted file mode 100644
index b7eaa41..0000000
--- a/src/libwebsockets.h
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation:
- *  version 2.1 of the License.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- *  MA  02110-1301  USA
- */
-
-#ifndef __LIBWEBSOCKET_H__
-#define __LIBWEBSOCKET_H__
-
-#ifdef __cplusplus
-extern "C" {
-#include <cstddef>
-#endif
-
-#ifdef WIN32
-
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN
-#endif
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <stddef.h>
-#include "../win32port/win32helpers/websock-w32.h"
-
-#include "../win32port/win32helpers/gettimeofday.h"
-
-#define strcasecmp stricmp
-#define getdtablesize() 30000
-
-typedef int ssize_t;
-
-#ifdef LWS_DLL
-#ifdef LWS_INTERNAL
-#define LWS_EXTERN extern __declspec(dllexport)
-#else
-#define LWS_EXTERN extern __declspec(dllimport)
-#endif
-#endif
-
-#else // NOT WIN32
-#include <poll.h>
-#include <unistd.h>
-#endif
-
-#include <assert.h>
-
-#ifndef LWS_EXTERN
-#define LWS_EXTERN extern
-#endif
-
-#define CONTEXT_PORT_NO_LISTEN 0
-#define MAX_MUX_RECURSION 2
-
-enum lws_log_levels {
-	LLL_ERR = 1 << 0,
-	LLL_WARN = 1 << 1,
-	LLL_NOTICE = 1 << 2,
-	LLL_INFO = 1 << 3,
-	LLL_DEBUG = 1 << 4,
-	LLL_PARSER = 1 << 5,
-	LLL_HEADER = 1 << 6,
-	LLL_EXT = 1 << 7,
-	LLL_CLIENT = 1 << 8,
-	LLL_LATENCY = 1 << 9,
-
-	LLL_COUNT = 10 /* set to count of valid flags */
-};
-
-LWS_EXTERN void _lws_log(int filter, const char *format, ...);
-
-/* notice, warn and log are always compiled in */
-#define lwsl_notice(...) _lws_log(LLL_NOTICE, __VA_ARGS__)
-#define lwsl_warn(...) _lws_log(LLL_WARN, __VA_ARGS__)
-#define lwsl_err(...) _lws_log(LLL_ERR, __VA_ARGS__)
-/*
- *  weaker logging can be deselected at configure time using --disable-debug
- *  that gets rid of the overhead of checking while keeping _warn and _err
- *  active
- */
-#ifdef _DEBUG
-
-#define lwsl_info(...) _lws_log(LLL_INFO, __VA_ARGS__)
-#define lwsl_debug(...) _lws_log(LLL_DEBUG, __VA_ARGS__)
-#define lwsl_parser(...) _lws_log(LLL_PARSER, __VA_ARGS__)
-#define lwsl_header(...)  _lws_log(LLL_HEADER, __VA_ARGS__)
-#define lwsl_ext(...)  _lws_log(LLL_EXT, __VA_ARGS__)
-#define lwsl_client(...) _lws_log(LLL_CLIENT, __VA_ARGS__)
-#define lwsl_latency(...) _lws_log(LLL_LATENCY, __VA_ARGS__)
-LWS_EXTERN void lwsl_hexdump(void *buf, size_t len);
-
-#else /* no debug */
-
-#define lwsl_info(...)
-#define lwsl_debug(...)
-#define lwsl_parser(...)
-#define lwsl_header(...)
-#define lwsl_ext(...)
-#define lwsl_client(...)
-#define lwsl_latency(...)
-#define lwsl_hexdump(a, b)
-
-#endif
-
-enum libwebsocket_context_options {
-	LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT = 2,
-	LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME = 4,
-};
-
-enum libwebsocket_callback_reasons {
-	LWS_CALLBACK_ESTABLISHED,
-	LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
-	LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
-	LWS_CALLBACK_CLIENT_ESTABLISHED,
-	LWS_CALLBACK_CLOSED,
-	LWS_CALLBACK_RECEIVE,
-	LWS_CALLBACK_CLIENT_RECEIVE,
-	LWS_CALLBACK_CLIENT_RECEIVE_PONG,
-	LWS_CALLBACK_CLIENT_WRITEABLE,
-	LWS_CALLBACK_SERVER_WRITEABLE,
-	LWS_CALLBACK_HTTP,
-	LWS_CALLBACK_HTTP_FILE_COMPLETION,
-	LWS_CALLBACK_HTTP_WRITEABLE,
-	LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
-	LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
-	LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS,
-	LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS,
-	LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION,
-	LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
-	LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
-	LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
-	LWS_CALLBACK_PROTOCOL_INIT,
-	LWS_CALLBACK_PROTOCOL_DESTROY,
-	/* external poll() management support */
-	LWS_CALLBACK_ADD_POLL_FD,
-	LWS_CALLBACK_DEL_POLL_FD,
-	LWS_CALLBACK_SET_MODE_POLL_FD,
-	LWS_CALLBACK_CLEAR_MODE_POLL_FD,
-};
-
-#ifndef LWS_NO_EXTENSIONS
-enum libwebsocket_extension_callback_reasons {
-	LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT,
-	LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT,
-	LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT,
-	LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT,
-	LWS_EXT_CALLBACK_CONSTRUCT,
-	LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
-	LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE,
-	LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
-	LWS_EXT_CALLBACK_DESTROY,
-	LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING,
-	LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED,
-	LWS_EXT_CALLBACK_PACKET_RX_PREPARSE,
-	LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
-	LWS_EXT_CALLBACK_PACKET_TX_DO_SEND,
-	LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
-	LWS_EXT_CALLBACK_FLUSH_PENDING_TX,
-	LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
-	LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
-	LWS_EXT_CALLBACK_1HZ,
-	LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE,
-	LWS_EXT_CALLBACK_IS_WRITEABLE,
-	LWS_EXT_CALLBACK_PAYLOAD_TX,
-	LWS_EXT_CALLBACK_PAYLOAD_RX,
-};
-#endif
-
-enum libwebsocket_write_protocol {
-	LWS_WRITE_TEXT,
-	LWS_WRITE_BINARY,
-	LWS_WRITE_CONTINUATION,
-	LWS_WRITE_HTTP,
-
-	/* special 04+ opcodes */
-
-	LWS_WRITE_CLOSE,
-	LWS_WRITE_PING,
-	LWS_WRITE_PONG,
-
-	/* flags */
-
-	LWS_WRITE_NO_FIN = 0x40,
-	/*
-	 * client packet payload goes out on wire unmunged
-	 * only useful for security tests since normal servers cannot
-	 * decode the content if used
-	 */
-	LWS_WRITE_CLIENT_IGNORE_XOR_MASK = 0x80
-};
-
-/*
- * you need these to look at headers that have been parsed if using the
- * LWS_CALLBACK_FILTER_CONNECTION callback.  If a header from the enum
- * list below is absent, .token = NULL and token_len = 0.  Otherwise .token
- * points to .token_len chars containing that header content.
- */
-
-struct lws_tokens {
-	char *token;
-	int token_len;
-};
-
-enum lws_token_indexes {
-	WSI_TOKEN_GET_URI,
-	WSI_TOKEN_HOST,
-	WSI_TOKEN_CONNECTION,
-	WSI_TOKEN_KEY1,
-	WSI_TOKEN_KEY2,
-	WSI_TOKEN_PROTOCOL,
-	WSI_TOKEN_UPGRADE,
-	WSI_TOKEN_ORIGIN,
-	WSI_TOKEN_DRAFT,
-	WSI_TOKEN_CHALLENGE,
-
-	/* new for 04 */
-	WSI_TOKEN_KEY,
-	WSI_TOKEN_VERSION,
-	WSI_TOKEN_SWORIGIN,
-
-	/* new for 05 */
-	WSI_TOKEN_EXTENSIONS,
-
-	/* client receives these */
-	WSI_TOKEN_ACCEPT,
-	WSI_TOKEN_NONCE,
-	WSI_TOKEN_HTTP,
-	WSI_TOKEN_MUXURL,
-
-	/* use token storage to stash these */
-
-	_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
-	_WSI_TOKEN_CLIENT_PEER_ADDRESS,
-	_WSI_TOKEN_CLIENT_URI,
-	_WSI_TOKEN_CLIENT_HOST,
-	_WSI_TOKEN_CLIENT_ORIGIN,
-
-	/* always last real token index*/
-	WSI_TOKEN_COUNT,
-	/* parser state additions */
-	WSI_TOKEN_NAME_PART,
-	WSI_TOKEN_SKIPPING,
-	WSI_TOKEN_SKIPPING_SAW_CR,
-	WSI_PARSING_COMPLETE,
-	WSI_INIT_TOKEN_MUXURL,
-};
-
-/*
- * From RFC 6455
-   1000
-
-      1000 indicates a normal closure, meaning that the purpose for
-      which the connection was established has been fulfilled.
-
-   1001
-
-      1001 indicates that an endpoint is "going away", such as a server
-      going down or a browser having navigated away from a page.
-
-   1002
-
-      1002 indicates that an endpoint is terminating the connection due
-      to a protocol error.
-
-   1003
-
-      1003 indicates that an endpoint is terminating the connection
-      because it has received a type of data it cannot accept (e.g., an
-      endpoint that understands only text data MAY send this if it
-      receives a binary message).
-
-   1004
-
-      Reserved.  The specific meaning might be defined in the future.
-
-   1005
-
-      1005 is a reserved value and MUST NOT be set as a status code in a
-      Close control frame by an endpoint.  It is designated for use in
-      applications expecting a status code to indicate that no status
-      code was actually present.
-
-   1006
-
-      1006 is a reserved value and MUST NOT be set as a status code in a
-      Close control frame by an endpoint.  It is designated for use in
-      applications expecting a status code to indicate that the
-      connection was closed abnormally, e.g., without sending or
-      receiving a Close control frame.
-
-   1007
-
-      1007 indicates that an endpoint is terminating the connection
-      because it has received data within a message that was not
-      consistent with the type of the message (e.g., non-UTF-8 [RFC3629]
-      data within a text message).
-
-   1008
-
-      1008 indicates that an endpoint is terminating the connection
-      because it has received a message that violates its policy.  This
-      is a generic status code that can be returned when there is no
-      other more suitable status code (e.g., 1003 or 1009) or if there
-      is a need to hide specific details about the policy.
-
-   1009
-
-      1009 indicates that an endpoint is terminating the connection
-      because it has received a message that is too big for it to
-      process.
-
-   1010
-
-      1010 indicates that an endpoint (client) is terminating the
-      connection because it has expected the server to negotiate one or
-      more extension, but the server didn't return them in the response
-      message of the WebSocket handshake.  The list of extensions that
-      are needed SHOULD appear in the /reason/ part of the Close frame.
-      Note that this status code is not used by the server, because it
-      can fail the WebSocket handshake instead.
-
-   1011
-
-      1011 indicates that a server is terminating the connection because
-      it encountered an unexpected condition that prevented it from
-      fulfilling the request.
-
-   1015
-
-      1015 is a reserved value and MUST NOT be set as a status code in a
-      Close control frame by an endpoint.  It is designated for use in
-      applications expecting a status code to indicate that the
-      connection was closed due to a failure to perform a TLS handshake
-      (e.g., the server certificate can't be verified).
-*/
-
-enum lws_close_status {
-	LWS_CLOSE_STATUS_NOSTATUS = 0,
-	LWS_CLOSE_STATUS_NORMAL = 1000,
-	LWS_CLOSE_STATUS_GOINGAWAY = 1001,
-	LWS_CLOSE_STATUS_PROTOCOL_ERR = 1002,
-	LWS_CLOSE_STATUS_UNACCEPTABLE_OPCODE = 1003,
-	LWS_CLOSE_STATUS_RESERVED = 1004,
-	LWS_CLOSE_STATUS_NO_STATUS = 1005,
-	LWS_CLOSE_STATUS_ABNORMAL_CLOSE = 1006,
-	LWS_CLOSE_STATUS_INVALID_PAYLOAD = 1007,
-	LWS_CLOSE_STATUS_POLICY_VIOLATION = 1008,
-	LWS_CLOSE_STATUS_MESSAGE_TOO_LARGE = 1009,
-	LWS_CLOSE_STATUS_EXTENSION_REQUIRED = 1010,
-	LWS_CLOSE_STATUS_UNEXPECTED_CONDITION = 1011,
-	LWS_CLOSE_STATUS_TLS_FAILURE = 1015,
-};
-
-struct libwebsocket;
-struct libwebsocket_context;
-/* needed even with extensions disabled for create context */
-struct libwebsocket_extension;
-
-/**
- * callback_function() - User server actions
- * @context:	Websockets context
- * @wsi:	Opaque websocket instance pointer
- * @reason:	The reason for the call
- * @user:	Pointer to per-session user data allocated by library
- * @in:		Pointer used for some callback reasons
- * @len:	Length set for some callback reasons
- *
- *	This callback is the way the user controls what is served.  All the
- *	protocol detail is hidden and handled by the library.
- *
- *	For each connection / session there is user data allocated that is
- *	pointed to by "user".  You set the size of this user data area when
- *	the library is initialized with libwebsocket_create_server.
- *
- *	You get an opportunity to initialize user data when called back with
- *	LWS_CALLBACK_ESTABLISHED reason.
- *
- *  LWS_CALLBACK_ESTABLISHED:  after the server completes a handshake with
- *				an incoming client
- *
- *  LWS_CALLBACK_CLIENT_CONNECTION_ERROR: the request client connection has
- *        been unable to complete a handshake with the remote server
- *
- *  LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH: this is the last chance for the
- *				client user code to examine the http headers
- *				and decide to reject the connection.  If the
- *				content in the headers is interesting to the
- *				client (url, etc) it needs to copy it out at
- *				this point since it will be destroyed before
- *				the CLIENT_ESTABLISHED call
- *
- *  LWS_CALLBACK_CLIENT_ESTABLISHED: after your client connection completed
- *				a handshake with the remote server
- *
- *	LWS_CALLBACK_CLOSED: when the websocket session ends
- *
- *	LWS_CALLBACK_RECEIVE: data has appeared for this server endpoint from a
- *				remote client, it can be found at *in and is
- *				len bytes long
- *
- *	LWS_CALLBACK_CLIENT_RECEIVE_PONG: if you elected to see PONG packets,
- *				they appear with this callback reason.  PONG
- *				packets only exist in 04+ protocol
- *
- *	LWS_CALLBACK_CLIENT_RECEIVE: data has appeared from the server for the
- *				client connection, it can be found at *in and
- *				is len bytes long
- *
- *	LWS_CALLBACK_HTTP: an http request has come from a client that is not
- *				asking to upgrade the connection to a websocket
- *				one.  This is a chance to serve http content,
- *				for example, to send a script to the client
- *				which will then open the websockets connection.
- *				@in points to the URI path requested and
- *				libwebsockets_serve_http_file() makes it very
- *				simple to send back a file to the client.
- *				Normally after sending the file you are done
- *				with the http connection, since the rest of the
- *				activity will come by websockets from the script
- *				that was delivered by http, so you will want to
- *				return 1; to close and free up the connection.
- *				That's important because it uses a slot in the
- *				total number of client connections allowed set
- *				by MAX_CLIENTS.
- *
- *	LWS_CALLBACK_HTTP_WRITEABLE: you can write more down the http protocol
- *		link now.
- *
- *	LWS_CALLBACK_HTTP_FILE_COMPLETION: a file requested to be send down
- *				http link has completed.
- *
- *	LWS_CALLBACK_CLIENT_WRITEABLE:
- *      LWS_CALLBACK_SERVER_WRITEABLE:   If you call
- *		libwebsocket_callback_on_writable() on a connection, you will
- *		get one of these callbacks coming when the connection socket
- *		is able to accept another write packet without blocking.
- *		If it already was able to take another packet without blocking,
- *		you'll get this callback at the next call to the service loop
- *		function.  Notice that CLIENTs get LWS_CALLBACK_CLIENT_WRITEABLE
- *		and servers get LWS_CALLBACK_SERVER_WRITEABLE.
- *
- *	LWS_CALLBACK_FILTER_NETWORK_CONNECTION: called when a client connects to
- *		the server at network level; the connection is accepted but then
- *		passed to this callback to decide whether to hang up immediately
- *		or not, based on the client IP.  @in contains the connection
- *		socket's descriptor.  Return non-zero to terminate
- *		the connection before sending or receiving anything.
- *		Because this happens immediately after the network connection
- *		from the client, there's no websocket protocol selected yet so
- *		this callback is issued only to protocol 0.
- *
- *	LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: called when the handshake has
- *		been received and parsed from the client, but the response is
- *		not sent yet.  Return non-zero to disallow the connection.
- *		@user is a pointer to an array of struct lws_tokens, you can
- *		use the header enums lws_token_indexes from libwebsockets.h
- *		to check for and read the supported header presence and
- *		content before deciding to allow the handshake to proceed or
- *		to kill the connection.
- *
- *	LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if configured for
- *		including OpenSSL support, this callback allows your user code
- *		to perform extra SSL_CTX_load_verify_locations() or similar
- *		calls to direct OpenSSL where to find certificates the client
- *		can use to confirm the remote server identity.  @user is the
- *		OpenSSL SSL_CTX*
- *
- *	LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if configured for
- *		including OpenSSL support, this callback allows your user code
- *		to load extra certifcates into the server which allow it to
- *		verify the validity of certificates returned by clients.  @user
- *		is the server's OpenSSL SSL_CTX*
- *
- *	LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: if the
- *		libwebsockets context was created with the option
- *		LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT, then this
- *		callback is generated during OpenSSL verification of the cert
- *		sent from the client.  It is sent to protocol[0] callback as
- *		no protocol has been negotiated on the connection yet.
- *		Notice that the libwebsockets context and wsi are both NULL
- *		during this callback.  See
- *		 http://www.openssl.org/docs/ssl/SSL_CTX_set_verify.html
- *		to understand more detail about the OpenSSL callback that
- *		generates this libwebsockets callback and the meanings of the
- *		arguments passed.  In this callback, @user is the x509_ctx,
- *		@in is the ssl pointer and @len is preverify_ok
- *		Notice that this callback maintains libwebsocket return
- *		conventions, return 0 to mean the cert is OK or 1 to fail it.
- *		This also means that if you don't handle this callback then
- *		the default callback action of returning 0 allows the client
- *		certificates.
- *
- *	LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER: this callback happens
- *		when a client handshake is being compiled.  @user is NULL,
- *		@in is a char **, it's pointing to a char * which holds the
- *		next location in the header buffer where you can add
- *		headers, and @len is the remaining space in the header buffer,
- *		which is typically some hundreds of bytes.  So, to add a canned
- *		cookie, your handler code might look similar to:
- *
- *		char **p = (char **)in;
- *
- *		if (len < 100)
- *			return 1;
- *
- *		*p += sprintf(*p, "Cookie: a=b\x0d\x0a");
- *
- *		return 0;
- *
- *		Notice if you add anything, you just have to take care about
- *		the CRLF on the line you added.  Obviously this callback is
- *		optional, if you don't handle it everything is fine.
- *
- *		Notice the callback is coming to protocols[0] all the time,
- *		because there is no specific protocol handshook yet.
- *
- *	LWS_CALLBACK_CONFIRM_EXTENSION_OKAY: When the server handshake code
- *		sees that it does support a requested extension, before
- *		accepting the extension by additing to the list sent back to
- *		the client it gives this callback just to check that it's okay
- *		to use that extension.  It calls back to the requested protocol
- *		and with @in being the extension name, @len is 0 and @user is
- *		valid.  Note though at this time the ESTABLISHED callback hasn't
- *		happened yet so if you initialize @user content there, @user
- *		content during this callback might not be useful for anything.
- *		Notice this callback comes to protocols[0].
- *
- *	LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED:	When a client
- *		connection is being prepared to start a handshake to a server,
- *		each supported extension is checked with protocols[0] callback
- *		with this reason, giving the user code a chance to suppress the
- *		claim to support that extension by returning non-zero.  If
- *		unhandled, by default 0 will be returned and the extension
- *		support included in the header to the server.  Notice this
- *		callback comes to protocols[0].
- *
- *	LWS_CALLBACK_PROTOCOL_INIT:	One-time call per protocol so it can
- *		do initial setup / allocations etc
- *
- *	LWS_CALLBACK_PROTOCOL_DESTROY:	One-time call per protocol indicating
- *		this protocol won't get used at all after this callback, the
- *		context is getting destroyed.  Take the opportunity to
- *		deallocate everything that was allocated by the protocol.
- *
- *	The next four reasons are optional and only need taking care of if you
- *	will be integrating libwebsockets sockets into an external polling
- *	array.
- *
- *	LWS_CALLBACK_ADD_POLL_FD: libwebsocket deals with its poll() loop
- *		internally, but in the case you are integrating with another
- *		server you will need to have libwebsocket sockets share a
- *		polling array with the other server.  This and the other
- *		POLL_FD related callbacks let you put your specialized
- *		poll array interface code in the callback for protocol 0, the
- *		first protocol you support, usually the HTTP protocol in the
- *		serving case.  This callback happens when a socket needs to be
- *		added to the polling loop: @in contains the fd, and
- *		@len is the events bitmap (like, POLLIN).  If you are using the
- *		internal polling loop (the "service" callback), you can just
- *		ignore these callbacks.
- *
- *	LWS_CALLBACK_DEL_POLL_FD: This callback happens when a socket descriptor
- *		needs to be removed from an external polling array.  @in is
- *		the socket desricptor.  If you are using the internal polling
- *		loop, you can just ignore it.
- *
- *	LWS_CALLBACK_SET_MODE_POLL_FD: This callback happens when libwebsockets
- *		wants to modify the events for the socket descriptor in @in.
- *		The handler should OR @len on to the events member of the pollfd
- *		struct for this socket descriptor.  If you are using the
- *		internal polling loop, you can just ignore it.
- *
- *	LWS_CALLBACK_CLEAR_MODE_POLL_FD: This callback occurs when libwebsockets
- *		wants to modify the events for the socket descriptor in @in.
- *		The handler should AND ~@len on to the events member of the
- *		pollfd struct for this socket descriptor.  If you are using the
- *		internal polling loop, you can just ignore it.
- */
-LWS_EXTERN int callback(struct libwebsocket_context *context,
-			struct libwebsocket *wsi,
-			 enum libwebsocket_callback_reasons reason, void *user,
-							  void *in, size_t len);
-
-typedef int (callback_function)(struct libwebsocket_context *context,
-			struct libwebsocket *wsi,
-			 enum libwebsocket_callback_reasons reason, void *user,
-							  void *in, size_t len);
-
-#ifndef LWS_NO_EXTENSIONS
-/**
- * extension_callback_function() - Hooks to allow extensions to operate
- * @context:	Websockets context
- * @ext:	This extension
- * @wsi:	Opaque websocket instance pointer
- * @reason:	The reason for the call
- * @user:	Pointer to per-session user data allocated by library
- * @in:		Pointer used for some callback reasons
- * @len:	Length set for some callback reasons
- *
- *	Each extension that is active on a particular connection receives
- *	callbacks during the connection lifetime to allow the extension to
- *	operate on websocket data and manage itself.
- *
- *	Libwebsockets takes care of allocating and freeing "user" memory for
- *	each active extension on each connection.  That is what is pointed to
- *	by the @user parameter.
- *
- *	LWS_EXT_CALLBACK_CONSTRUCT:  called when the server has decided to
- *		select this extension from the list provided by the client,
- *		just before the server will send back the handshake accepting
- *		the connection with this extension active.  This gives the
- *		extension a chance to initialize its connection context found
- *		in @user.
- *
- *	LWS_EXT_CALLBACK_CLIENT_CONSTRUCT: same as LWS_EXT_CALLBACK_CONSTRUCT
- *		but called when client is instantiating this extension.  Some
- *		extensions will work the same on client and server side and then
- *		you can just merge handlers for both CONSTRUCTS.
- *
- *	LWS_EXT_CALLBACK_DESTROY:  called when the connection the extension was
- *		being used on is about to be closed and deallocated.  It's the
- *		last chance for the extension to deallocate anything it has
- *		allocated in the user data (pointed to by @user) before the
- *		user data is deleted.  This same callback is used whether you
- *		are in client or server instantiation context.
- *
- *	LWS_EXT_CALLBACK_PACKET_RX_PREPARSE: when this extension was active on
- *		a connection, and a packet of data arrived at the connection,
- *		it is passed to this callback to give the extension a chance to
- *		change the data, eg, decompress it.  @user is pointing to the
- *		extension's private connection context data, @in is pointing
- *		to an lws_tokens struct, it consists of a char * pointer called
- *		token, and an int called token_len.  At entry, these are
- *		set to point to the received buffer and set to the content
- *		length.  If the extension will grow the content, it should use
- *		a new buffer allocated in its private user context data and
- *		set the pointed-to lws_tokens members to point to its buffer.
- *
- *	LWS_EXT_CALLBACK_PACKET_TX_PRESEND: this works the same way as
- *		LWS_EXT_CALLBACK_PACKET_RX_PREPARSE above, except it gives the
- *		extension a chance to change websocket data just before it will
- *		be sent out.  Using the same lws_token pointer scheme in @in,
- *		the extension can change the buffer and the length to be
- *		transmitted how it likes.  Again if it wants to grow the
- *		buffer safely, it should copy the data into its own buffer and
- *		set the lws_tokens token pointer to it.
- */
-LWS_EXTERN int extension_callback(struct libwebsocket_context *context,
-			struct libwebsocket_extension *ext,
-			struct libwebsocket *wsi,
-			enum libwebsocket_extension_callback_reasons reason,
-			void *user, void *in, size_t len);
-
-typedef int (extension_callback_function)(struct libwebsocket_context *context,
-			struct libwebsocket_extension *ext,
-			struct libwebsocket *wsi,
-			enum libwebsocket_extension_callback_reasons reason,
-			void *user, void *in, size_t len);
-#endif
-
-/**
- * struct libwebsocket_protocols -	List of protocols and handlers server
- *					supports.
- * @name:	Protocol name that must match the one given in the client
- *		Javascript new WebSocket(url, 'protocol') name
- * @callback:	The service callback used for this protocol.  It allows the
- *		service action for an entire protocol to be encapsulated in
- *		the protocol-specific callback
- * @per_session_data_size:	Each new connection using this protocol gets
- *		this much memory allocated on connection establishment and
- *		freed on connection takedown.  A pointer to this per-connection
- *		allocation is passed into the callback in the 'user' parameter
- * @rx_buffer_size: if you want atomic frames delivered to the callback, you
- *		should set this to the size of the biggest legal frame that
- *		you support.  If the frame size is exceeded, there is no
- *		error, but the buffer will spill to the user callback when
- *		full, which you can detect by using
- *		libwebsockets_remaining_packet_payload().  Notice that you
- *		just talk about frame size here, the LWS_SEND_BUFFER_PRE_PADDING
- *		and post-padding are automatically also allocated on top.
- * @owning_server:	the server init call fills in this opaque pointer when
- *		registering this protocol with the server.
- * @protocol_index: which protocol we are starting from zero
- *
- *	This structure represents one protocol supported by the server.  An
- *	array of these structures is passed to libwebsocket_create_server()
- *	allows as many protocols as you like to be handled by one server.
- */
-
-struct libwebsocket_protocols {
-	const char *name;
-	callback_function *callback;
-	size_t per_session_data_size;
-	size_t rx_buffer_size;
-
-	/*
-	 * below are filled in on server init and can be left uninitialized,
-	 * no need for user to use them directly either
-	 */
-
-	struct libwebsocket_context *owning_server;
-	int protocol_index;
-};
-
-#ifndef LWS_NO_EXTENSIONS
-/**
- * struct libwebsocket_extension -	An extension we know how to cope with
- *
- * @name:			Formal extension name, eg, "deflate-stream"
- * @callback:			Service callback
- * @per_session_data_size:	Libwebsockets will auto-malloc this much
- *				memory for the use of the extension, a pointer
- *				to it comes in the @user callback parameter
- * @per_context_private_data:   Optional storage for this extension that
- *				is per-context, so it can track stuff across
- *				all sessions, etc, if it wants
- */
-
-struct libwebsocket_extension {
-	const char *name;
-	extension_callback_function *callback;
-	size_t per_session_data_size;
-	void *per_context_private_data;
-};
-#endif
-
-/**
- * struct lws_context_creation_info: parameters to create context with
- *
- * @port:	Port to listen on... you can use 0 to suppress listening on
- *		any port, that's what you want if you are not running a
- *		websocket server at all but just using it as a client
- * @iface:	NULL to bind the listen socket to all interfaces, or the
- *		interface name, eg, "eth2"
- * @protocols:	Array of structures listing supported protocols and a protocol-
- *		specific callback for each one.  The list is ended with an
- *		entry that has a NULL callback pointer.
- *		It's not const because we write the owning_server member
- * @extensions: NULL or array of libwebsocket_extension structs listing the
- *		extensions this context supports.  If you configured with
- *		--without-extensions, you should give NULL here.
- * @ssl_cert_filepath:	If libwebsockets was compiled to use ssl, and you want
- *			to listen using SSL, set to the filepath to fetch the
- *			server cert from, otherwise NULL for unencrypted
- * @ssl_private_key_filepath: filepath to private key if wanting SSL mode,
- *			else ignored
- * @ssl_ca_filepath: CA certificate filepath or NULL
- * @ssl_cipher_list:	List of valid ciphers to use (eg,
- * 			"RC4-MD5:RC4-SHA:AES128-SHA:AES256-SHA:HIGH:!DSS:!aNULL"
- * 			or you can leave it as NULL to get "DEFAULT"
- * @gid:	group id to change to after setting listen socket, or -1.
- * @uid:	user id to change to after setting listen socket, or -1.
- * @options:	0, or LWS_SERVER_OPTION_DEFEAT_CLIENT_MASK
- * @user:	optional user pointer that can be recovered via the context
- *		pointer using libwebsocket_context_user
- * @ka_time:	0 for no keepalive, otherwise apply this keepalive timeout to
- *		all libwebsocket sockets, client or server
- * @ka_probes:	if ka_time was nonzero, after the timeout expires how many
- *		times to try to get a response from the peer before giving up
- *		and killing the connection
- * @ka_interval: if ka_time was nonzero, how long to wait before each ka_probes
- *		attempt
- */
-
-struct lws_context_creation_info {
-	int port;
-	const char *iface;
-	struct libwebsocket_protocols *protocols;
-	struct libwebsocket_extension *extensions;
-	const char *ssl_cert_filepath;
-	const char *ssl_private_key_filepath;
-	const char *ssl_ca_filepath;
-	const char *ssl_cipher_list;
-	int gid;
-	int uid;
-	unsigned int options;
-	void *user;
-	int ka_time;
-	int ka_probes;
-	int ka_interval;
-
-};
-
-LWS_EXTERN
-void lws_set_log_level(int level,
-			void (*log_emit_function)(int level, const char *line));
-
-LWS_EXTERN void
-lwsl_emit_syslog(int level, const char *line);
-
-LWS_EXTERN struct libwebsocket_context *
-libwebsocket_create_context(struct lws_context_creation_info *info);
-
-LWS_EXTERN void
-libwebsocket_context_destroy(struct libwebsocket_context *context);
-
-LWS_EXTERN int
-libwebsocket_service(struct libwebsocket_context *context, int timeout_ms);
-
-LWS_EXTERN int
-libwebsocket_service_fd(struct libwebsocket_context *context,
-							 struct pollfd *pollfd);
-
-LWS_EXTERN void *
-libwebsocket_context_user(struct libwebsocket_context *context);
-
-/*
- * IMPORTANT NOTICE!
- *
- * When sending with websocket protocol (LWS_WRITE_TEXT or LWS_WRITE_BINARY)
- * the send buffer has to have LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE
- * buf, and LWS_SEND_BUFFER_POST_PADDING bytes valid AFTER (buf + len).
- *
- * This allows us to add protocol info before and after the data, and send as
- * one packet on the network without payload copying, for maximum efficiency.
- *
- * So for example you need this kind of code to use libwebsocket_write with a
- * 128-byte payload
- *
- *   char buf[LWS_SEND_BUFFER_PRE_PADDING + 128 + LWS_SEND_BUFFER_POST_PADDING];
- *
- *   // fill your part of the buffer... for example here it's all zeros
- *   memset(&buf[LWS_SEND_BUFFER_PRE_PADDING], 0, 128);
- *
- *   libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING], 128,
- *   								LWS_WRITE_TEXT);
- *
- * When sending LWS_WRITE_HTTP, there is no protocol addition and you can just
- * use the whole buffer without taking care of the above.
- */
-
-/*
- * this is the frame nonce plus two header plus 8 length
- *   there's an additional two for mux extension per mux nesting level
- * 2 byte prepend on close will already fit because control frames cannot use
- * the big length style
- */
-
-#define LWS_SEND_BUFFER_PRE_PADDING (4 + 10 + (2 * MAX_MUX_RECURSION))
-#define LWS_SEND_BUFFER_POST_PADDING 4
-
-LWS_EXTERN int
-libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len,
-				     enum libwebsocket_write_protocol protocol);
-
-LWS_EXTERN int
-libwebsockets_serve_http_file(struct libwebsocket_context *context,
-			struct libwebsocket *wsi, const char *file,
-						     const char *content_type);
-LWS_EXTERN int
-libwebsockets_serve_http_file_fragment(struct libwebsocket_context *context,
-			struct libwebsocket *wsi);
-
-LWS_EXTERN const struct libwebsocket_protocols *
-libwebsockets_get_protocol(struct libwebsocket *wsi);
-
-LWS_EXTERN int
-libwebsocket_callback_on_writable(struct libwebsocket_context *context,
-						      struct libwebsocket *wsi);
-
-LWS_EXTERN int
-libwebsocket_callback_on_writable_all_protocol(
-				 const struct libwebsocket_protocols *protocol);
-
-LWS_EXTERN int
-libwebsocket_get_socket_fd(struct libwebsocket *wsi);
-
-LWS_EXTERN int
-libwebsocket_is_final_fragment(struct libwebsocket *wsi);
-
-LWS_EXTERN unsigned char
-libwebsocket_get_reserved_bits(struct libwebsocket *wsi);
-
-LWS_EXTERN int
-libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable);
-
-LWS_EXTERN void
-libwebsocket_rx_flow_allow_all_protocol(
-				const struct libwebsocket_protocols *protocol);
-
-LWS_EXTERN size_t
-libwebsockets_remaining_packet_payload(struct libwebsocket *wsi);
-
-LWS_EXTERN struct libwebsocket *
-libwebsocket_client_connect(struct libwebsocket_context *clients,
-			      const char *address,
-			      int port,
-			      int ssl_connection,
-			      const char *path,
-			      const char *host,
-			      const char *origin,
-			      const char *protocol,
-			      int ietf_version_or_minus_one);
-
-LWS_EXTERN struct libwebsocket *
-libwebsocket_client_connect_extended(struct libwebsocket_context *clients,
-			      const char *address,
-			      int port,
-			      int ssl_connection,
-			      const char *path,
-			      const char *host,
-			      const char *origin,
-			      const char *protocol,
-			      int ietf_version_or_minus_one,
-			      void *userdata);
-
-LWS_EXTERN const char *
-libwebsocket_canonical_hostname(struct libwebsocket_context *context);
-
-
-LWS_EXTERN void
-libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
-		struct libwebsocket *wsi, int fd, char *name, int name_len,
-					char *rip, int rip_len);
-
-LWS_EXTERN int
-libwebsockets_get_random(struct libwebsocket_context *context,
-							    void *buf, int len);
-
-LWS_EXTERN int
-lws_daemonize(const char *_lock_path);
-
-LWS_EXTERN int
-lws_send_pipe_choked(struct libwebsocket *wsi);
-
-LWS_EXTERN int
-lws_frame_is_binary(struct libwebsocket *wsi);
-
-LWS_EXTERN unsigned char *
-libwebsockets_SHA1(const unsigned char *d, size_t n, unsigned char *md);
-
-LWS_EXTERN int
-lws_b64_encode_string(const char *in, int in_len, char *out, int out_size);
-
-LWS_EXTERN int
-lws_b64_decode_string(const char *in, char *out, int out_size);
-
-LWS_EXTERN const char *
-lws_get_library_version(void);
-
-/* access to headers... only valid while headers valid */
-
-LWS_EXTERN int
-lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h);
-
-LWS_EXTERN int
-lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
-						enum lws_token_indexes h);
-
-/*
- * Note: this is not normally needed as a user api.  It's provided in case it is
- * useful when integrating with other app poll loop service code.
- */
-
-LWS_EXTERN int
-libwebsocket_read(struct libwebsocket_context *context,
-				struct libwebsocket *wsi,
-					       unsigned char *buf, size_t len);
-
-#ifndef LWS_NO_EXTENSIONS
-LWS_EXTERN struct libwebsocket_extension *libwebsocket_get_internal_extensions();
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index b2e11de..24aa4d8 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -223,6 +223,7 @@
 				(port==NULL) ? "830" : port,
 				nc_session_get_id(session));
 
+		/** \todo allocate from apr_pool */
 		if ((locked_session = malloc (sizeof (struct session_with_mutex))) == NULL || pthread_mutex_init (&locked_session->lock, NULL) != 0) {
 			nc_session_free(session);
 			free (locked_session);
@@ -240,6 +241,7 @@
 			ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "Error while locking rwlock: %d (%s)", errno, strerror(errno));
 			return NULL;
 		}
+		locked_session->notifications = apr_array_make(pool, NOTIFICATION_QUEUE_SIZE, sizeof(notification_t));
 		ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, server, "Add connection to the list");
 		apr_hash_set(conns, apr_pstrdup(pool, session_key), APR_HASH_KEY_STRING, (void *) locked_session);
 		ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, server, "Before session_unlock");
@@ -270,6 +272,8 @@
 	}
 	locked_session = (struct session_with_mutex *)apr_hash_get(conns, session_key, APR_HASH_KEY_STRING);
 	if (locked_session != NULL) {
+		/** \todo free all notifications from queue */
+		apr_array_clear(locked_session->notifications);
 		pthread_mutex_destroy(&locked_session->lock);
 		ns = locked_session->session;
 		free (locked_session);
@@ -1446,8 +1450,11 @@
 		return;
 	}
 
+	/* prepare internal lists */
+	netconf_sessions_list = apr_hash_make(pool);
+
 	#ifdef WITH_NOTIFICATIONS
-	if (notification_init(pool, server) == -1) {
+	if (notification_init(pool, server, netconf_sessions_list) == -1) {
 		ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "libwebsockets initialization failed");
 		use_notifications = 0;
 	} else {
@@ -1455,9 +1462,6 @@
 	}
 	#endif
 
-	/* prepare internal lists */
-	netconf_sessions_list = apr_hash_make(pool);
-
 	/* setup libnetconf's callbacks */
 	nc_verbosity(NC_VERB_DEBUG);
 	clb_print_server = server;
diff --git a/src/mod_netconf.spec.in b/src/mod_netconf.spec.in
index af04b73..88bc5cf 100644
--- a/src/mod_netconf.spec.in
+++ b/src/mod_netconf.spec.in
@@ -20,7 +20,7 @@
 %setup
 
 %build
-%configure --with-distro=@DISTRO@ @LIBNETCONF_WITH@;
+%configure --with-distro=@DISTRO@ @LIBNETCONF_WITH@ --with-notifications;
 make
 
 %install
@@ -29,7 +29,7 @@
 %post
 #add device module to configuration only when installing, not on update or reinstall.
 #https://fedoraproject.org/wiki/Packaging:Guidelines?rd=Packaging/Guidelines#Running_scriptlets_only_in_certain_situations
-[ -d /var/run/httpd ] || {mkdir -p /var/run/httpd && chown apache:apache /var/run/httpd}
+[ -d /var/run/httpd ] || { mkdir -p /var/run/httpd && chown apache:apache /var/run/httpd; }
 service httpd restart
 
 %postun
diff --git a/src/notification-server.c b/src/notification-server.c
index 382629b..0fdbba4 100644
--- a/src/notification-server.c
+++ b/src/notification-server.c
@@ -25,14 +25,23 @@
 #include <string.h>
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <sys/queue.h>
 #include <fcntl.h>
 #include <assert.h>
-#include "libwebsockets.h"
+#include <pthread.h>
+#include <libnetconf.h>
+#include <libwebsockets.h>
 #include "notification_module.h"
+#include "mod_netconf.h"
 
 #ifndef TEST_NOTIFICATION_SERVER
 #include <httpd.h>
 #include <http_log.h>
+#include <apr_hash.h>
+#include <apr_tables.h>
+
+#else
+static int force_exit = 0;
 #endif
 
 #if defined(TEST_NOTIFICATION_SERVER) || defined(WITH_NOTIFICATIONS)
@@ -42,10 +51,19 @@
 static struct pollfd *pollfds;
 static int *fd_lookup;
 static int count_pollfds;
-static int force_exit = 0;
 static struct libwebsocket_context *context = NULL;
 static server_rec *http_server = NULL;
 
+extern pthread_rwlock_t session_lock; /**< mutex protecting netconf_session_list from multiple access errors */
+
+struct ntf_thread_config {
+	struct nc_session *session;
+	char *session_hash;
+};
+
+static apr_hash_t *netconf_locked_sessions = NULL;
+static pthread_key_t thread_key;
+
 /*
  * This demo server shows how to use libwebsockets for one or more
  * websocket protocols in the same server
@@ -236,8 +254,7 @@
 		libwebsockets_get_peer_addresses(context, wsi, (int)(long)in, client_name,
 			     sizeof(client_name), client_ip, sizeof(client_ip));
 
-		fprintf(stderr, "Received network connect from %s (%s)\n",
-							client_name, client_ip);
+		//fprintf(stderr, "Received network connect from %s (%s)\n", client_name, client_ip);
 		/* if we returned non-zero from here, we kill the connection */
 		break;
 
@@ -283,53 +300,51 @@
 	return 0;
 }
 
-/*
+/**
  * this is just an example of parsing handshake headers, you don't need this
  * in your code unless you will filter allowing connections by the header
  * content
  */
-
-static void
-dump_handshake_info(struct libwebsocket *wsi)
-{
-	int n;
-	static const char *token_names[WSI_TOKEN_COUNT] = {
-		/*[WSI_TOKEN_GET_URI]		=*/ "GET URI",
-		/*[WSI_TOKEN_HOST]		=*/ "Host",
-		/*[WSI_TOKEN_CONNECTION]	=*/ "Connection",
-		/*[WSI_TOKEN_KEY1]		=*/ "key 1",
-		/*[WSI_TOKEN_KEY2]		=*/ "key 2",
-		/*[WSI_TOKEN_PROTOCOL]		=*/ "Protocol",
-		/*[WSI_TOKEN_UPGRADE]		=*/ "Upgrade",
-		/*[WSI_TOKEN_ORIGIN]		=*/ "Origin",
-		/*[WSI_TOKEN_DRAFT]		=*/ "Draft",
-		/*[WSI_TOKEN_CHALLENGE]		=*/ "Challenge",
-
-		/* new for 04 */
-		/*[WSI_TOKEN_KEY]		=*/ "Key",
-		/*[WSI_TOKEN_VERSION]		=*/ "Version",
-		/*[WSI_TOKEN_SWORIGIN]		=*/ "Sworigin",
-
-		/* new for 05 */
-		/*[WSI_TOKEN_EXTENSIONS]	=*/ "Extensions",
-
-		/* client receives these */
-		/*[WSI_TOKEN_ACCEPT]		=*/ "Accept",
-		/*[WSI_TOKEN_NONCE]		=*/ "Nonce",
-		/*[WSI_TOKEN_HTTP]		=*/ "Http",
-		/*[WSI_TOKEN_MUXURL]	=*/ "MuxURL",
-	};
-	char buf[256];
-
-	for (n = 0; n < WSI_TOKEN_COUNT; n++) {
-		if (!lws_hdr_total_length(wsi, n))
-			continue;
-
-		lws_hdr_copy(wsi, buf, sizeof buf, n);
-
-		fprintf(stderr, "    %s = %s\n", token_names[n], buf);
-	}
-}
+//static void dump_handshake_info(struct libwebsocket *wsi)
+//{
+//	int n;
+//	static const char *token_names[WSI_TOKEN_COUNT] = {
+//		/*[WSI_TOKEN_GET_URI]		=*/ "GET URI",
+//		/*[WSI_TOKEN_HOST]		=*/ "Host",
+//		/*[WSI_TOKEN_CONNECTION]	=*/ "Connection",
+//		/*[WSI_TOKEN_KEY1]		=*/ "key 1",
+//		/*[WSI_TOKEN_KEY2]		=*/ "key 2",
+//		/*[WSI_TOKEN_PROTOCOL]		=*/ "Protocol",
+//		/*[WSI_TOKEN_UPGRADE]		=*/ "Upgrade",
+//		/*[WSI_TOKEN_ORIGIN]		=*/ "Origin",
+//		/*[WSI_TOKEN_DRAFT]		=*/ "Draft",
+//		/*[WSI_TOKEN_CHALLENGE]		=*/ "Challenge",
+//
+//		/* new for 04 */
+//		/*[WSI_TOKEN_KEY]		=*/ "Key",
+//		/*[WSI_TOKEN_VERSION]		=*/ "Version",
+//		/*[WSI_TOKEN_SWORIGIN]		=*/ "Sworigin",
+//
+//		/* new for 05 */
+//		/*[WSI_TOKEN_EXTENSIONS]	=*/ "Extensions",
+//
+//		/* client receives these */
+//		/*[WSI_TOKEN_ACCEPT]		=*/ "Accept",
+//		/*[WSI_TOKEN_NONCE]		=*/ "Nonce",
+//		/*[WSI_TOKEN_HTTP]		=*/ "Http",
+//		/*[WSI_TOKEN_MUXURL]	=*/ "MuxURL",
+//	};
+//	char buf[256];
+//
+//	for (n = 0; n < WSI_TOKEN_COUNT; n++) {
+//		if (!lws_hdr_total_length(wsi, n))
+//			continue;
+//
+//		//lws_hdr_copy(wsi, buf, sizeof buf, n);
+//
+//		//fprintf(stderr, "    %s = %s\n", token_names[n], buf);
+//	}
+//}
 
 /* dumb_increment protocol */
 
@@ -341,102 +356,320 @@
  * connection.
  */
 
-struct per_session_data__dumb_increment {
+struct per_session_data__notif_client {
 	int number;
+	char *session_key;
+	struct nc_session *session;
 };
 
-//static void get_client_notification()
-//{
-//	/* get non-exclusive (read) access to sessions_list (conns) */
-//	if (pthread_rwlock_rdlock (&session_lock) != 0) {
-//		ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "Error while locking rwlock: %d (%s)", errno, strerror(errno));
-//		return NULL;
-//	}
-//	/* get session where send the RPC */
-//	locked_session = (struct session_with_mutex *)apr_hash_get(conns, session_key, APR_HASH_KEY_STRING);
-//	if (locked_session != NULL) {
-//		session = locked_session->session;
-//	}
-//	if (session != NULL) {
-//		/* get exclusive access to session */
-//		if (pthread_mutex_lock(&locked_session->lock) != 0) {
-//			/* unlock before returning error */
-//			if (pthread_rwlock_unlock (&session_lock) != 0) {
-//				ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "Error while locking rwlock: %d (%s)", errno, strerror(errno));
-//				return NULL;
-//			}
-//			return NULL;
-//		}
-//		/* send the request and get the reply */
-//		msgt = nc_session_send_recv(session, rpc, &reply);
-//
-//		/* first release exclusive lock for this session */
-//		pthread_mutex_unlock(&locked_session->lock);
-//		/* end of critical section */
-//		if (pthread_rwlock_unlock (&session_lock) != 0) {
-//			ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
-//			return (NULL);
-//		}
-//
-//		/* process the result of the operation */
-//		switch (msgt) {
-//		case NC_MSG_UNKNOWN:
-//			if (nc_session_get_status(session) != NC_SESSION_STATUS_WORKING) {
-//				ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "mod_netconf: receiving rpc-reply failed");
-//				netconf_close(server, conns, session_key);
-//				return (NULL);
-//			}
-//			/* no break */
-//		case NC_MSG_NONE:
-//			/* there is error handled by callback */
-//			return (NULL);
-//			break;
-//		case NC_MSG_REPLY:
-//			switch (replyt = nc_reply_get_type(reply)) {
-//			case NC_REPLY_DATA:
-//				if ((data = nc_reply_get_data (reply)) == NULL) {
-//					ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "mod_netconf: no data from reply");
-//					data = NULL;
-//				}
-//				break;
-//			default:
-//				ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "mod_netconf: unexpected rpc-reply (%d)", replyt);
-//				data = NULL;
-//				break;
-//			}
-//			break;
-//		default:
-//			ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "mod_netconf: unexpected reply message received (%d)", msgt);
-//			data = NULL;
-//			break;
-//		}
-//		nc_reply_free(reply);
-//		return (data);
-//	} else {
-//		/* release lock on failure */
-//		if (pthread_rwlock_unlock (&session_lock) != 0) {
-//			ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
-//		}
-//		ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "Unknown session to process.");
-//		return (NULL);
-//	}
-//}
+struct session_with_mutex *get_ncsession_from_key(const char *session_key)
+{
+	struct session_with_mutex *locked_session = NULL;
+	if (session_key == NULL) {
+		return (NULL);
+	}
+	if (pthread_rwlock_wrlock(&session_lock) != 0) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "Error while locking rwlock: %d (%s)", errno, strerror(errno));
+		#endif
+		return (NULL);
+	}
+	locked_session = (struct session_with_mutex *)apr_hash_get(netconf_locked_sessions, session_key, APR_HASH_KEY_STRING);
+	if (pthread_rwlock_unlock (&session_lock) != 0) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		ap_log_error (APLOG_MARK, APLOG_ERR, 0, http_server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+		#endif
+		return (NULL);
+	}
+	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)
+{
+	nc_reply *reply = NULL;
+	char *data = NULL;
+	int ret = EXIT_SUCCESS;
+
+	/* send the request and get the reply */
+	switch (nc_session_send_recv(session, rpc, &reply)) {
+	case NC_MSG_UNKNOWN:
+		if (nc_session_get_status(session) != NC_SESSION_STATUS_WORKING) {
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: receiving rpc-reply failed.");
+			}
+			#endif
+			//cmd_disconnect(NULL);
+			ret = EXIT_FAILURE;
+			break;
+		}
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: Unknown error occurred.");
+		}
+		#endif
+		ret = EXIT_FAILURE;
+		break;
+	case NC_MSG_NONE:
+		/* error occurred, but processed by callback */
+		break;
+	case NC_MSG_REPLY:
+		switch (nc_reply_get_type(reply)) {
+		case NC_REPLY_OK:
+			break;
+		case NC_REPLY_DATA:
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notifications: recv: %s.", data = nc_reply_get_data (reply));
+				free(data);
+			}
+			#endif
+			break;
+		case NC_REPLY_ERROR:
+			/* wtf, you shouldn't be here !?!? */
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: operation failed, but rpc-error was not processed.");
+			}
+			#endif
+			ret = EXIT_FAILURE;
+			break;
+		default:
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: unexpected operation result.");
+			}
+			#endif
+			ret = EXIT_FAILURE;
+			break;
+		}
+		break;
+	default:
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: Unknown error occurred.");
+		}
+		#endif
+		ret = EXIT_FAILURE;
+		break;
+	}
+	nc_rpc_free(rpc);
+	nc_reply_free(reply);
+
+	return (ret);
+}
+
+/**
+ * \brief Callback to store incoming notification
+ * \param [in] eventtime - time when notification occured
+ * \param [in] content - content of notification
+ */
+static void notification_fileprint (time_t eventtime, const char* content)
+{
+	char t[128];
+	struct session_with_mutex *target_session = NULL;
+	notification_t *ntf = NULL;
+	char *session_hash = NULL;
+
+	t[0] = 0;
+	strftime(t, sizeof(t), "%c", localtime(&eventtime));
+
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "notification: eventTime: %s\n%s\n", t, content);
+	}
+	
+	/* \todo replace last_session_key with client identification */
+	session_hash = pthread_getspecific(thread_key);
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: fileprint getspecific (%s)", session_hash);
+	}
+	target_session = get_ncsession_from_key(session_hash);
+	if (target_session == NULL) {
+		ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "no session found last_session_key (%s)", session_hash);
+		return;
+	}
+	if (pthread_mutex_lock(&target_session->lock) != 0) {
+		ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "Error while locking rwlock: %d (%s)", errno, strerror(errno));
+		return;
+	}
+	if (target_session->notifications == NULL) {
+		ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "target_session->notifications is NULL");
+		if (pthread_mutex_unlock(&target_session->lock) != 0) {
+			ap_log_error (APLOG_MARK, APLOG_ERR, 0, http_server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+			return;
+		}
+		return;
+	}
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: ready to push to notifications queue");
+	}
+	ntf = (notification_t *) apr_array_push(target_session->notifications);
+	if (ntf == NULL) {
+		ap_log_error (APLOG_MARK, APLOG_ERR, 0, http_server, "Failed to allocate element ");
+		if (pthread_mutex_unlock(&target_session->lock) != 0) {
+			ap_log_error (APLOG_MARK, APLOG_ERR, 0, http_server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+			return;
+		}
+		return;
+	}
+	ntf->eventtime = time(NULL);
+	//ntf->content = strdup("notifikace");
+	//ntf->eventtime = eventtime;
+	ntf->content = strdup(content);
+
+	if (http_server != NULL) {
+		ap_log_error (APLOG_MARK, APLOG_NOTICE, 0, http_server, "added notif to queue %u (%s)", (unsigned int) ntf->eventtime, "notifikace");
+	}
+
+	if (pthread_mutex_unlock(&target_session->lock) != 0) {
+		ap_log_error (APLOG_MARK, APLOG_ERR, 0, http_server, "Error while unlocking rwlock: %d (%s)", errno, strerror(errno));
+		return;
+	}
+}
+
+/**
+ * \brief Thread for libnetconf notifications dispatch
+ * \param [in] arg - struct ntf_thread_config * with nc_session
+ */
+void* notification_thread(void* arg)
+{
+	struct ntf_thread_config *config = (struct ntf_thread_config*)arg;
+	#ifndef TEST_NOTIFICATION_SERVER
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "notifications: in thread for libnetconf notifications");
+	}
+	#endif
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notifications: pthread_key_create");
+	}
+	if (pthread_key_create(&thread_key, NULL) != 0) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: pthread_key_create failed");
+		}
+		#endif
+	}
+	pthread_setspecific(thread_key, config->session_hash);
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notifications: dispatching");
+	}
+	ncntf_dispatch_receive(config->session, notification_fileprint);
+	#ifndef TEST_NOTIFICATION_SERVER
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "notifications: ended thread for libnetconf notifications");
+	}
+	#endif
+	free(config);
+	return (NULL);
+}
+
+
+int notif_subscribe(struct session_with_mutex *locked_session, const char *session_hash, time_t start_time, time_t stop_time)
+{
+	time_t start = -1;
+	time_t stop = -1;
+	struct nc_filter *filter = NULL;
+	char *stream = NULL;
+	nc_rpc *rpc = NULL;
+	pthread_t thread;
+	struct ntf_thread_config *tconfig;
+	struct nc_session *session;
+
+	if (locked_session == NULL) {
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: no locked_session was given.");
+		}
+		return (EXIT_FAILURE);
+	}
+
+	session = locked_session->session;
+
+	start = time(NULL) + start_time;
+	stop = time(NULL) + stop_time;
+	if (http_server != NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: history: %u %u", (unsigned int) start, (unsigned int) stop);
+	}
+
+	if (session == NULL) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: NETCONF session not established.");
+		}
+		#endif
+		return (EXIT_FAILURE);
+	}
+
+	/* check if notifications are allowed on this session */
+	if (nc_session_notif_allowed(session) == 0) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: Notification subscription is not allowed on this session.");
+		}
+		#endif
+		return (EXIT_FAILURE);
+	}
+	/* check times */
+	if (start != -1 && stop != -1 && start > stop) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: Subscription start time must be lower than the end time.");
+		}
+		#endif
+		return (EXIT_FAILURE);
+	}
+
+	/* create requests */
+	rpc = nc_rpc_subscribe(stream, filter, (start_time == 0)?NULL:&start, (stop_time == 0)?NULL:&stop);
+	nc_filter_free(filter);
+	if (rpc == NULL) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: creating an rpc request failed.");
+		}
+		#endif
+		return (EXIT_FAILURE);
+	}
+
+	if (send_recv_process(session, "subscribe", rpc) != 0) {
+		return (EXIT_FAILURE);
+	}
+	rpc = NULL; /* just note that rpc is already freed by send_recv_process() */
+
+	tconfig = malloc(sizeof(struct ntf_thread_config));
+	tconfig->session = session;
+	tconfig->session_hash = strdup(session_hash);
+	if (http_server != NULL) {
+		ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: creating libnetconf notification thread (%s).",
+		tconfig->session_hash);
+	}
+	if (pthread_create(&thread, NULL, notification_thread, tconfig) != 0) {
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notifications: creating a thread for receiving notifications failed");
+		}
+		#endif
+		return (EXIT_FAILURE);
+	}
+	pthread_detach(thread);
+	return (EXIT_SUCCESS);
+}
 
 static int callback_notification(struct libwebsocket_context *context,
 			struct libwebsocket *wsi,
 			enum libwebsocket_callback_reasons reason,
-					       void *user, void *in, size_t len)
+			void *user, void *in, size_t len)
 {
-	int isnotif = 0;
-	int n, m;
-	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 512 + LWS_SEND_BUFFER_POST_PADDING];
+	int n = 0;
+	int m = 0;
+	unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 4096 + LWS_SEND_BUFFER_POST_PADDING];
 	unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
-	struct per_session_data__dumb_increment *pss = (struct per_session_data__dumb_increment *)user;
-	#ifndef TEST_NOTIFICATION_SERVER
-	if (http_server != NULL) {
-		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "libwebsockets callback_notification");
-	}
-	#endif
+	struct per_session_data__notif_client *pss = (struct per_session_data__notif_client *)user;
+
+	//#ifndef TEST_NOTIFICATION_SERVER
+	//if (http_server != NULL) {
+	//	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "libwebsockets callback_notification");
+	//}
+	//#endif
 
 	switch (reason) {
 
@@ -447,8 +680,70 @@
 
 	case LWS_CALLBACK_SERVER_WRITEABLE:
 //		get_client_notification();
-		n = sprintf((char *)p, "not%d\n", pss->number++);
-		m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
+		if (pss->session_key == NULL) {
+			return 0;
+		}
+		/*
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: prepare to SENDING");
+		}
+		*/
+
+		struct session_with_mutex *ls = get_ncsession_from_key(pss->session_key);
+		if (ls == NULL) {
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notification: session not found");
+			}
+			return -1;
+		}
+		if (pthread_mutex_lock(&ls->lock) != 0) {
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notification: cannot lock session");
+			}
+			#endif
+		}
+		notification_t *notif = NULL;
+		if (ls->notifications == NULL) {
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notification: no notifications array");
+			}
+			#endif
+			pthread_mutex_unlock(&ls->lock);
+			return -1;
+		}
+
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: POP notifications for session");
+		}
+
+		while ((notif = (notification_t *) apr_array_pop(ls->notifications)) != NULL) {
+			char t[128];
+			t[0] = 0;
+			strftime(t, sizeof(t), "%c", localtime(&notif->eventtime));
+			n = 0;
+			n = sprintf((char *)p, "%s\n", notif->content);
+			m = libwebsocket_write(wsi, p, n, LWS_WRITE_TEXT);
+			//free(notif->content);
+			//free(notif);
+		}
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: POP notifications done");
+		}
+
+		if (pthread_mutex_unlock(&ls->lock) != 0) {
+			#ifndef TEST_NOTIFICATION_SERVER
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_ERR, 0, http_server, "notification: cannot unlock session");
+			}
+			#endif
+		}
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: unlocked session lock");
+		}
+
+
 		if (m < n) {
 			lwsl_err("ERROR %d writing to di socket\n", n);
 			return -1;
@@ -461,6 +756,37 @@
 
 	case LWS_CALLBACK_RECEIVE:
 //		fprintf(stderr, "rx %d\n", (int)len);
+		#ifndef TEST_NOTIFICATION_SERVER
+		if (http_server != NULL) {
+			ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "received: (%s)", (char *)in);
+		}
+		#endif
+		if (pss->session_key == NULL) {
+			char session_key_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);
+			sscanf(in+40, "%d %d", (int *) &start, (int *) &stop);
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "notification: get key (%s) from (%s) (%i,%i)", pss->session_key, (char *) in, (int) start, (int) stop);
+			}
+			
+			/* TODO subscribe, map with ncnotif print callback */
+			struct session_with_mutex *ls = get_ncsession_from_key(pss->session_key);
+			if (ls == NULL) {
+				if (http_server != NULL) {
+					ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, http_server, "notification: session_key not found (%s)", pss->session_key);
+				}
+				return 0;
+			}
+			if (http_server != NULL) {
+				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, http_server, "notification: prepare to subscribe stream");
+			}
+			notif_subscribe(ls, pss->session_key, (time_t) start, (time_t) stop);
+		}
 		if (len < 6)
 			break;
 		if (strcmp((const char *)in, "reset\n") == 0)
@@ -498,24 +824,29 @@
 	{
 		"notification-protocol",
 		callback_notification,
-		sizeof(struct per_session_data__dumb_increment),
-		10,
+		sizeof(struct per_session_data__notif_client),
+		80,
 	},
 	{ NULL, NULL, 0, 0 } /* terminator */
 };
 
 
-int notification_init(apr_pool_t * pool, server_rec * server)
+/**
+ * initialization of notification module
+ */
+int notification_init(apr_pool_t * pool, server_rec * server, apr_hash_t *conns)
 {
-	char cert_path[1024];
-	char key_path[1024];
-	int use_ssl = 0;
+	//char cert_path[1024];
+	//char key_path[1024];
+	//int use_ssl = 0;
 	struct lws_context_creation_info info;
 	int opts = 0;
-	char interface_name[128] = "";
+	//char interface_name[128] = "";
 	const char *iface = NULL;
 	int debug_level = 7;
 
+	netconf_locked_sessions = conns;
+
 	memset(&info, 0, sizeof info);
 	info.port = NOTIFICATION_SERVER_PORT;
 
@@ -558,6 +889,7 @@
 		lwsl_err("libwebsocket init failed\n");
 		return -1;
 	}
+	return 0;
 }
 
 void notification_close()
@@ -567,6 +899,7 @@
 	lwsl_notice("libwebsockets-test-server exited cleanly\n");
 }
 
+
 /**
  * \brief send notification if any
  * \return < 0 on error
@@ -625,106 +958,6 @@
 #ifdef TEST_NOTIFICATION_SERVER
 int main(int argc, char **argv)
 {
-//	char cert_path[1024];
-//	char key_path[1024];
-//	int n = 0;
-//	int use_ssl = 0;
-//	struct libwebsocket_context *context;
-//	int opts = 0;
-//	char interface_name[128] = "";
-//	const char *iface = NULL;
-//	unsigned int oldus = 0;
-//	unsigned int olds = 0;
-//	struct lws_context_creation_info info;
-//
-//	int debug_level = 7;
-//
-//	memset(&info, 0, sizeof info);
-//	info.port = 8081;
-//
-//	/* tell the library what debug level to emit and to send it to syslog */
-//	lws_set_log_level(debug_level, lwsl_emit_syslog);
-//
-//	lwsl_notice("libwebsockets test server - "
-//			"(C) Copyright 2010-2013 Andy Green <andy@warmcat.com> - "
-//						    "licensed under LGPL2.1\n");
-//	max_poll_elements = getdtablesize();
-//	pollfds = malloc(max_poll_elements * sizeof (struct pollfd));
-//	fd_lookup = malloc(max_poll_elements * sizeof (int));
-//	if (pollfds == NULL || fd_lookup == NULL) {
-//		lwsl_err("Out of memory pollfds=%d\n", max_poll_elements);
-//		return -1;
-//	}
-//
-//	info.iface = iface;
-//	info.protocols = protocols;
-//
-//	//snprintf(cert_path, sizeof(cert_path), "%s/libwebsockets-test-server.pem", resource_path);
-//	//snprintf(key_path, sizeof(cert_path), "%s/libwebsockets-test-server.key.pem", resource_path);
-//
-//	//info.ssl_cert_filepath = cert_path;
-//	//info.ssl_private_key_filepath = key_path;
-//	//
-//	info.gid = -1;
-//	info.uid = -1;
-//	info.options = opts;
-//
-//	/* create server */
-//	context = libwebsocket_create_context(&info);
-//	if (context == NULL) {
-//		lwsl_err("libwebsocket init failed\n");
-//		return -1;
-//	}
-//
-//	n = 0;
-//	while (n >= 0 && !force_exit) {
-//		struct timeval tv;
-//
-//		gettimeofday(&tv, NULL);
-//
-//		/*
-//		 * This provokes the LWS_CALLBACK_SERVER_WRITEABLE for every
-//		 * live websocket connection using the DUMB_INCREMENT protocol,
-//		 * as soon as it can take more packets (usually immediately)
-//		 */
-//
-//		if (((unsigned int)tv.tv_sec - olds) > 0) {
-//			libwebsocket_callback_on_writable_all_protocol(&protocols[PROTOCOL_NOTIFICATION]);
-//			olds = tv.tv_sec;
-//		}
-//
-//
-//		/*
-//		 * this represents an existing server's single poll action
-//		 * which also includes libwebsocket sockets
-//		 */
-//
-//		n = poll(pollfds, count_pollfds, 50);
-//		if (n < 0)
-//			continue;
-//
-//
-//		if (n) {
-//			for (n = 0; n < count_pollfds; n++) {
-//				if (pollfds[n].revents) {
-//					/*
-//					* returns immediately if the fd does not
-//					* match anything under libwebsockets
-//					* control
-//					*/
-//					if (libwebsocket_service_fd(context, &pollfds[n]) < 0) {
-//						break;
-//					}
-//				}
-//			}
-//		}
-//	}
-//
-//	libwebsocket_context_destroy(context);
-//
-//	lwsl_notice("libwebsockets-test-server exited cleanly\n");
-//
-//	return 0;
 	if (notification_init(NULL, NULL) == -1) {
 		fprintf(stderr, "Error during initialization\n");
 		return 1;
diff --git a/src/notification_module.h b/src/notification_module.h
index 8166af3..8861e12 100644
--- a/src/notification_module.h
+++ b/src/notification_module.h
@@ -42,11 +42,12 @@
  */
 #ifndef __NOTIFICATION_MODULE_H
 #define __NOTIFICATION_MODULE_H
-#include "libwebsockets.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;
 typedef struct s {} server_rec;
@@ -54,10 +55,24 @@
 
 #define NOTIFICATION_SERVER_PORT	8080
 
-int notification_init(apr_pool_t * pool, server_rec * server);
+/**
+ * \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, apr_hash_t *conns);
 
+/**
+ * \brief Handle method - passes execution into the libwebsocket library
+ * \return 0 on success
+ */
 int notification_handle();
 
+/**
+ * \brief Notification module finalization
+ */
 void notification_close();
 
 #endif