replace old server config loader config

Mon, 24 Aug 2020 17:07:41 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 24 Aug 2020 17:07:41 +0200
branch
config
changeset 256
19259b6c5cf7
parent 255
b5d15a4a19f5
child 257
bfeb015c98a4

replace old server config loader

src/server/config/serverconfig.c file | annotate | diff | comparison | revisions
src/server/config/serverconfig.h file | annotate | diff | comparison | revisions
src/server/daemon/config.c file | annotate | diff | comparison | revisions
src/server/daemon/config.h file | annotate | diff | comparison | revisions
src/server/daemon/event.c file | annotate | diff | comparison | revisions
src/server/daemon/event.h file | annotate | diff | comparison | revisions
src/server/daemon/httplistener.c file | annotate | diff | comparison | revisions
src/server/daemon/httplistener.h file | annotate | diff | comparison | revisions
src/server/daemon/ldap_auth.c file | annotate | diff | comparison | revisions
src/server/daemon/ldap_auth.h file | annotate | diff | comparison | revisions
src/server/daemon/log.c file | annotate | diff | comparison | revisions
src/server/daemon/log.h file | annotate | diff | comparison | revisions
src/server/daemon/main.c file | annotate | diff | comparison | revisions
src/server/daemon/threadpools.c file | annotate | diff | comparison | revisions
src/server/daemon/threadpools.h file | annotate | diff | comparison | revisions
src/server/daemon/webserver.c file | annotate | diff | comparison | revisions
src/server/util/util.c file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/serverconfig.c	Mon Aug 24 17:07:41 2020 +0200
@@ -0,0 +1,322 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "serverconfig.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <ucx/buffer.h>
+#include <ucx/utils.h>
+
+ServerConfig* serverconfig_load(const char *file) {
+    FILE *in = fopen(file, "r");
+    if(in == NULL) {
+        return NULL;
+    }
+    
+    UcxBuffer *buf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND);
+    if(!buf) {
+        fclose(in);
+        return NULL;
+    }
+    
+    ucx_stream_copy(in, buf, (read_func)fread, (write_func)ucx_buffer_write);
+    fclose(in);
+    
+    ServerConfig *scfg = serverconfig_parse(scstrn(buf->space, buf->size));
+    
+    ucx_buffer_free(buf);
+    return scfg;
+}
+
+
+static CFGToken get_next_token(scstr_t content, int *pos) {
+    CFGToken token = { {NULL, 0}, CFG_NO_TOKEN };
+    CFGTokenType type = CFG_TOKEN;
+    
+    int start = *pos;
+    
+    int token_begin = -1;
+    int token_end = content.length-1;
+    
+    int quote = 0;
+    int comment = 0;
+    
+    int i;
+    char prev = 0;
+    for(i=start;i<content.length;i++) {
+        char c = content.ptr[i];
+        if(c == '\n') {
+            if(quote) {
+                *pos = i;
+                return token; // error
+            } else if(start == i) {
+                // single newline char token
+                type = CFG_TOKEN_NEWLINE;
+                token_begin = i;
+                token_end = i+1;
+                break;
+            }
+            
+            token_end = i;
+            if(token_begin < 0) {
+                // only space/comment token
+                token_begin = start;
+                type = comment ? CFG_TOKEN_COMMENT : CFG_TOKEN_SPACE;
+            }
+            // make sure next run will return current newline char as token
+            i--;
+            break;
+        } else if(quote) {
+            if(c == '"' && prev != '\\') {
+                quote = 0;
+            }
+        } else if(comment) {
+            // ignore
+            if(c == '\n') {
+                comment = 0;
+            }
+        } else if(c == '#') {
+            comment = 1;
+        } else if(isspace(c)) {
+            if(token_begin >= 0) {
+                token_end = i;
+                break;
+            }
+        } else if(c == '"') {
+            quote = 1;
+            if(token_begin < 0) {
+                token_begin = i;
+            }
+        } else if(token_begin < 0) {
+            token_begin = i;
+        }
+        prev = c;
+    }
+    
+    *pos = i + 1;
+    
+    if(token_begin < 0) {
+        return token; // error
+    }
+    
+    token.type = type;
+    token.content = scstrsubsl(content, token_begin, token_end - token_begin);
+    return token;
+}
+
+
+static void test_print_config(ConfigNode *parent) {
+    UCX_FOREACH(elm, parent->children) {
+        ConfigNode *node = elm->data;
+        
+        if(node->type == CONFIG_NODE_SPACE) {
+            printf("sp: %s", node->text_begin.ptr);
+        } else if(node->type == CONFIG_NODE_COMMENT) {
+            printf("cm: %s", node->text_begin.ptr);
+        } else if(node->type == CONFIG_NODE_OBJECT) {
+            printf("o{: %s : %s", node->name.ptr, node->text_begin.ptr);
+            test_print_config(node);
+            printf("o}: %s", node->text_end.ptr);
+        } else if(node->type == CONFIG_NODE_DIRECTIVE) {
+            printf("di: %s", node->text_begin.ptr);
+        } else {
+            printf("fk: %s", node->text_begin.ptr);
+        }
+    }
+}
+
+ServerConfig* serverconfig_parse(scstr_t content) {
+    UcxMempool *mp = ucx_mempool_new(512);
+    if(!mp) return NULL;
+    UcxAllocator *a = mp->allocator;
+    
+    ServerConfig *config = ucx_mempool_malloc(mp, sizeof(ServerConfig));
+    if(!config) {
+        ucx_mempool_destroy(mp);
+        return NULL;
+    }
+    config->mp = mp;
+    
+    // PARSE:
+    // first non space/comment token is directive/object name
+    // following tokens are arguments
+    // newline starts new directive
+    // '{' converts directive to object and following directives will
+    // be placed into the object
+    int pos = 0; // needed for tokenizer
+    CFGToken token;
+    
+    ConfigNode *root_obj = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode));
+    root_obj->type = CONFIG_NODE_OBJECT;
+    
+    UcxList *node_stack = ucx_list_prepend(NULL, root_obj);
+    
+    ConfigNode *current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode));
+    current->type = CONFIG_NODE_SPACE;
+    ConfigNode *obj = NULL;
+    int obj_closed = 0;
+    
+    int text_start = 0;
+    int err = 0;
+    while((token = get_next_token(content, &pos)).type != CFG_NO_TOKEN) {
+        //printf("%s [%.*s]\n", token_type_str(token.type), (int)token.content.length, token.content.ptr);
+        
+        switch(token.type) {
+            CFG_NO_TOKEN: break;
+            case CFG_TOKEN_COMMENT: {
+                if(current->type == CONFIG_NODE_SPACE) {
+                    current->type = CONFIG_NODE_COMMENT;
+                }
+                break;
+            }
+            case CFG_TOKEN_SPACE: break;
+            case CFG_TOKEN_NEWLINE: {
+                scstr_t line = scstrsubsl(content, text_start, pos - text_start);
+                text_start = pos;
+                
+                sstr_t line_cp = sstrdup_a(a, line);
+
+                ConfigNode *parent = node_stack->data;
+                if(current->type == CONFIG_NODE_CLOSE_OBJECT) {
+                    parent->text_end = line_cp;
+                    node_stack = ucx_list_remove_a(a, node_stack, node_stack);
+                } else if(current->type == CONFIG_NODE_OPEN_OBJECT) {
+                    sstr_t new_textbegin = sstrcat_a(a, 2, obj->text_begin, line_cp);
+                    alfree(a, obj->text_begin.ptr);
+                    alfree(a, line_cp.ptr);
+                    obj->text_begin = new_textbegin;
+                } else {
+                    current->text_begin = line_cp;
+                    ConfigNode *parent = node_stack->data;
+                    parent->children = ucx_list_append_a(a, parent->children, current);
+                }
+                
+                if(obj && obj->type == CONFIG_NODE_OBJECT) {
+                    node_stack = ucx_list_prepend_a(a, node_stack, obj);
+                    obj = NULL;
+                }
+
+                current = ucx_mempool_calloc(mp, 1, sizeof(ConfigNode));
+                current->type = CONFIG_NODE_SPACE;
+                
+                obj_closed = 0;
+                break;
+            }
+            case CFG_TOKEN: {
+                if(!sstrcmp(token.content, S("{"))) {
+                    if(!obj) {
+                        err = 1;
+                        break;
+                    }
+                    obj->type = CONFIG_NODE_OBJECT;
+                    if(current != obj) {
+                        current->type = CONFIG_NODE_OPEN_OBJECT;
+                    }
+                } else if(!sstrcmp(token.content, S("}"))) {
+                    obj_closed = 1; // force newline before next directive
+                    obj = NULL;
+                    current->type = CONFIG_NODE_CLOSE_OBJECT;
+                } else {
+                    if(obj_closed) {
+                        err = 1;
+                        break;
+                    }
+                    
+                    if(!current->name.ptr) {
+                        current->name = sstrdup_a(a, token.content);
+                        current->type = CONFIG_NODE_DIRECTIVE;
+                        obj = current;
+                    } else {
+                        ConfigArg *arg = ucx_mempool_calloc(mp, 1, sizeof(ConfigArg));
+                        // TODO: add support for key/value
+                        arg->value = sstrdup_a(a, token.content);
+                        current->args = ucx_list_append_a(a, current->args, arg);
+                    }
+                }
+                break;
+            }
+        }
+        
+        if(err) {
+            break;
+        }
+    }
+    
+    if(pos < content.length || err) {
+        // content not fully parsed because of an error
+        ucx_mempool_destroy(mp);
+        return NULL;
+    }
+    
+    //test_print_config(&root_obj);
+    config->root = root_obj;
+    config->tab = sstrdup_a(a, SC("\t"));
+    
+    return config;
+}
+
+void serverconfig_free(ServerConfig *cfg) {
+    ucx_mempool_destroy(cfg->mp);
+}
+
+ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, scstr_t name) {
+    UCX_FOREACH(elm, parent->children) {
+        ConfigNode *node = elm->data;
+        if(node->type == type && !sstrcmp(node->name, name)) {
+            return node;
+        }
+    }
+    return NULL;
+}
+
+UcxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, scstr_t name) {
+    UcxList *nodes = NULL;
+    
+    UCX_FOREACH(elm, parent->children) {
+        ConfigNode *node = elm->data;
+        if(node->type == type && !sstrcmp(node->name, name)) {
+            nodes = ucx_list_append(nodes, node);
+        }
+    }
+    
+    return nodes;
+}
+
+scstr_t serverconfig_directive_value(ConfigNode *obj, scstr_t name) {
+    ConfigNode *node = serverconfig_get_node(obj, CONFIG_NODE_DIRECTIVE, name);
+    if(node && ucx_list_size(node->args) == 1) {
+        ConfigArg *arg = node->args->data;
+        return SCSTR(arg->value);
+    }
+    return scstrn(NULL, 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/config/serverconfig.h	Mon Aug 24 17:07:41 2020 +0200
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2020 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WS_CONFIG_SERVERCONFIG_H
+#define WS_CONFIG_SERVERCONFIG_H
+
+#include <ucx/list.h>
+#include <ucx/map.h>
+#include <ucx/mempool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct ServerConfig    ServerConfig;
+typedef struct ConfigNode      ConfigNode;
+typedef struct ConfigArg       ConfigArg;
+typedef struct CFGToken        CFGToken;
+
+typedef enum ConfigNodeType    ConfigNodeType;
+typedef enum CFGTokenType      CFGTokenType;
+
+struct ServerConfig {
+    UcxMempool *mp;
+    ConfigNode *root;
+    sstr_t tab;
+};
+
+enum ConfigNodeType {
+    CONFIG_NODE_SPACE = 0,
+    CONFIG_NODE_COMMENT,
+    CONFIG_NODE_OBJECT,
+    CONFIG_NODE_DIRECTIVE,
+    CONFIG_NODE_OPEN_OBJECT,
+    CONFIG_NODE_CLOSE_OBJECT
+};
+
+struct ConfigNode {
+    sstr_t text_begin;
+    sstr_t text_end; 
+    ConfigNodeType type;
+    
+    sstr_t name;
+    UcxList *args;
+    UcxList *children;
+};
+
+struct ConfigArg {
+    sstr_t name;
+    sstr_t value;
+};
+
+
+enum CFGTokenType {
+    CFG_NO_TOKEN = 0,
+    CFG_TOKEN_COMMENT,
+    CFG_TOKEN_SPACE,
+    CFG_TOKEN_NEWLINE,
+    CFG_TOKEN
+};
+
+struct CFGToken {
+    scstr_t content;
+    CFGTokenType type;
+};
+
+ServerConfig* serverconfig_load(const char *file);
+
+ServerConfig* serverconfig_parse(scstr_t content);
+
+void serverconfig_free(ServerConfig *cfg);
+
+ConfigNode* serverconfig_get_node(ConfigNode *parent, ConfigNodeType type, scstr_t name);
+
+UcxList* serverconfig_get_node_list(ConfigNode *parent, ConfigNodeType type, scstr_t name);
+
+scstr_t serverconfig_directive_value(ConfigNode *obj, scstr_t name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* WS_CONFIG_SERVERCONFIG_H */
+
--- a/src/server/daemon/config.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/config.c	Mon Aug 24 17:07:41 2020 +0200
@@ -128,10 +128,12 @@
 ServerConfiguration* load_server_conf(char *file) {
     log_ereport(LOG_VERBOSE, "load_server_conf");
 
-    ServerConfig2 *serverconf2 = load_server_config(file);
-    if(serverconf2 == NULL) {
+    ServerConfig *serverconf = serverconfig_load(file);
+    if(!serverconf) {
         log_ereport(LOG_FAILURE, "Cannot load server.conf");
+        return NULL;
     }
+    
     pool_handle_t *pool = pool_create();
     
     
@@ -167,49 +169,54 @@
      */
     
     // init logfile first
-    UcxList *lfl = ucx_map_sstr_get(serverconf2->objects, sstrn("LogFile", 7));
-    if(lfl != NULL) {
-        ServerConfigObject *logobj = lfl->data;
-        if(logobj == NULL) {
+    UcxList *list = NULL;
+    
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("LogFile"));
+    if(list) {
+        ConfigNode *logobj = list->data;
+        if(!logobj) {
             // error
-            return NULL;
+            return NULL; // TODO: fix memory leak
         }
         
         int ret = cfg_handle_logfile(serverconfig, logobj);
         if(ret != 0) {
             // cannot initialize log file
-            return NULL;
+            return NULL; // TODO: fix memory leak
         }
     } else {
         // horrible error
         return NULL;
     }
+    ucx_list_free(list);
      
-    UcxList *list = ucx_map_sstr_get(serverconf2->objects, sstrn("Runtime", 7));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Runtime"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
-        if(cfg_handle_runtime(serverconfig, scfgobj)) {
+        ConfigNode *runtimeobj = elm->data;
+        if(cfg_handle_runtime(serverconfig, runtimeobj)) {
             // error
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("Threadpool", 10));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Threadpool"));
     UCX_FOREACH(elm, list) {
         if(cfg_handle_threadpool(serverconfig, elm->data)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     // check thread pool config
     if(check_thread_pool_cfg() != 0) {
         /* critical error */
         return NULL;
     }
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("EventHandler", 12));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("EventHandler"));
     UCX_FOREACH(elm, list) {
         if(cfg_handle_eventhandler(
-                serverconfig, (ServerConfigObject*)elm->data)) {
+                serverconfig, elm->data)) {
             // error            
             return NULL;
         }
@@ -219,38 +226,43 @@
         /* critical error */
         return NULL;
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("AccessLog", 9));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AccessLog"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
+        ConfigNode *scfgobj = elm->data;
         if(cfg_handle_accesslog(serverconfig, scfgobj)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("AuthDB", 6));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("AuthDB"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
+        ConfigNode *scfgobj = elm->data;
         if(cfg_handle_authdb(serverconfig, scfgobj)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("Listener", 8));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("Listener"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
+        ConfigNode *scfgobj = elm->data;
         if(cfg_handle_listener(serverconfig, scfgobj)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     
-    list = ucx_map_sstr_get(serverconf2->objects, sstrn("VirtualServer", 13));
+    list = serverconfig_get_node_list(serverconf->root, CONFIG_NODE_OBJECT, SC("VirtualServer"));
     UCX_FOREACH(elm, list) {
-        ServerConfigObject *scfgobj = elm->data;
+        ConfigNode *scfgobj = elm->data;
         if(cfg_handle_vs(serverconfig, scfgobj)) {
             return NULL;
         }
     }
+    ucx_list_free(list);
     
 
     // set VirtualServer for all listeners
@@ -274,7 +286,8 @@
         ls = ls->next;
     }
     
-    free_server_config(serverconf2);
+    serverconfig_free(serverconf);
+    
     return serverconfig;
 }
 
@@ -294,22 +307,23 @@
     
 }
 
-int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User"));
+int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj) { 
+    scstr_t user = serverconfig_directive_value(obj, SC("User"));
     if(user.ptr) {
-        cfg->user = sstrdup_pool(cfg->pool, user);
+        cfg->user = sstrdup_a(cfg->a, user);
     }
-    sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp"));
+    scstr_t tmp = serverconfig_directive_value(obj, SC("Temp"));
     if(tmp.ptr) {
-        cfg->tmp = sstrdup_pool(cfg->pool, tmp);
+        cfg->tmp = sstrdup_a(cfg->a, tmp);
     } else {
+        // TODO: do this check after all config loading is done
         log_ereport(LOG_MISCONFIG, "no temporary directory specified");
         return -1;
     }
     
     // mime file
-    sstr_t mf = cfg_directivelist_get_str(obj->directives, sstr("MimeFile"));  
-    sstr_t base = sstr("config/"); 
+    scstr_t mf = serverconfig_directive_value(obj, SC("MimeFile"));  
+    scstr_t base = SC("config/"); 
     sstr_t file = sstrcat(2, base, mf);
     
     if(mime_conf_load(cfg, file)) {
@@ -320,9 +334,9 @@
     return 0;
 }
 
-int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File"));
-    sstr_t lvl = cfg_directivelist_get_str(obj->directives, sstr("Level"));
+int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj) {
+    scstr_t file = serverconfig_directive_value(obj, SC("File"));
+    scstr_t lvl = serverconfig_directive_value(obj, SC("Level"));
     
     if(file.ptr == NULL || lvl.ptr == NULL) {
         /* missing log file parameters */
@@ -330,21 +344,18 @@
     }
     
     LogConfig logcfg;
-    logcfg.file = sstrdup(file).ptr;
-    logcfg.level = sstrdup(lvl).ptr;
+    logcfg.file = file.ptr;
+    logcfg.level = lvl.ptr;
     logcfg.log_stdout = 0;
     logcfg.log_stderr = 0;
     /* TODO: stdout, stderr config */
     
     int ret = init_log_file(&logcfg);
-    
-    free(logcfg.file);
-    free(logcfg.level);
 
     return ret;
 }
 
-int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj) {
     ThreadPoolConfig poolcfg;
     poolcfg.min_threads = 4;
     poolcfg.min_threads = 4;
@@ -352,21 +363,11 @@
     poolcfg.queue_size = 64;
     poolcfg.stack_size = 262144;
     
-    sstr_t name = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name"));
-    sstr_t min = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("MinThreads"));
-    sstr_t max = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("MaxThreads"));
-    sstr_t stack = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("StackSize"));
-    sstr_t queue = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("QueueSize"));
+    scstr_t name  = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t min   = serverconfig_directive_value(obj, SC("MinThreads"));
+    scstr_t max   = serverconfig_directive_value(obj, SC("MaxThreads"));
+    scstr_t stack = serverconfig_directive_value(obj, SC("StackSize"));
+    scstr_t queue = serverconfig_directive_value(obj, SC("QueueSize"));
     // TODO: Type
     
     if(name.length == 0) {
@@ -375,27 +376,19 @@
     }
     
     if(min.length != 0) {
-        min = sstrdup(min);
         poolcfg.min_threads = atoi(min.ptr);
-        free(min.ptr);
     }
     
     if(max.length != 0) {
-        max = sstrdup(max);
         poolcfg.max_threads = atoi(max.ptr);
-        free(max.ptr);
     }
     
     if(stack.length != 0) {
-        stack = sstrdup(stack);
         poolcfg.stack_size = atoi(stack.ptr);
-        free(stack.ptr);
     }
     
     if(queue.length != 0) {
-        queue = sstrdup(queue);
         poolcfg.queue_size = atoi(queue.ptr);
-        free(queue.ptr);
     }
     
     create_threadpool(name, &poolcfg);
@@ -403,32 +396,26 @@
     return 0;
 }
 
