From 2757011e1b4ddbc7c1f0ae137ecc8f4e07121d5a Mon Sep 17 00:00:00 2001
From: Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
Date: Sun, 12 Mar 2017 17:13:37 -0300
Subject: [PATCH] several smaller fixes and documentation updates

---
 include/villas/fpga/card.h          |  4 ++-
 include/villas/fpga/ip.h            |  4 ++-
 include/villas/fpga/ips/dft.h       |  4 ++-
 include/villas/fpga/ips/dma.h       |  4 ++-
 include/villas/fpga/ips/fifo.h      |  4 ++-
 include/villas/fpga/ips/intc.h      |  4 ++-
 include/villas/fpga/ips/model.h     |  4 ++-
 include/villas/fpga/ips/rtds_axis.h |  4 ++-
 include/villas/fpga/ips/switch.h    |  4 ++-
 include/villas/fpga/ips/timer.h     |  4 ++-
 include/villas/fpga/vlnv.h          |  4 ++-
 include/villas/hook.h               |  5 ++--
 include/villas/node.h               | 32 +++++++++++-----------
 include/villas/nodes/ngsi.h         |  2 +-
 include/villas/pool.h               | 19 ++++++++++---
 include/villas/queue.h              | 11 ++++++++
 include/villas/webmsg_format.h      | 15 +++++------
 lib/fpga/card.c                     |  3 +--
 lib/hook.c                          | 41 ++++++++++++++++++++---------
 lib/hooks/convert.c                 |  4 +--
 lib/node.c                          |  7 ++++-
 lib/node_type.c                     |  2 +-
 lib/nodes/socket.c                  | 10 ++++---
 lib/nodes/websocket.c               |  8 +++---
 lib/sample.c                        |  4 ++-
 lib/web.c                           | 28 +++++++++++---------
 26 files changed, 156 insertions(+), 79 deletions(-)

diff --git a/include/villas/fpga/card.h b/include/villas/fpga/card.h
index 54e55e0da..3937aae48 100644
--- a/include/villas/fpga/card.h
+++ b/include/villas/fpga/card.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
  *********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ip.h b/include/villas/fpga/ip.h
index 5b7593136..90f434331 100644
--- a/include/villas/fpga/ip.h
+++ b/include/villas/fpga/ip.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
  *********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/dft.h b/include/villas/fpga/ips/dft.h
index f8ac4910d..ca7d16b0f 100644
--- a/include/villas/fpga/ips/dft.h
+++ b/include/villas/fpga/ips/dft.h
@@ -5,7 +5,9 @@
  * @copyright 2017, Steffen Vogel
 **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/dma.h b/include/villas/fpga/ips/dma.h
index d42d4d885..db05a9595 100644
--- a/include/villas/fpga/ips/dma.h
+++ b/include/villas/fpga/ips/dma.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
  
diff --git a/include/villas/fpga/ips/fifo.h b/include/villas/fpga/ips/fifo.h
index c7af8eb49..d685fd663 100644
--- a/include/villas/fpga/ips/fifo.h
+++ b/include/villas/fpga/ips/fifo.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/intc.h b/include/villas/fpga/ips/intc.h
index 4af79a068..b4898730b 100644
--- a/include/villas/fpga/ips/intc.h
+++ b/include/villas/fpga/ips/intc.h
@@ -4,7 +4,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/model.h b/include/villas/fpga/ips/model.h
index 60725589f..aa191ea00 100644
--- a/include/villas/fpga/ips/model.h
+++ b/include/villas/fpga/ips/model.h
@@ -5,7 +5,9 @@
  * @copyright 2017, Steffen Vogel
  *********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/rtds_axis.h b/include/villas/fpga/ips/rtds_axis.h