-int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *obj) {
+int cfg_handle_eventhandler(ServerConfiguration *c, ConfigNode *obj) {
     EventHandlerConfig evcfg;
     
-    sstr_t name      = cfg_directivelist_get_str(obj->directives, sstr("Name"));
-    sstr_t threads   = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Threads"));
-    sstr_t isdefault = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Default"));
+    scstr_t name      = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t threads   = serverconfig_directive_value(obj, SC("Threads"));
+    scstr_t isdefault = serverconfig_directive_value(obj, SC("Default"));
     
     evcfg.name = name;
     
-    sstr_t s = sstrdup(threads);
-    evcfg.nthreads = atoi(s.ptr);
-    free(s.ptr);
+    evcfg.nthreads = atoi(threads.ptr);
     
     evcfg.isdefault = util_getboolean(isdefault.ptr, 0);
     
     return create_event_handler(&evcfg);
 }
 
-int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj) {
     // TODO: use a name to identify the log file
     
-    sstr_t file = cfg_directivelist_get_str(obj->directives, sstr("File"));
+    scstr_t file = serverconfig_directive_value(obj, SC("File"));
     if(file.ptr == NULL) {
         return 0;
     }
@@ -443,10 +430,10 @@
         return 0;
     }
     AccessLog *log = pool_malloc(cfg->pool, sizeof(AccessLog));
-    log->file = sstrdup_pool(cfg->pool, file);
+    log->file = sstrdup_a(cfg->a, file);
     log->format = format;
     log->log = log_file;
-    cfg->logfiles = ucx_list_append(cfg->logfiles, log);
+    cfg->logfiles = ucx_list_append_a(cfg->a, cfg->logfiles, log);
     
     if(!cfg->default_log) {
         cfg->default_log = log;
@@ -455,62 +442,31 @@
     return 0;
 }
 
-int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    sstr_t name = cfg_directivelist_get_str(obj->directives, sstr("Name"));
-    sstr_t type = cfg_directivelist_get_str(obj->directives, sstr("Type"));
+int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj) {
+    scstr_t name = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t type = serverconfig_directive_value(obj, SC("Type"));
     
     AuthDB *authdb = NULL;
     
     if(!sstrcmp(type, sstr("ldap"))) {
         LDAPConfig conf;
         
-        sstr_t host = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("Host"));
-        sstr_t port = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("Port"));
-        sstr_t basedn = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BaseDN"));
-        sstr_t binddn = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BindDN"));
-        sstr_t basepw = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("BindPW"));
+        scstr_t host = serverconfig_directive_value(obj, SC("Host"));
+        scstr_t port = serverconfig_directive_value( obj, SC("Port"));
+        scstr_t basedn = serverconfig_directive_value(obj, SC("BaseDN"));
+        scstr_t binddn = serverconfig_directive_value(obj, SC("BindDN"));
+        scstr_t basepw = serverconfig_directive_value(obj, SC("BindPW"));
         