index b81759e26..f48fd8390 100644
--- a/include/villas/fpga/ips/rtds_axis.h
+++ b/include/villas/fpga/ips/rtds_axis.h
@@ -5,7 +5,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/switch.h b/include/villas/fpga/ips/switch.h
index 0d09cb7a2..1172ab9cb 100644
--- a/include/villas/fpga/ips/switch.h
+++ b/include/villas/fpga/ips/switch.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/ips/timer.h b/include/villas/fpga/ips/timer.h
index cf5e3779e..f1ae91ecb 100644
--- a/include/villas/fpga/ips/timer.h
+++ b/include/villas/fpga/ips/timer.h
@@ -7,7 +7,9 @@
  * @copyright 2017, Steffen Vogel
  **********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASfpga
+ * @{
+ */
 
 #pragma once
 
diff --git a/include/villas/fpga/vlnv.h b/include/villas/fpga/vlnv.h
index fa77555d7..19bce9485 100644
--- a/include/villas/fpga/vlnv.h
+++ b/include/villas/fpga/vlnv.h
@@ -5,7 +5,9 @@
  * @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
  *********************************************************************************/
 
-/** @addtogroup fpga VILLASfpga @{ */
+/** @addtogroup fpga VILLASILLASfpga
+ * @{
+ */
 
 #ifndef _FPGA_VLNV_H_
 #define _FPGA_VLNV_H_
diff --git a/include/villas/hook.h b/include/villas/hook.h
index cac1d91f0..81d0ca153 100644
--- a/include/villas/hook.h
+++ b/include/villas/hook.h
@@ -148,11 +148,12 @@ void * hook_storage(struct hook *h, int when, size_t len, ctor_cb_t ctor, dtor_c
  */
 int hook_parse_list(struct list *list, config_setting_t *cfg);
 
-/** Parse a single hook and append it to the list.
+/** Parse a single hook.
+ *
  * A hook definition is composed of the hook name and optional parameters
  * seperated by a colon.
  *
  * Examples:
  *   "print:stdout"
  */
-int hook_parse(config_setting_t *cfg, struct list *list);
+int hook_parse(struct hook *h, config_setting_t *cfg);
\ No newline at end of file
diff --git a/include/villas/node.h b/include/villas/node.h
index e14ad3cd9..e2bdafe33 100644
--- a/include/villas/node.h
+++ b/include/villas/node.h
@@ -45,11 +45,19 @@ struct node
 	config_setting_t *cfg;	/**< A pointer to the libconfig object which instantiated this node */
 };
 
-/** Destroy node by freeing dynamically allocated memory.
+int node_init(struct node *n, struct node_type *vt);
+
+/** Parse a single node and add it to the global configuration.
  *
- * @see node_type::destroy
+ * @param cfg A libconfig object pointing to the node.
+ * @param nodes Add new nodes to this linked list.
+ * @retval 0 Success. Everything went well.
+ * @retval <0 Error. Something went wrong.
  */
-int node_destroy(struct node *n);
+int node_parse(struct node *n, config_setting_t *cfg);
+
+/** Validate node configuration. */
+int node_check(struct node *n);
 
 /** Start operation of a node.
  *
@@ -63,6 +71,12 @@ int node_start(struct node *n);
  */
 int node_stop(struct node *n);
 
+/** Destroy node by freeing dynamically allocated memory.
+ *
+ * @see node_type::destroy
+ */
+int node_destroy(struct node *n);
+
 /** Return a pointer to a string which should be used to print this node.
  *
  * @see node::_name‚
@@ -103,16 +117,4 @@ int node_write(struct node *n, struct sample *smps[], unsigned cnt);
  */
 int node_parse_list(struct list *list, config_setting_t *cfg, struct list *all);
 
-/** Parse a single node and add it to the global configuration.
- *
- * @param cfg A libconfig object pointing to the node.
- * @param nodes Add new nodes to this linked list.
- * @retval 0 Success. Everything went well.
- * @retval <0 Error. Something went wrong.
- */
-int node_parse(struct node *n, config_setting_t *cfg);
-
-/** Validate node configuration. */
-int node_check(struct node *n);
-
 /** @} */
\ No newline at end of file
diff --git a/include/villas/nodes/ngsi.h b/include/villas/nodes/ngsi.h
index d518e0025..45c6be49d 100644
--- a/include/villas/nodes/ngsi.h
+++ b/include/villas/nodes/ngsi.h
@@ -25,7 +25,7 @@
 #include "list.h"
 #include "config.h"
 #include "msg.h"
-#include "cfg.h"
+#include "super_node.h"
 #include "node.h"
 
 struct node;
diff --git a/include/villas/pool.h b/include/villas/pool.h
index 9112bdf30..f8fef235f 100644
--- a/include/villas/pool.h
+++ b/include/villas/pool.h
@@ -33,19 +33,32 @@ struct pool {
 
 #define INLINE static inline __attribute__((unused)) 
 
-/** Initiazlize a pool */
+/** Initiazlize a pool
+ *
+ * @param[inout] p The pool data structure.
+ * @param[in] cnt The total number of blocks which are reserverd by this pool.
+ * @param[in] blocksz The size in bytes per block.
+ * @param[in] mem The type of memory which should be used for this pool.
+ * @retval 0 The pool has been successfully initialized.
+ * @retval <>0 There was an error during the pool initialization.
+ */
 int pool_init(struct pool *p, size_t cnt, size_t blocksz, const struct memtype *mem);
 
 /** Destroy and release memory used by pool. */
 int pool_destroy(struct pool *p);
 
-/** Pop cnt values from the stack an place them in the array blocks */
+/** Pop up to \p cnt values from the stack an place them in the array \p blocks.
+ *
+ * @return The number of blocks actually retrieved from the pool.
+ *         This number can be smaller than the requested \p cnt blocks
+ *         in case the pool currently holds less than \p cnt blocks.
+ */
 INLINE ssize_t pool_get_many(struct pool *p, void *blocks[], size_t cnt)
 {
 	return queue_pull_many(&p->queue, blocks, cnt);
 }
 
-/** Push cnt values which are giving by the array values to the stack. */
+/** Push \p cnt values which are giving by the array values to the stack. */
 INLINE ssize_t pool_put_many(struct pool *p, void *blocks[], size_t cnt)
 {
 	return queue_push_many(&p->queue, blocks, cnt);
diff --git a/include/villas/queue.h b/include/villas/queue.h
index 07d94c7e2..b68f72c76 100644
--- a/include/villas/queue.h
+++ b/include/villas/queue.h
@@ -86,6 +86,17 @@ int queue_push(struct queue *q, void *ptr);
 
 int queue_pull(struct queue *q, void **ptr);
 
+/** Enqueue up to \p cnt pointers of the \p ptr array into the queue.
+ *
+ * @return The number of pointers actually enqueued.
+ *         This number can be smaller then \p cnt in case the queue is filled.
+ */
 int queue_push_many(struct queue *q, void *ptr[], size_t cnt);
 
+/** Dequeue up to \p cnt pointers from the queue and place them into the \p ptr array.
+ *
+ * @return The number of pointers actually dequeued.
+ *         This number can be smaller than \p cnt in case the queue contained less than
+ *         \p cnt elements.
+ */
 int queue_pull_many(struct queue *q, void *ptr[], size_t cnt);
\ No newline at end of file
diff --git a/include/villas/webmsg_format.h b/include/villas/webmsg_format.h
index c6b0e0d4d..19b600de6 100644
--- a/include/villas/webmsg_format.h
+++ b/include/villas/webmsg_format.h
@@ -7,11 +7,12 @@
  *   Unauthorized copying of this file, via any medium is strictly prohibited. 
  *********************************************************************************/
 
-#ifndef _WEBMSG_FORMAT_H_
-#define _WEBMSG_FORMAT_H_
+#pragma once
 
 #include <stdint.h>
 
+#include "msg_format.h"
+
 #ifdef __linux__
   #define _BSD_SOURCE		1
   #include <endian.h>
@@ -39,16 +40,16 @@
 #endif
 
 /** The total size in bytes of a message */
-#define WEBMSG_LEN(values)	(sizeof(struct msg) + MSG_DATA_LEN(values))
+#define WEBMSG_LEN(values)	(sizeof(struct webmsg) + MSG_DATA_LEN(values))
 
 /** The length of \p values values in bytes. */
 #define WEBMSG_DATA_LEN(values)	(sizeof(float) * (values))
 
 /** The offset to the first data value in a message. */
-#define WEBMSG_DATA_OFFSET(msg)	((char *) (msg) + offsetof(struct msg, data))
+#define WEBMSG_DATA_OFFSET(msg)	((char *) (msg) + offsetof(struct webmsg, data))
 
 /** Initialize a message with default values */
-#define WEBMSG_INIT(len, seq) (struct msg) {\
+#define WEBMSG_INIT(len, seq) (struct webmsg) {\
 	.version  = WEBMSG_VERSION,	\
 	.type     = WEBMSG_TYPE_DATA,	\
 	.endian   = WEBMSG_ENDIAN_HOST,	\
@@ -97,6 +98,4 @@ struct webmsg
 		float    f;	/**< Floating point values (note msg::endian) */
 		uint32_t i;	/**< Integer values (note msg::endian) */
 	} data[];
-} __attribute__((packed));
-
-#endif /* _WEBMSG_FORMAT_H_ */
+} __attribute__((packed));
\ No newline at end of file
diff --git a/lib/fpga/card.c b/lib/fpga/card.c
index 39b28bbae..bdfbdcccb 100644
--- a/lib/fpga/card.c
+++ b/lib/fpga/card.c
@@ -25,8 +25,7 @@ int fpga_card_init(struct fpga_card *c, struct pci *pci, struct vfio_container *
 
 	fpga_card_check(c);
 	
-	if (c->state == STATE_INITIALIZED)
-		return 0;
+	assert(c->state != STATE_DESTROYED);
 
 	/* Search for FPGA card */
 	pdev = pci_lookup_device(pci, &c->filter);
diff --git a/lib/hook.c b/lib/hook.c
index dfa9d9ffb..da0c03be0 100644
--- a/lib/hook.c
+++ b/lib/hook.c
@@ -113,14 +113,21 @@ void * hook_storage(struct hook *h, int when, size_t len, ctor_cb_t ctor, dtor_c
  */
 int hook_parse_list(struct list *list, config_setting_t *cfg)
 {
+	struct hook h;
+	
 	switch (config_setting_type(cfg)) {
 		case CONFIG_TYPE_STRING:
-			hook_parse(cfg, list);
+			hook_parse(&h, cfg);
+			list_push(list, memdup(&h, sizeof(h)));
 			break;
 
 		case CONFIG_TYPE_ARRAY:
-			for (int i = 0; i < config_setting_length(cfg); i++)
-				hook_parse(config_setting_get_elem(cfg, i), list);
+			for (int i = 0; i < config_setting_length(cfg); i++) {
+				config_setting_t *cfg_hook = config_setting_get_elem(cfg, i);
+				
+				hook_parse(&h, cfg_hook);
+				list_push(list, memdup(&h, sizeof(h)));
+			}
 			break;
 
 		default:
@@ -130,27 +137,35 @@ int hook_parse_list(struct list *list, config_setting_t *cfg)
 	return list_length(list);
 }
 
-int hook_parse(config_setting_t *cfg, struct list *list)
+int hook_parse(struct hook *h, config_setting_t *cfg)
 {
-	struct hook *hook;
-	struct plugin *plg;
-
+	int ret;
+	const char *hookline;
 	char *name, *param;
-	const char *hookline = config_setting_get_string(cfg);
+	struct plugin *p;
+	
+	hookline = config_setting_get_string(cfg);
 	if (!hookline)
 		cerror(cfg, "Invalid hook function");
 	
 	name  = strtok((char *) hookline, ":");
 	param = strtok(NULL, "");
 
-	plg = plugin_lookup(PLUGIN_TYPE_HOOK, name);
-	if (!plg)
+	p = plugin_lookup(PLUGIN_TYPE_HOOK, name);
+	if (!p)
 		cerror(cfg, "Unknown hook function '%s'", name);
 	
-	hook = memdup(&plg->hook, sizeof(plg->hook));
-	hook->parameter = param;
+	if (p->hook.type & HOOK_AUTO)
+		cerror(cfg, "Hook '%s' is built-in and can not be added manually.", name);
+
+	hook_copy(&p->hook, h);
+
+	h->parameter = param;
 	
-	list_push(list, hook);
+	/* Parse hook arguments */
+	ret = h->cb(h, HOOK_PARSE, NULL);
+	if (ret)
+		cerror(cfg, "Failed to parse arguments for hook '%s'", name);
 
 	return 0;
 }
\ No newline at end of file
diff --git a/lib/hooks/convert.c b/lib/hooks/convert.c
index 4b4a4a645..ec272e7e3 100644
--- a/lib/hooks/convert.c
+++ b/lib/hooks/convert.c
@@ -35,7 +35,7 @@ static int hook_convert(struct hook *h, int when, struct hook_info *k)
 		
 		case HOOK_READ:
 			for (int i = 0; i < k->cnt; i++) {
-				for (int j = 0; j < k->smps[0]->length; j++) {
+				for (int j = 0; j < k->smps[i]->length; j++) {
 					switch (private->mode) {
 						case TO_FIXED: k->smps[i]->data[j].i = k->smps[i]->data[j].f * 1e3; break;
 						case TO_FLOAT: k->smps[i]->data[j].f = k->smps[i]->data[j].i; break;
@@ -57,7 +57,7 @@ static struct plugin p = {
 		.priority = 99,
 		.history = 0,
 		.cb	= hook_convert,
-		.type	= HOOK_STORAGE | HOOK_DESTROY | HOOK_READ
+		.type	= HOOK_STORAGE | HOOK_READ
 	}
 };
 
diff --git a/lib/node.c b/lib/node.c
index bd4fbe0be..407e39456 100644
--- a/lib/node.c
+++ b/lib/node.c
@@ -13,10 +13,15 @@
 #include "config.h"
 #include "plugin.h"
 
-int node_init(struct node *n)
+int node_init(struct node *n, struct node_type *vt)
 {
 	assert(n->state == STATE_DESTROYED);
+
+	n->_vt = vt;
+	n->_vd = alloc(vt->size);
 	
+	list_push(&vt->instances, n);
+
 	n->state = STATE_INITIALIZED;
 
 	return 0;
diff --git a/lib/node_type.c b/lib/node_type.c
index 83fd068af..92f074cec 100644
--- a/lib/node_type.c
+++ b/lib/node_type.c
@@ -20,7 +20,7 @@ int node_type_start(struct node_type *vt, int argc, char *argv[], config_setting
 	
 	assert(vt->state != STATE_STARTED);
 
-	info("Initializing " YEL("%s") " node type", plugin_name(vt));
+	info("Initializing " YEL("%s") " node type which is used by %zu nodes", plugin_name(vt), list_length(&vt->instances));
 	{ INDENT
 		ret = vt->init ? vt->init(argc, argv, cfg) : 0;
 	}	
diff --git a/lib/nodes/socket.c b/lib/nodes/socket.c
index 71fe94ea7..dcef254b8 100644
--- a/lib/nodes/socket.c
+++ b/lib/nodes/socket.c
@@ -31,7 +31,7 @@
 #include "plugin.h"
 
 /* Forward declartions */
-static struct node_type vt;
+static struct plugin p;
 
 /* Private static storage */
 struct list interfaces;
@@ -45,7 +45,10 @@ int socket_init(int argc, char * argv[], config_setting_t *cfg)
 	list_init(&interfaces);
 
 	/* Gather list of used network interfaces */
-	list_foreach(struct node *n, &vt.instances) {
+	list_foreach(struct node *n, &p.node.instances) {
+		if (n->state != STATE_INITIALIZED)
+			continue;
+
 		struct socket *s = n->_vd;
 		struct rtnl_link *link;
 
@@ -114,11 +117,12 @@ char * socket_print(struct node *n)
 	
 	if (s->header == SOCKET_HEADER_DEFAULT)
 		endian = "auto";
-	else
+	else {
 		switch (s->endian) {
 			case MSG_ENDIAN_LITTLE:	endian = "little";	break;
 			case MSG_ENDIAN_BIG:	endian = "big";		break;
 		}
+	}
 
 	char *local = socket_print_addr((struct sockaddr *) &s->local);
 	char *remote = socket_print_addr((struct sockaddr *) &s->remote);
diff --git a/lib/nodes/websocket.c b/lib/nodes/websocket.c
index adf33a92d..ffdd96c9f 100644
--- a/lib/nodes/websocket.c
+++ b/lib/nodes/websocket.c
@@ -12,15 +12,15 @@
 
 #include <libconfig.h>
 
-#include "nodes/websocket.h"
 #include "super_node.h"
 #include "webmsg_format.h"
 #include "timing.h"
 #include "utils.h"
-#include "msg.h"
 #include "config.h"
 #include "plugin.h"
 
+#include "nodes/websocket.h"
+
 /* Internal datastructures */
 struct destination {
 	char *uri;
@@ -33,7 +33,7 @@ static int id = 0;		/**< Highest assigned ID to websocket nodes. */
 struct list connections;	/**< List of active libwebsocket connections which receive samples from all nodes (catch all) */
 
 /* Forward declarations */
-static struct node_type vt;
+static struct plugin p;
 
 __attribute__((unused)) static int websocket_connection_init(struct websocket_connection *c)
 {
@@ -143,7 +143,7 @@ int websocket_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, voi
 				char *node = uri + 1;
 			
 				/* Search for node whose name matches the URI. */
-				c->node = list_lookup(&vt.instances, node);
+				c->node = list_lookup(&p.node.instances, node);
 				if (c->node == NULL) {
 					warn("LWS: Closing Connection for non-existent node: %s", uri + 1);
 					return -1;
diff --git a/lib/sample.c b/lib/sample.c
index 009988338..73005d05f 100644
--- a/lib/sample.c
+++ b/lib/sample.c
@@ -143,8 +143,10 @@ int sample_scan(const char *line, struct sample *s, int *fl)
 		*fl = flags;
 	if (flags & SAMPLE_OFFSET) {
 		struct timespec off = time_from_double(offset);
-		s->ts.received = time_diff(&s->ts.origin, &off);
+		s->ts.received = time_add(&s->ts.origin, &off);
 	}
+	else
+		s->ts.received = s->ts.origin;
 
 	return s->length;
 }
diff --git a/lib/web.c b/lib/web.c
index 601f2c288..3c1ea68d1 100644
--- a/lib/web.c
+++ b/lib/web.c
@@ -125,6 +125,8 @@ static void logger(int level, const char *msg) {
 int web_init(struct web *w, struct api *a)
 {
 	info("Initialize web sub-system");
+	
+	lws_set_log_level((1 << LLL_COUNT) - 1, logger);
 
 	w->api = a;
 	
@@ -154,11 +156,6 @@ int web_parse(struct web *w, config_setting_t *cfg)
 
 int web_start(struct web *w)
 {
-	/* update web root of mount point */
-	mounts[0].origin = w->htdocs;
-
-	lws_set_log_level((1 << LLL_COUNT) - 1, logger);
-
 	/* Start server */
 	struct lws_context_creation_info ctx_info = {
 		.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT,
@@ -176,14 +173,21 @@ int web_start(struct web *w)
 		.ssl_private_key_filepath = w->ssl_private_key
 	};
 
-	w->context = lws_create_context(&ctx_info);
-	if (w->context == NULL)
-		error("WebSocket: failed to initialize server");
-	
-	w->vhost = lws_create_vhost(w->context, &vhost_info);
-	if (w->vhost == NULL)
-		error("WebSocket: failed to initialize server");
+	info("Starting web sub-system");
+
+	{ INDENT
+		/* update web root of mount point */
+		mounts[0].origin = w->htdocs;
+
+		w->context = lws_create_context(&ctx_info);
+		if (w->context == NULL)
+			error("WebSocket: failed to initialize server");
 	
+		w->vhost = lws_create_vhost(w->context, &vhost_info);
+		if (w->vhost == NULL)
+			error("WebSocket: failed to initialize server");
+	}
+
 	w->state = STATE_STARTED;
 
 	return 0;