-        host = sstrdup(host);
-        port = sstrdup(port);
-        basedn = sstrdup(basedn);
-        binddn = sstrdup(binddn);
-        basepw = sstrdup(basepw);
-        
-        conf.hostname = host.ptr;
+        conf.hostname = sstrdup_a(cfg->a, host).ptr;
         conf.port = atoi(port.ptr);
-        conf.basedn = basedn.ptr;
-        conf.binddn = binddn.ptr;
-        conf.bindpw = basepw.ptr;
+        conf.basedn = sstrdup_a(cfg->a, basedn).ptr;
+        conf.binddn = sstrdup_a(cfg->a, binddn).ptr;
+        conf.bindpw = sstrdup_a(cfg->a, basepw).ptr;
         
-        name = sstrdup(name);
-        
-        authdb = create_ldap_authdb(name.ptr, &conf);
-        
-        // TODO: create_ldap_authdb should copy the strings
-        /*
-        free(host.ptr);
-        free(port.ptr);
-        free(basedn.ptr);
-        free(binddn.ptr);
-        free(basepw.ptr);
-        free(name.ptr);
-        */
-        
+        authdb = create_ldap_authdb(cfg, name.ptr, &conf);      
     } else if(!sstrcmp(type, sstr("keyfile"))) {
         // we only need the file parameter
-        sstr_t file = cfg_directivelist_get_str(
-                obj->directives,
-                sstr("File"));
+        scstr_t file = serverconfig_directive_value(obj, SC("File"));
         if(file.length == 0) {
             log_ereport(
                     LOG_MISCONFIG,
@@ -531,42 +487,33 @@
     return 0;
 }
 
-int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj) {
     ListenerConfig lc;
     ZERO(&lc, sizeof(ListenerConfig));
     lc.cfg = cfg;
     lc.port = 8080;
     lc.nacceptors = 1;
     
-    // TODO: use sstrdup_pool?
-    lc.name = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name")));
-    lc.port = atoi(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Port")).ptr);
-    lc.vs = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("DefaultVS")));
-    lc.threadpool = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Threadpool")));
+    scstr_t name = serverconfig_directive_value(obj, SC("Name"));
+    scstr_t port = serverconfig_directive_value(obj, SC("Port"));
+    scstr_t vs   = serverconfig_directive_value(obj, SC("DefaultVS"));
+    scstr_t thrp = serverconfig_directive_value(obj, SC("Threadpool"));
+    scstr_t blck = serverconfig_directive_value(obj, SC("BlockingIO"));
     
-    sstr_t blockingio = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("BlockingIO"));
-    if(blockingio.ptr) {
-        lc.blockingio = util_getboolean_s(blockingio, WS_FALSE);
-    }
+    // TODO: use sstrdup_pool?
+    lc.name = sstrdup(name);
+    lc.port = atoi(port.ptr);
+    lc.vs = sstrdup(vs);
+    lc.threadpool = sstrdup(thrp);
     
-    sstr_t ssl = cfg_directivelist_get_str(obj->directives, S("SSL"));
+    lc.blockingio = util_getboolean_s(blck, WS_FALSE);
+    
+    scstr_t ssl = serverconfig_directive_value(obj, SC("SSL"));
     if(util_getboolean_s(ssl, WS_FALSE)) {
-        sstr_t cert = cfg_directivelist_get_str(obj->directives, S("Cert"));
-        sstr_t privkey = cfg_directivelist_get_str(obj->directives, S("Key"));
-        sstr_t chain = cfg_directivelist_get_str(obj->directives, S("CertChain"));
-        sstr_t disableprot = cfg_directivelist_get_str(
-                obj->directives,
-                S("SSLDisableProtocol"));
+        scstr_t cert        = serverconfig_directive_value(obj, SC("Cert"));
+        scstr_t privkey     = serverconfig_directive_value(obj, SC("Key"));
+        scstr_t chain       = serverconfig_directive_value(obj, SC("CertChain"));
+        scstr_t disableprot = serverconfig_directive_value(obj, SC("SSLDisableProtocol"));
         
         WSBool config_ok = WS_TRUE;
         // TODO: log error
@@ -603,30 +550,21 @@
         return 1;
     }
     
-    listener->default_vs.vs_name = lc.vs.ptr;
-    cfg->listeners = ucx_list_append(cfg->listeners, listener); 
+    listener->default_vs.vs_name = sstrdup_a(cfg->a, lc.vs).ptr;
+    cfg->listeners = ucx_list_append_a(cfg->a, cfg->listeners, listener); 
     
     return 0;
 }
 
-int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) {
+int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj) {
     VirtualServer *vs = vs_new();
 
-    vs->name = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Name")));
-    vs->host = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("Host")));
-    vs->document_root = sstrdup(cfg_directivelist_get_str(
-            obj->directives,
-            sstr("DocRoot")));
-    sstr_t objfile = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("ObjectFile"));
-    sstr_t aclfile = cfg_directivelist_get_str(
-            obj->directives,
-            sstr("ACLFile"));
+    vs->name = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Name")));
+    vs->host = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("Host")));
+    vs->document_root = sstrdup_a(cfg->a, serverconfig_directive_value(obj, SC("DocRoot")));
+    
+    scstr_t objfile = serverconfig_directive_value(obj, SC("ObjectFile"));
+    scstr_t aclfile = serverconfig_directive_value(obj, SC("ACLFile"));
     
     // load the object config file
     sstr_t base = sstr("config/");
@@ -916,7 +854,7 @@
     return &acllist->acl;
 }
 
-AuthDB* keyfile_load(ServerConfiguration *cfg, sstr_t file) {
+AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file) {
     Keyfile *keyfile = keyfile_new(cfg->a);
     if(!keyfile) {
         return NULL;
--- a/src/server/daemon/config.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/config.h	Mon Aug 24 17:07:41 2020 +0200
@@ -39,6 +39,7 @@
 #include "../config/mimeconf.h"
 #include "../config/acl.h"
 #include "../config/keyfile.h"
+#include "../config/serverconfig.h"
 
 #include "acldata.h"
 #include "keyfile_auth.h"
@@ -79,21 +80,21 @@
 
 void init_server_config_parser();
 
-int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_runtime(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_logfile(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_logfile(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_threadpool(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_threadpool(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_eventhandler(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_eventhandler(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_accesslog(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_accesslog(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_authdb(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_listener(ServerConfiguration *cfg, ConfigNode *obj);
 
-int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj);
+int cfg_handle_vs(ServerConfiguration *cfg, ConfigNode *obj);
 
 ServerConfiguration* load_server_conf(char *file);
 void cfg_ref(ServerConfiguration *cfg);
@@ -104,7 +105,7 @@
 
 ACLData* acl_conf_load(ServerConfiguration *cfg, sstr_t file);
 ACLList* acl_config_convert(ServerConfiguration *cfg, ACLConfig *acl);
-AuthDB* keyfile_load(ServerConfiguration *cfg, sstr_t file);
+AuthDB* keyfile_load(ServerConfiguration *cfg, scstr_t file);
 
 
 
--- a/src/server/daemon/event.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/event.c	Mon Aug 24 17:07:41 2020 +0200
@@ -88,7 +88,7 @@
     }
     
     EventHandlerConfig cfg;
-    cfg.name = sstr("default");
+    cfg.name = SC("default");
     cfg.nthreads = 1;
     cfg.isdefault = 1;
     
--- a/src/server/daemon/event.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/event.h	Mon Aug 24 17:07:41 2020 +0200
@@ -43,7 +43,7 @@
 } EVHandler;
 
 typedef struct event_handler_conf {
-    sstr_t   name;
+    scstr_t  name;
     int      nthreads;
     int      isdefault;
 } EventHandlerConfig;
--- a/src/server/daemon/httplistener.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/httplistener.c	Mon Aug 24 17:07:41 2020 +0200
@@ -237,23 +237,18 @@
         }
         // TODO: cleanup on error
         
-        sstr_t file;
         int ret;
         char errbuf[512];
         
         if(!conf->chainfile.ptr) {
-            file = sstrdup(conf->certfile);
-            ret = SSL_CTX_use_certificate_file(ctx, file.ptr, SSL_FILETYPE_PEM);
-            free(file.ptr);
+            ret = SSL_CTX_use_certificate_file(ctx, conf->certfile.ptr, SSL_FILETYPE_PEM);
             if(!ret) {
                 ERR_error_string(ERR_get_error(), errbuf);
                 log_ereport(LOG_MISCONFIG, "Cannot load ssl chain file: %s", errbuf);
                 return NULL;
             }
         } else {
-            file = sstrdup(conf->chainfile);
-            ret = SSL_CTX_use_certificate_chain_file(ctx, file.ptr);
-            free(file.ptr);
+            ret = SSL_CTX_use_certificate_chain_file(ctx, conf->chainfile.ptr);
             if(!ret) { 
                 ERR_error_string(ERR_get_error(), errbuf);
                 log_ereport(LOG_MISCONFIG, "Cannot load ssl cert file: %s", errbuf);
@@ -261,9 +256,7 @@
             }
         }
         
-        file = sstrdup(conf->privkeyfile);
-        ret = SSL_CTX_use_PrivateKey_file(ctx, file.ptr, SSL_FILETYPE_PEM);
-        free(file.ptr);
+        ret = SSL_CTX_use_PrivateKey_file(ctx, conf->privkeyfile.ptr, SSL_FILETYPE_PEM);
         if(!ret) { 
             ERR_error_string(ERR_get_error(), errbuf);
             log_ereport(LOG_MISCONFIG, "Cannot load ssl key file: %s", errbuf);
--- a/src/server/daemon/httplistener.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/httplistener.h	Mon Aug 24 17:07:41 2020 +0200
@@ -64,10 +64,10 @@
     int                  nacceptors;
     WSBool               blockingio;
     WSBool               ssl;
-    sstr_t               certfile;
-    sstr_t               privkeyfile;
-    sstr_t               chainfile;
-    sstr_t               disable_proto;
+    scstr_t              certfile;
+    scstr_t              privkeyfile;
+    scstr_t              chainfile;
+    scstr_t              disable_proto;
 };
 
 struct _acceptor {
--- a/src/server/daemon/ldap_auth.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/ldap_auth.c	Mon Aug 24 17:07:41 2020 +0200
@@ -47,9 +47,9 @@
 #endif
 }
 
-AuthDB* create_ldap_authdb(char *name, LDAPConfig *conf) {
-    LDAPAuthDB *authdb = malloc(sizeof(LDAPAuthDB));
-    authdb->authdb.name = strdup(name);
+AuthDB* create_ldap_authdb(ServerConfiguration *cfg, const char *name, LDAPConfig *conf) {
+    LDAPAuthDB *authdb = almalloc(cfg->a, sizeof(LDAPAuthDB));
+    authdb->authdb.name = pool_strdup(cfg->pool, name);
     authdb->authdb.get_user = ldap_get_user;
     authdb->authdb.use_cache = 1;
     authdb->config = *conf;
@@ -64,7 +64,7 @@
     // initialize group cache
     authdb->groups.first = NULL;
     authdb->groups.last = NULL;
-    authdb->groups.map = ucx_map_new(32);
+    authdb->groups.map = ucx_map_new_a(cfg->a, 32);
 
     return (AuthDB*) authdb;
 }
--- a/src/server/daemon/ldap_auth.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/ldap_auth.h	Mon Aug 24 17:07:41 2020 +0200
@@ -34,6 +34,8 @@
 #include <ldap.h>
 #include <ucx/map.h>
 
+#include "config.h"
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -90,7 +92,7 @@
     LDAPGroup   *next;
 };
 
-AuthDB* create_ldap_authdb(char *name, LDAPConfig *conf);
+AuthDB* create_ldap_authdb(ServerConfiguration *cfg, const char *name, LDAPConfig *conf);
 
 LDAP* get_ldap_session(LDAPAuthDB *authdb);
 
--- a/src/server/daemon/log.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/log.c	Mon Aug 24 17:07:41 2020 +0200
@@ -335,7 +335,9 @@
  * This source file only manages access log files. IO is performed directly
  * by AddLog safs. 
  */
-LogFile* get_access_log_file(sstr_t file) {
+LogFile* get_access_log_file(scstr_t file) {
+    // TODO: this looks dubious
+    
     if(!access_log_files) {
         access_log_files = ucx_map_new(4);
     }
--- a/src/server/daemon/log.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/log.h	Mon Aug 24 17:07:41 2020 +0200
@@ -40,10 +40,10 @@
 #endif
 
 typedef struct {
-    char   *file;
-    char   *level;
-    int    log_stdout;
-    int    log_stderr;
+    const char   *file;
+    const char   *level;
+    int          log_stdout;
+    int          log_stderr;
 } LogConfig;
 
 typedef struct {
@@ -75,7 +75,7 @@
 void log_remove_logdup(LogDup *dup);
 
 // access logging
-LogFile* get_access_log_file(sstr_t file);
+LogFile* get_access_log_file(scstr_t file);
 
 #ifdef	__cplusplus
 }
--- a/src/server/daemon/main.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/main.c	Mon Aug 24 17:07:41 2020 +0200
@@ -167,7 +167,7 @@
     int status;
     status = webserver_init();
     if(status != 0) {
-        log_ereport(LOG_FAILURE, "cannot initialize server.");
+        log_ereport(LOG_FAILURE, "Cannot initialize server.");
         return EXIT_FAILURE;
     }
 
--- a/src/server/daemon/threadpools.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/threadpools.c	Mon Aug 24 17:07:41 2020 +0200
@@ -45,7 +45,7 @@
 static threadpool_t *default_io_pool;
 static threadpool_t *last_io_pool;
 
-int create_threadpool(sstr_t name, ThreadPoolConfig *cfg) { 
+int create_threadpool(scstr_t name, ThreadPoolConfig *cfg) { 
     if(thread_pool_map == NULL) {
         thread_pool_map = ucx_map_new(16);
     }
@@ -77,7 +77,7 @@
     }
 }
 
-int create_io_pool(sstr_t name, int numthreads) {
+int create_io_pool(scstr_t name, int numthreads) {
     if(io_pool_map == NULL) {
         io_pool_map = ucx_map_new(4);
     }
@@ -110,13 +110,13 @@
         cfg.max_threads = 8;
         cfg.queue_size = 64;
         cfg.stack_size = 262144;
-        if(create_threadpool(sstr("default"), &cfg)) {
+        if(create_threadpool(SC("default"), &cfg)) {
             return 1;
         }
     }
     
     if(num_iopools == 0) {
-        if(create_io_pool(sstr("default"), 8)) {
+        if(create_io_pool(SC("default"), 8)) {
             return 1;
         }
     }
--- a/src/server/daemon/threadpools.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/threadpools.h	Mon Aug 24 17:07:41 2020 +0200
@@ -45,7 +45,7 @@
     int queue_size;
 } ThreadPoolConfig;
 
-int create_threadpool(sstr_t name, ThreadPoolConfig *cfg);
+int create_threadpool(scstr_t name, ThreadPoolConfig *cfg);
 
 int check_thread_pool_cfg();
 
--- a/src/server/daemon/webserver.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/daemon/webserver.c	Mon Aug 24 17:07:41 2020 +0200
@@ -87,7 +87,6 @@
     init_configuration_manager();
     ServerConfiguration *cfg;
     if(cfgmgr_load_config(&cfg) != 0) {
-        fprintf(stderr, "Cannot load configuration\n");
         return -1;
     }
     
--- a/src/server/util/util.c	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/util/util.c	Mon Aug 24 17:07:41 2020 +0200
@@ -394,7 +394,7 @@
     return def;
 }
 
-int util_getboolean_s(sstr_t s, int def) {
+int util_getboolean_s(scstr_t s, int def) {
     if(s.length == 0) {
         return def;
     }
--- a/src/server/util/util.h	Mon Aug 24 12:50:16 2020 +0200
+++ b/src/server/util/util.h	Mon Aug 24 17:07:41 2020 +0200
@@ -197,7 +197,7 @@
 NSAPI_PUBLIC PRBool INTutil_format_http_version(const char *v, int *protv_num, char *buffer, int size);
 
 NSAPI_PUBLIC int INTutil_getboolean(const char *v, int def);
-int util_getboolean_s(sstr_t s, int def);
+int util_getboolean_s(scstr_t s, int def);
 
 // new
 NSAPI_PUBLIC int util_strtoint(char *str, int64_t *value);

mercurial