server can reload configuration

Sat, 06 Oct 2012 13:00:07 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 06 Oct 2012 13:00:07 +0200
changeset 36
450d2d5f4735
parent 35
4417619a9bbd
child 37
360b9aabe17e

server can reload configuration

src/server/config/conf.c file | annotate | diff | comparison | revisions
src/server/config/serverconf.c 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/configmanager.c 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/httprequest.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.c file | annotate | diff | comparison | revisions
src/server/daemon/vserver.c file | annotate | diff | comparison | revisions
src/server/daemon/vserver.h file | annotate | diff | comparison | revisions
src/server/safs/init.c file | annotate | diff | comparison | revisions
src/server/ucx/allocator.c file | annotate | diff | comparison | revisions
src/server/ucx/allocator.h file | annotate | diff | comparison | revisions
src/server/ucx/atomic.c file | annotate | diff | comparison | revisions
src/server/ucx/atomic.h file | annotate | diff | comparison | revisions
src/server/ucx/dlist.c file | annotate | diff | comparison | revisions
src/server/ucx/dlist.h file | annotate | diff | comparison | revisions
src/server/ucx/list.c file | annotate | diff | comparison | revisions
src/server/ucx/list.h file | annotate | diff | comparison | revisions
src/server/ucx/map.c file | annotate | diff | comparison | revisions
src/server/ucx/map.h file | annotate | diff | comparison | revisions
src/server/ucx/mempool.h file | annotate | diff | comparison | revisions
src/server/ucx/objs.mk file | annotate | diff | comparison | revisions
src/server/ucx/string.c file | annotate | diff | comparison | revisions
src/server/ucx/string.h file | annotate | diff | comparison | revisions
src/server/ucx/ucx.h file | annotate | diff | comparison | revisions
src/server/webdav/webdav.c file | annotate | diff | comparison | revisions
--- a/src/server/config/conf.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/config/conf.c	Sat Oct 06 13:00:07 2012 +0200
@@ -143,7 +143,7 @@
         }
 
         sstr_t line = sstr(buf);
-        return sstrdub(line);
+        return sstrdup(line);
     }
 
     sstr_t s;
--- a/src/server/config/serverconf.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/config/serverconf.c	Sat Oct 06 13:00:07 2012 +0200
@@ -87,7 +87,7 @@
             sstr_t tag = cfg_get_end_tag_name(line);
             if(sstrcmp(tag, conf->obj->type) != 0) {
                 fprintf(stderr, "syntax error: wrong close tag\n");
-                fprintf(stderr, "open tag: %s   close tag: %s\n", sstrdub(tag).ptr, sstrdub(conf->obj->type).ptr);
+                fprintf(stderr, "open tag: %s   close tag: %s\n", sstrdup(tag).ptr, sstrdup(conf->obj->type).ptr);
                 exit(-1);
             }
             conf->obj = NULL;
--- a/src/server/daemon/config.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/config.c	Sat Oct 06 13:00:07 2012 +0200
@@ -38,6 +38,7 @@
 #include <sys/mman.h>
 
 #include "../ucx/string.h"
+#include "../ucx/atomic.h"
 
 #include "httplistener.h"
 #include "config.h"
@@ -111,6 +112,7 @@
         fprintf(stderr, "Cannot load server.conf\n");
     }
     ServerConfiguration *serverconfig = malloc(sizeof(ServerConfiguration));
+    serverconfig->ref = 1;
     serverconfig->pool = pool_create();
     serverconfig->listeners = NULL;
     serverconfig->host_vs = ucx_map_new(16);
@@ -184,29 +186,30 @@
         cfg_handle_vs(serverconfig, scfgobj);
     }
 
-    /* check event handler config */
+    // check event handler config
     if(check_event_handler_cfg() != 0) {
         /* critical error */
         return NULL;
     }
     
-    /* check thread pool config */
+    // check thread pool config
     if(check_thread_pool_cfg() != 0) {
         /* critical error */
         return NULL;
     }
 
-    /* set VirtualServer for all listeners */
+    // set VirtualServer for all listeners
     UcxList *ls = serverconfig->listeners;
     while(ls) {
         HttpListener *listener = ls->data;
 
         sstr_t vsname = sstr(listener->default_vs.vs_name);
 
-        /* search for VirtualServer */
-        int b = 0;
+        // search for VirtualServer
+        //int b = 0;
         UcxMapIterator iter = ucx_map_iterator(serverconfig->host_vs);
-        UCX_MAP_FOREACH(VirtualServer*, vs, serverconfig->host_vs, iter) {
+        VirtualServer *vs;
+        UCX_MAP_FOREACH(vs, iter) {
             if(!sstrcmp(vsname, vs->name)) {
                 listener->default_vs.vs = vs;
                 break;
@@ -219,16 +222,27 @@
     return serverconfig;
 }
 
+void cfg_ref(ServerConfiguration *cfg) {
+    ucx_atomic_inc_32(&cfg->ref);
+}
+
+void cfg_unref(ServerConfiguration *cfg) {
+    uint32_t ref = ucx_atomic_dec_32_nv(&cfg->ref);
+    if(ref == 0) {
+        // TODO: free configuration
+    }
+}
+
 
 void init_server_config_parser() {
     
 }
 
 int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) {
-    cfg->user = sstrdub(cfg_directivelist_get_str(
+    cfg->user = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("User")));
-    cfg->tmp = sstrdub(cfg_directivelist_get_str(
+    cfg->tmp = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("Temp")));
 
@@ -246,7 +260,7 @@
     
     LogConfig logcfg;
     logcfg.file = sstrdup(file).ptr;
-    logcfg.level = sstrdub(lvl).ptr;
+    logcfg.level = sstrdup(lvl).ptr;
     /* TODO: stdout, stderr config */
     
     int ret = init_log_file(&logcfg);
@@ -289,21 +303,23 @@
 
 int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) {
     ListenerConfig lc;
+    lc.cfg = cfg;
     lc.port = 8080;
     lc.nacceptors = 1;
-
-    lc.name = sstrdub(cfg_directivelist_get_str(
+    
+    // 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 = sstrdub(cfg_directivelist_get_str(
+    lc.vs = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("DefaultVS")));
     
 
-    HttpListener *listener = http_listener_new(&lc);
+    HttpListener *listener = http_listener_create(&lc);
     listener->default_vs.vs_name = lc.vs.ptr;
     cfg->listeners = ucx_list_append(cfg->listeners, listener); 
 
@@ -313,13 +329,13 @@
 int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) {
     VirtualServer *vs = vs_new();
 
-    vs->name = sstrdub(cfg_directivelist_get_str(
+    vs->name = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("Name")));
-    vs->host = sstrdub(cfg_directivelist_get_str(
+    vs->host = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("Host")));
-    vs->document_root = sstrdub(cfg_directivelist_get_str(
+    vs->document_root = sstrdup(cfg_directivelist_get_str(
             obj->directives,
             sstr("DocRoot")));
     sstr_t objfile = cfg_directivelist_get_str(
@@ -335,12 +351,13 @@
     ConfigFile *f = cfgmgr_get_file(file);
     if(f == NULL) {
         f = malloc(sizeof(ConfigFile));
-        f->file = sstrdub(file);
+        f->file = sstrdup(file);
         f->reload = object_conf_reload;
         f->reload(f, cfg);
         cfgmgr_attach_file(f);
     }
-    vs->objects = (HTTPObjectConfig*)f->data;
+    vs->objectfile = sstrdup(file); // TODO: pool
+    vs->objects = (HTTPObjectConfig*)f->data; // TODO: ref
 
     ucx_map_sstr_put(cfg->host_vs, vs->host, vs);
     
@@ -387,10 +404,10 @@
         char *name = NULL;
         char *ppath = NULL;
         if(cob->name.length > 0) {
-            name = sstrdub(cob->name).ptr;
+            name = sstrdup(cob->name).ptr;
         }
         if(cob->ppath.length > 0) {
-            ppath = sstrdub(cob->ppath).ptr;
+            ppath = sstrdup(cob->ppath).ptr;
         }
 
         /* create and add object */
--- a/src/server/daemon/config.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/config.h	Sat Oct 06 13:00:07 2012 +0200
@@ -29,6 +29,8 @@
 #ifndef CONF_H
 #define	CONF_H
 
+#include <inttypes.h>
+
 #include "../util/object.h"
 
 #include "../config/objconf.h"
@@ -54,6 +56,7 @@
     UcxMap          *authdbs;
     sstr_t          tmp;
     sstr_t          user;
+    uint32_t        ref;        // reference counter
 } ServerConfiguration;
 
 
@@ -86,6 +89,8 @@
 int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj);
 
 ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file);
+void cfg_ref(ServerConfiguration *cfg);
+void cfg_unref(ServerConfiguration *cfg);
 
 int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg);
 
--- a/src/server/daemon/configmanager.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/configmanager.c	Sat Oct 06 13:00:07 2012 +0200
@@ -31,6 +31,10 @@
 
 #include "../public/nsapi.h"
 
+#include "../ucx/string.h"
+
+#include "httplistener.h"
+#include "log.h"
 #include "configmanager.h"
 
 ServerConfiguration *current_config = NULL;
@@ -53,12 +57,44 @@
     return ucx_map_sstr_get(config_files, name);
 }
 
+// copy functions
+static void* copy_listener(HttpListener *ls, ServerConfiguration *cfg) {
+    /*
+     * we reuse the old listener, but change the
+     * ServerConfiguration and VirtualServer
+     */
+    http_listener_ref(ls);
+    ls->cfg = cfg;
+    
+    sstr_t vsname = ls->default_vs.vs->name;
+    ls->default_vs.vs = ucx_map_sstr_get(cfg->host_vs, vsname);
+    
+    return ls;
+}
+
+static void* copy_vs(void *vserver, void *pool) {
+    VirtualServer *vs = vs_copy(vserver, pool);
+    
+    /*
+     * this function is executed on configuration reload, so some
+     * VS configs may be changed
+     * 
+     * vs
+     *    objects
+     */
+    ConfigFile *objectfile = cfgmgr_get_file(vs->objectfile);
+    vs->objects = objectfile->data;
+    return vs;
+}
+
+
 int cfgmgr_load_config() {
     int cfgreload = 0;
     
     /* check config files */  
     UcxMapIterator iter = ucx_map_iterator(config_files);
-    UCX_MAP_FOREACH(ConfigFile*, f, config_files, iter) {
+    ConfigFile *f;
+    UCX_MAP_FOREACH(f, iter) {
         struct stat s;
         if(stat(f->file.ptr, &s) != 0) {
             fprintf(
@@ -70,6 +106,11 @@
 
         if(f->last_modified != s.st_mtim.tv_sec) {
             /* reload the file */
+            //printf("reload: %s\n", sstrdup(f->file).ptr);
+            log_ereport(
+                    LOG_LEVEL_INFO,
+                    "reload configuration file: %s",
+                    f->file.ptr);
             f->reload(f, current_config);
             cfgreload = 1;
         }
@@ -83,6 +124,7 @@
 
     ServerConfiguration *config;
     if(sc_last_modified != s.st_mtim.tv_sec) {
+        printf("cfgmgr load server.conf\n");
         config = load_server_conf(
             current_config,
             "conf/server.conf");
@@ -91,13 +133,35 @@
             fprintf(stderr, "Cannot load server.conf\n");
             return -1;
         }
+        
+        sc_last_modified = s.st_mtim.tv_sec;
     } else if(cfgreload) {
         /* copy configuration */
-
+        printf("cfgmgr copy server.conf\n");
+        
         /* TODO: copy */
+        /*
         config = load_server_conf(
             current_config,
             "conf/server.conf");
+        */
+        config = malloc(sizeof(ServerConfiguration));
+        config->ref = 1;
+        config->pool = pool_create();
+        config->user = sstrdup_pool(config->pool, current_config->user);
+        config->tmp = sstrdup_pool(config->pool, current_config->tmp);
+        
+        // copy configuration       
+        config->host_vs = ucx_map_clone(
+                current_config->host_vs,
+                copy_vs,
+                config->pool);
+        
+        config->listeners = ucx_list_clone(
+                current_config->listeners,
+                (copy_func)copy_listener,
+                config);
+        
 
         if(config == NULL) {
             fprintf(stderr, "Cannot load server.conf\n");
@@ -105,10 +169,11 @@
         }
 
     } else {
+        printf("no reconfig required!\n");
         config = current_config;
     }
 
-
+    
     current_config = config;
     return 0;
 }
--- a/src/server/daemon/httplistener.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/httplistener.c	Sat Oct 06 13:00:07 2012 +0200
@@ -47,6 +47,7 @@
 #include <pthread.h>
 
 #include "../ucx/map.h"
+#include "../ucx/atomic.h"
 #include "httplistener.h"
 
 #include "session.h"
@@ -67,8 +68,55 @@
     return 0;
 }
 
+HttpListener* http_listener_create(ListenerConfig *conf) {
+    if(listener_map == NULL) {
+        listener_map = ucx_map_new(16);
+    }
+
+    HttpListener *fl = ucx_map_sstr_get(listener_map, conf->name);
+    if(fl == NULL) {
+        return http_listener_new(conf);
+    }
+    
+    HttpListener* newls = malloc(sizeof(HttpListener));
+    if(newls == NULL) {
+        // TODO: error
+    }
+    
+    newls->cfg = conf->cfg;
+    newls->default_vs.vs_name = conf->vs.ptr;
+    newls->port = fl->port;
+    newls->server_socket = fl->server_socket;
+    newls->session_handler = fl->session_handler; // TODO
+    newls->ref = 2; // 1 reference is fl->next
+    
+    // create acceptor threads
+    newls->acceptors = calloc(newls->nacceptors, sizeof(void*));
+    for (int i=0;i<newls->nacceptors;i++) {
+        newls->acceptors[i] = acceptor_new(newls);
+    }
+    
+    // fl hold one reference of newls
+    fl->next = newls;
+    
+    
+    ucx_map_sstr_put(listener_map, newls->name, newls);
+    
+    for (int i=0;i<newls->nacceptors;i++) {
+        acceptor_start(newls->acceptors[i]);
+    }
+    
+    // check if a restart is required to apply all changes
+    
+    if(newls->port != conf->port) {
+        // TODO: log
+    }
+    
+    return newls;
+}
 
 HttpListener* http_listener_new(ListenerConfig *conf) {
+    // TODO: remove
     if(listener_map == NULL) {
         listener_map = ucx_map_new(16);
     }
@@ -77,6 +125,7 @@
     if(fl != NULL) {
         return fl;
     }
+    // end remove
 
     HttpListener *listener = malloc(sizeof(HttpListener));
     listener->name = conf->name;
@@ -84,6 +133,8 @@
     listener->session_handler = create_event_session_handler();
     listener->nacceptors = conf->nacceptors;
     listener->port = conf->port;
+    listener->ref = 1;
+    listener->next = NULL;
     ucx_map_sstr_put(listener_map, listener->name, listener);
 
     struct sockaddr_in servaddr;   /* server address */
@@ -140,6 +191,20 @@
     return 0;
 }
 
+void http_listener_ref(HttpListener *listener) {
+    ucx_atomic_inc_32(&listener->ref);
+}
+
+void http_listener_unref(HttpListener *listener) {
+    uint32_t ref = ucx_atomic_dec_32_nv(&listener->ref);
+    if(ref == 0) {
+        free(listener->acceptors);
+        // TODO: unref cfg
+        // TODO: unref session handler
+        free(listener);
+    }
+}
+
 
 
 Acceptor* acceptor_new(HttpListener *listener) {
@@ -178,22 +243,33 @@
             continue;
         }
         
+        // check listener
+        HttpListener *ls = listener;
+        int acceptor_exit = 0;
+        while(ls->next) {
+            ls = ls->next;
+            acceptor_exit = 1;
+        }
+        
         /* create Connection object */
         Connection *conn = malloc(sizeof(Connection));
         conn->address = ca;
         conn->fd = clientfd;
-        conn->listener = listener;
+        conn->listener = ls;
 
         /* enqueue the connection */
-        listener->session_handler->enqueue_connection(
-                listener->session_handler,
+        ls->session_handler->enqueue_connection(
+                ls->session_handler,
                 conn);
 
         /* ready for new connection */
-        if(0) {
+        if(acceptor_exit) {
             break;
         }
     }
     
+    http_listener_unref(listener->next);
+    http_listener_unref(listener);
+    
     return NULL;
 }
--- a/src/server/daemon/httplistener.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/httplistener.h	Sat Oct 06 13:00:07 2012 +0200
@@ -31,6 +31,8 @@
 
 #include "sessionhandler.h"
 
+#include "config.h"
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -45,11 +47,12 @@
     char             *vs_name;
 };
 struct _listener_config {
-    sstr_t         name;
-    sstr_t         vs;
-    char           *address;
-    int            port;
-    int            nacceptors;
+    ServerConfiguration  *cfg;
+    sstr_t               name;
+    sstr_t               vs;
+    char                 *address;
+    int                  port;
+    int                  nacceptors;
 };
 
 struct _acceptor {
@@ -58,21 +61,30 @@
 };
 
 struct _http_listener {
-    sstr_t           name;
-    union vs         default_vs;
-    int              port;
-    int              server_socket;
-    Acceptor         **acceptors;
-    int              nacceptors;
-    SessionHandler   *session_handler;
+    ServerConfiguration  *cfg;
+    sstr_t               name;
+    union vs             default_vs;
+    int                  port;
+    int                  server_socket;
+    SessionHandler       *session_handler;
+    HttpListener         *next;
+    Acceptor             **acceptors;
+    int                  nacceptors;
+    uint32_t             ref; // reference counter
 };
 
 int start_all_listener();
 
+HttpListener* http_listener_create(ListenerConfig *conf);
+
+// used by http_listener_create
 HttpListener* http_listener_new(ListenerConfig *conf);
 
 int http_listener_start(HttpListener *listener);
 
+void http_listener_ref(HttpListener *listener);
+void http_listener_unref(HttpListener *listener);
+
 Acceptor* acceptor_new(HttpListener *listener);
 
 void acceptor_start(Acceptor *a);
--- a/src/server/daemon/httprequest.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/httprequest.c	Sat Oct 06 13:00:07 2012 +0200
@@ -451,7 +451,7 @@
         }
         /* if there is a trailing '/', remove it */
         if(docroot.ptr[docroot.length - 1] == '/') {
-            docroot.ptr[docroot.length - 1] = 0; // TODO: can I do this?
+            //docroot.ptr[docroot.length - 1] = 0; // TODO: can I do this? No!!
             docroot.length--;
         }
 
--- a/src/server/daemon/sessionhandler.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/sessionhandler.c	Sat Oct 06 13:00:07 2012 +0200
@@ -211,5 +211,6 @@
         // TODO: critical error
     }
     
+    // process request
     r = handle_request(request);
 }
--- a/src/server/daemon/vserver.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/vserver.c	Sat Oct 06 13:00:07 2012 +0200
@@ -32,8 +32,20 @@
     VirtualServer *vs = malloc(sizeof(VirtualServer));
     vs->objects = NULL;
     vs->document_root = sstr("docs");
+    vs->ref = 1;
     return vs;
 }
 
+VirtualServer* vs_copy(VirtualServer *vs, pool_handle_t *pool) {
+    VirtualServer *newvs = malloc(sizeof(VirtualServer));
+    newvs->ref = 1;
+    newvs->document_root = sstrdup_pool(pool, vs->document_root);
+    newvs->host = sstrdup_pool(pool, vs->host);
+    newvs->name = sstrdup_pool(pool, vs->name);
+    newvs->objectfile = sstrdup_pool(pool, vs->objectfile);
+    
+    newvs->objects = vs->objects;
+    
+    return newvs;
+}
 
-
--- a/src/server/daemon/vserver.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/daemon/vserver.h	Sat Oct 06 13:00:07 2012 +0200
@@ -43,13 +43,16 @@
     sstr_t            host;
     // TODO: list of listeners, check listener of vs
     
+    sstr_t            objectfile;
     HTTPObjectConfig  *objects;
 
     sstr_t            document_root;
+    
+    uint32_t          ref; // reference counter
 };
 
 VirtualServer* vs_new();
-
+VirtualServer* vs_copy(VirtualServer *vs, pool_handle_t *pool);
 
 
 #ifdef	__cplusplus
--- a/src/server/safs/init.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/safs/init.c	Sat Oct 06 13:00:07 2012 +0200
@@ -72,7 +72,7 @@
             }
             struct FuncStruct fc;
             fc.func = (FuncPtr)sym;
-            fc.name = sstrdub(sstr(funcs)).ptr;
+            fc.name = sstrdup(sstr(funcs)).ptr;
             add_function(&fc);
 
             if(b) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/ucx/allocator.c	Sat Oct 06 13:00:07 2012 +0200
@@ -0,0 +1,14 @@
+#include <stdlib.h>
+#include "allocator.h"
+
+void *ucx_default_malloc(void *ignore, size_t n) {
+    return malloc(n);
+}
+
+void *ucx_default_calloc(void *ignore, size_t n, size_t size) {
+    return calloc(n, size);
+}
+
+void *ucx_default_realloc(void *ignore, void *data, size_t n) {
+    return realloc(data, n);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/ucx/allocator.h	Sat Oct 06 13:00:07 2012 +0200
@@ -0,0 +1,31 @@
+#ifndef ALLOCATOR_H
+#define	ALLOCATOR_H
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef void*(*ucx_allocator_malloc)(void *pool, size_t n);
+typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size);
+typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n);
+
+typedef struct {
+    void *pool;
+    ucx_allocator_malloc malloc;
+    ucx_allocator_calloc calloc;
+    ucx_allocator_realloc realloc;
+} UcxAllocator;
+
+void *ucx_default_malloc(void *ignore, size_t n);
+void *ucx_default_calloc(void *ignore, size_t n, size_t size);
+void *ucx_default_realloc(void *ignore, void *data, size_t n);
+
+#define UCX_ALLOCATOR_DEFAULT {NULL, \
+        ucx_default_malloc, ucx_default_calloc, ucx_default_realloc}
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* ALLOCATOR_H */
+
--- a/src/server/ucx/atomic.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/atomic.c	Sat Oct 06 13:00:07 2012 +0200
@@ -22,4 +22,34 @@
     atomic_inc_64(t);
 }
 
+void ucx_atomic_dec_8(volatile uint8_t *t) {
+    atomic_dec_8(t);
+}
 
+void ucx_atomic_dec_16(volatile uint16_t *t) {
+    atomic_dec_16(t);
+}
+
+void ucx_atomic_dec_32(volatile uint32_t *t) {
+    atomic_dec_32(t);
+}
+
+void ucx_atomic_dec_64(volatile uint64_t *t) {
+    atomic_dec_64(t);
+}
+
+uint8_t ucx_atomic_dec_8_nv(volatile uint8_t *t) {
+    return atomic_dec_8_nv(t);
+}
+
+uint16_t ucx_atomic_dec_16_nv(volatile uint16_t *t) {
+    return atomic_dec_16_nv(t);
+}
+
+uint32_t ucx_atomic_dec_32_nv(volatile uint32_t *t) {
+    return atomic_dec_32_nv(t);
+}
+
+uint64_t ucx_atomic_dec_64_nv(volatile uint64_t *t) {
+    return atomic_dec_64_nv(t);
+}
--- a/src/server/ucx/atomic.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/atomic.h	Sat Oct 06 13:00:07 2012 +0200
@@ -22,6 +22,22 @@
 
 void ucx_atomic_inc_64(volatile uint64_t *t);
 
+void ucx_atomic_dec_8(volatile uint8_t *t);
+
+void ucx_atomic_dec_16(volatile uint16_t *t);
+
+void ucx_atomic_dec_32(volatile uint32_t *t);
+
+void ucx_atomic_dec_64(volatile uint64_t *t);
+
+uint8_t ucx_atomic_dec_8_nv(volatile uint8_t *t);
+
+uint16_t ucx_atomic_dec_16_nv(volatile uint16_t *t);
+
+uint32_t ucx_atomic_dec_32_nv(volatile uint32_t *t);
+
+uint64_t ucx_atomic_dec_64_nv(volatile uint64_t *t);
+
 
 #ifdef	__cplusplus
 }
--- a/src/server/ucx/dlist.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/dlist.c	Sat Oct 06 13:00:07 2012 +0200
@@ -112,6 +112,96 @@
     return s;
 }
 
+UcxDlist *ucx_dlist_sort_merge(int length,
+        UcxDlist* ls, UcxDlist* rs, UcxDlist* le, UcxDlist* re,
+        cmp_func fnc, void* data) {
+    UcxDlist *sorted[length];
+    UcxDlist *rc, *lc;
+
+    lc = ls; rc = rs;
+    int n = 0;
+    while (lc != le && rc != re) {
+        if (fnc(lc->data, rc->data, data) <= 0) {
+            sorted[n] = lc;
+            lc = lc->next;
+        } else {
+            sorted[n] = rc;
+            rc = rc->next;
+        }
+        n++;
+    }
+    while (lc != le) {
+        sorted[n] = lc;
+        lc = lc->next;
+        n++;
+    }
+    while (rc != re) {
+        sorted[n] = rc;
+        rc = rc->next;
+        n++;
+    }
+
+    // Update pointer
+    sorted[0]->prev = NULL;
+    for (int i = 0 ; i < length-1 ; i++) {
+        sorted[i]->next = sorted[i+1];
+        sorted[i+1]->prev = sorted[i];
+    }
+    sorted[length-1]->next = NULL;
+
+    return sorted[0];
+}
+
+UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data) {
+    if (l == NULL) {
+        return NULL;
+    }
+
+    UcxDlist *lc;
+    int ln = 1;
+
+    UcxDlist *ls = l, *le;
+    lc = ls;
+    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
+        lc = lc->next;
+        ln++;
+    }
+    le = lc->next;
+
+    UcxDlist *rs = le, *re;
+    if (rs == NULL) {
+        return l; // this list is already sorted :)
+    } else {
+        UcxDlist *rc;
+        int rn = 1;
+        rc = rs;
+        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
+            rc = rc->next;
+            rn++;
+        }
+        re = rc->next;
+
+        // Something left? Sort it!
+        UcxDlist *remainder = re;
+        size_t remainder_length = ucx_dlist_size(remainder);
+        if (remainder != NULL) {
+            remainder = ucx_dlist_sort(remainder, fnc, data);
+        }
+
+        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
+        UcxDlist *sorted = ucx_dlist_sort_merge(ln+rn,
+                ls, rs, le, re,
+                fnc, data);
+
+        // merge sorted list with (also sorted) remainder
+        l = ucx_dlist_sort_merge(ln+rn+remainder_length,
+                sorted, remainder, NULL, NULL,
+                fnc, data);
+
+        return l;
+    }
+}
+
 /* dlist specific functions */
 UcxDlist *ucx_dlist_first(UcxDlist *l) {
     if (l == NULL) return NULL;
--- a/src/server/ucx/dlist.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/dlist.h	Sat Oct 06 13:00:07 2012 +0200
@@ -30,6 +30,8 @@
 UcxDlist *ucx_dlist_get(UcxDlist *l, int index);
 size_t ucx_dlist_size(UcxDlist *l);
 
+UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data);
+
 /* dlist specific functions */
 UcxDlist *ucx_dlist_first(UcxDlist *l);
 UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e);
--- a/src/server/ucx/list.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/list.c	Sat Oct 06 13:00:07 2012 +0200
@@ -25,7 +25,7 @@
         l1 = l1->next;
         l2 = l2->next;
     }
-
+    
     return (l1 == NULL && l2 == NULL);
 }
 
@@ -41,7 +41,7 @@
 UcxList *ucx_list_append(UcxList *l, void *data)  {
     UcxList *nl = (UcxList*) malloc(sizeof(UcxList));
     if (nl == NULL) return NULL;
-
+    
     nl->data = data;
     nl->next = NULL;
     if (l == NULL) {
@@ -56,7 +56,7 @@
 UcxList *ucx_list_prepend(UcxList *l, void *data) {
     UcxList *nl = ucx_list_append(NULL, data);
     if (nl == NULL) return NULL;
-
+    
     if (l != NULL) {
         nl->next = l;
     }
@@ -75,7 +75,7 @@
 
 UcxList *ucx_list_last(UcxList *l) {
     if (l == NULL) return NULL;
-
+    
     UcxList *e = l;
     while (e->next != NULL) {
         e = e->next;
@@ -91,13 +91,13 @@
         e = e->next;
         index--;
     }
-
+    
     return index == 0 ? e : NULL;
 }
 
 size_t ucx_list_size(UcxList *l) {
     if (l == NULL) return 0;
-
+    
     UcxList *e = l;
     size_t s = 1;
     while (e->next != NULL) {
@@ -108,13 +108,91 @@
     return s;
 }
 
-void ucx_list_foreach(UcxList *l, ucx_callback fnc, void* data) {
-    UcxList *e = l;
-    UcxList *n;
-    while (e != NULL) {
-        n = e->next;
-        fnc(e, data);
-        e = n;
+UcxList *ucx_list_sort_merge(int length,
+        UcxList* ls, UcxList* rs, UcxList* le, UcxList* re,
+        cmp_func fnc, void* data) {
+    UcxList *sorted[length];
+    UcxList *rc, *lc;
+
+    lc = ls; rc = rs;
+    int n = 0;
+    while (lc != le && rc != re) {
+        if (fnc(lc->data, rc->data, data) <= 0) {
+            sorted[n] = lc;
+            lc = lc->next;
+        } else {
+            sorted[n] = rc;
+            rc = rc->next;
+        }
+        n++;
+    }
+    while (lc != le) {
+        sorted[n] = lc;
+        lc = lc->next;
+        n++;
+    }
+    while (rc != re) {
+        sorted[n] = rc;
+        rc = rc->next;
+        n++;
+    }
+
+    // Update pointer
+    for (int i = 0 ; i < length-1 ; i++) {
+        sorted[i]->next = sorted[i+1];
+    }
+    sorted[length-1]->next = NULL;
+
+    return sorted[0];
+}
+
+UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) {
+    if (l == NULL) {
+        return NULL;
+    }
+
+    UcxList *lc;
+    int ln = 1;
+
+    UcxList *ls = l, *le;
+    lc = ls;
+    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
+        lc = lc->next;
+        ln++;
+    }
+    le = lc->next;
+
+    UcxList *rs = le, *re;
+    if (rs == NULL) {
+        return l; // this list is already sorted :)
+    } else {
+        UcxList *rc;
+        int rn = 1;
+        rc = rs;
+        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
+            rc = rc->next;
+            rn++;
+        }
+        re = rc->next;
+
+        // Something left? Sort it!
+        UcxList *remainder = re;
+        size_t remainder_length = ucx_list_size(remainder);
+        if (remainder != NULL) {
+            remainder = ucx_list_sort(remainder, fnc, data);
+        }
+
+        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
+        UcxList *sorted = ucx_list_sort_merge(ln+rn,
+                ls, rs, le, re,
+                fnc, data);
+
+        // merge sorted list with (also sorted) remainder
+        l = ucx_list_sort_merge(ln+rn+remainder_length,
+                sorted, remainder, NULL, NULL,
+                fnc, data);
+
+        return l;
     }
 }
 
@@ -128,7 +206,7 @@
         while (f->next != NULL && f->next != e) {
             f = f->next;
         }
-        /* perform remove iff this element is found in this list */
+        /* perform remove if this element is found in this list */
         if (f->next == e) {
             f->next = e->next;
             free(e);
--- a/src/server/ucx/list.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/list.h	Sat Oct 06 13:00:07 2012 +0200
@@ -1,5 +1,5 @@
 /*
- *
+ * 
  */
 
 #ifndef LIST_H
@@ -11,7 +11,7 @@
 #ifdef	__cplusplus
 extern "C" {
 #endif
-
+    
 typedef struct UcxList UcxList;
 struct UcxList {
     void    *data;
@@ -28,7 +28,8 @@
 UcxList *ucx_list_last(UcxList *l);
 UcxList *ucx_list_get(UcxList *l, int index);
 size_t ucx_list_size(UcxList *l);
-void ucx_list_foreach(UcxList *l, ucx_callback fnc, void *data);
+
+UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data);
 
 /* list specific functions */
 UcxList *ucx_list_remove(UcxList *l, UcxList *e);
--- a/src/server/ucx/map.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/map.c	Sat Oct 06 13:00:07 2012 +0200
@@ -8,6 +8,10 @@
 #include "map.h"
 
 UcxMap *ucx_map_new(size_t size) {
+    if(size == 0) {
+        size = 16;
+    }
+    
     UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap));
     if(map == NULL) {
         return NULL;
@@ -19,6 +23,7 @@
         return NULL;
     }
     map->size = size;
+    map->count = 0;
 
     return map;
 }
@@ -39,6 +44,48 @@
     free(map);
 }
 
+int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data) {
+    UcxMapIterator i = ucx_map_iterator(from);
+    void *value;
+    UCX_MAP_FOREACH(value, i) {
+        int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value);
+        if(ret != 0) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) {
+    size_t bs = (map->count * 5) >> 1;
+    UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size);
+    if(newmap == NULL) {
+        return NULL;
+    }
+    ucx_map_copy(map, newmap, fnc, data);
+    return newmap;
+}
+
+int ucx_map_rehash(UcxMap *map) {
+    size_t load = (map->size * 3) >> 2;
+    if (map->count > load) {
+        UcxMap oldmap;
+        oldmap.map = map->map;
+        oldmap.size = map->size;
+        oldmap.count = map->count;
+        
+        map->size = (map->count * 5) >> 1;
+        map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*));
+        if(map->map == NULL) {
+            *map = oldmap;
+            return 1;
+        }
+        map->count = 0;
+        ucx_map_copy(&oldmap, map, NULL, NULL);
+    }
+    return 0;
+}
+
 int ucx_map_put(UcxMap *map, UcxKey key, void *data) {
     if(key.hash == 0) {
         key.hash = ucx_hash((char*)key.data, key.len);
@@ -76,6 +123,7 @@
         memcpy(kd, key.data, key.len);
         key.data = kd;
         elm->key = key;
+        map->count++;
     }
     elm->data = data;
 
@@ -138,8 +186,11 @@
 
     switch (len) {
         case 3: h ^= (data[i + 2] & 0xFF) << 16;
+        /* no break */
         case 2: h ^= (data[i + 1] & 0xFF) << 8;
+        /* no break */
         case 1: h ^= (data[i + 0] & 0xFF); h *= m;
+        /* no break */
     }
 
     h ^= h >> 13;
@@ -186,3 +237,124 @@
     
     return 1;
 }
+
+int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
+        ucx_map_coder decoder, void* decdata) {
+
+    int c; int r, n;
+
+    char *key, *value;
+
+    while ((c = fgetc(f)) > 0) {
+        /* Discard leading spaces and comments */
+        if (c < 33) continue;
+        if (c == '#' || c == '!') {
+            while ((c = (char) fgetc(f)) > 0) {
+                if (c == '\n') break;
+            }
+            continue;
+        }
+
+        /* read into key buffer */
+        n = 16;
+        key = malloc(n);
+        r = 0;
+        do {
+            if (c == '=') break;
+            if (r > n - 2) {
+                n *= 2;
+                key = realloc(key, n);
+            }
+            key[r] = c;
+            r++;
+        } while ((c = fgetc(f)) > 0);
+        if (c <= 0) {
+            free(key);
+            return 1;
+        }
+        key[r] = 0;
+        while (key[--r] == ' ') key[r] = 0;
+
+        /* skip whitespaces */
+        while ((c = fgetc(f)) > 0) {
+            if (c > 32) break;
+        }
+        if (c <= 0) {
+            free(key);
+            return 1;
+        }
+
+        /* read into value buffer */
+        n = 64;
+        value = malloc(n);
+        r = 0;
+        do {
+            if (c == '\n') break;
+            if (r > n - 2) {
+                n *= 2;
+                value = realloc(value, n);
+            }
+            value[r] = c;
+            r++;
+        } while ((c = fgetc(f)) > 0);
+        value[r] = 0;
+        while (value[--r] < 33) value[r] = 0;
+
+        if (decoder) {
+            size_t decodedSize;
+            void *decoded = decoder(value, decdata, &decodedSize);
+            free(value);
+            value = decoded;
+            r = decodedSize;
+        } else {
+            r += 2;
+            value = realloc(value, r);
+        }
+
+        if (allocator.pool) {
+            void *pooledValue = allocator.malloc(allocator.pool, r);
+            memcpy(pooledValue, value, r);
+            free(value);
+            value = pooledValue;
+        }
+
+        ucx_map_cstr_put(map, key, value);
+        free(key);
+    }
+
+    return 0;
+}
+
+int ucx_map_store_enc(UcxMap *map, FILE *f,
+        ucx_map_coder encoder, void *encdata) {
+    UcxMapIterator iter = ucx_map_iterator(map);
+    char *k, *v;
+    sstr_t key, value;
+    int written;
+
+    UCX_MAP_FOREACH(v, iter) {
+        k = (char*) iter.cur->key.data;
+        key = sstr(k);
+        if (encoder) {
+            size_t encodedSize;
+            void *encoded = encoder(v, encdata, &encodedSize);
+            value = sstrn(encoded,encodedSize - 1);
+        } else {
+            value = sstr(v);
+        }
+
+        written = 0;
+        written += fwrite(key.ptr, 1, key.length, f);
+        written += fwrite(" = ", 1, 3, f);
+        written += fwrite(value.ptr, 1, value.length, f);
+        written += fwrite("\n", 1, 1, f);
+
+        if (encoder) {
+            free(value.ptr);
+        }
+
+        if (written != key.length + value.length + 4) return 1;
+    }
+
+    return 0;
+}
--- a/src/server/ucx/map.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/map.h	Sat Oct 06 13:00:07 2012 +0200
@@ -7,22 +7,33 @@
 
 #include "ucx.h"
 #include "string.h"
+#include "mempool.h"
+#include <stdio.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#define UCX_MAP_FOREACH(type,elm,map,iter) \
-        for(type elm;ucx_map_iter_next(&iter,(void*)&elm)==0;)
+#define UCX_MAP_FOREACH(elm,iter) \
+        for(;ucx_map_iter_next(&iter,(void*)&elm)==0;)
 
 typedef struct UcxMap          UcxMap;
 typedef struct UcxKey          UcxKey;
 typedef struct UcxMapElement   UcxMapElement;
 typedef struct UcxMapIterator  UcxMapIterator;
 
+/*
+ * param 1: element
+ * param 2: additional data
+ * param 3: size of encoded data will be stored here
+ * returns encoded / decoded string or NULL on failure
+ */
+typedef void*(*ucx_map_coder)(void*,void*,size_t*);
+
 struct UcxMap {
     UcxMapElement **map;
     size_t        size;
+    size_t        count;
 };
 
 struct UcxKey {
@@ -46,6 +57,10 @@
 
 UcxMap *ucx_map_new(size_t size);
 void ucx_map_free(UcxMap *map);
+/* you cannot clone maps with more than 390 mio entries */
+int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data);
+UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data);
+int ucx_map_rehash(UcxMap *map);
 
 int ucx_map_put(UcxMap *map, UcxKey key, void *data);
 void* ucx_map_get(UcxMap *map, UcxKey key);
@@ -63,6 +78,16 @@
 
 int ucx_map_iter_next(UcxMapIterator *i, void **elm);
 
+/* use macros for string maps only, values are not encoded */
+#define ucx_map_load(map, f, alloc) ucx_map_load_enc(map, f, alloc, NULL, NULL)
+#define ucx_map_store(map, f) ucx_map_store_enc(map, f, NULL, NULL)
+
+int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator,
+        ucx_map_coder decoder, void* decdata);
+/* encoders shall provide null terminated strings*/
+int ucx_map_store_enc(UcxMap *map, FILE *f,
+        ucx_map_coder encoder, void* encdata);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/src/server/ucx/mempool.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/mempool.h	Sat Oct 06 13:00:07 2012 +0200
@@ -5,6 +5,9 @@
 #ifndef MPOOL_H
 #define	MPOOL_H
 
+#include <stddef.h>
+#include "allocator.h"
+
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -17,6 +20,11 @@
     size_t size;
 } UcxMempool;
 
+#define UCX_ALLOCATOR_MEMPOOL(pool) {pool, \
+    (ucx_allocator_malloc) ucx_mempool_malloc, \
+    (ucx_allocator_calloc) ucx_mempool_calloc, \
+    (ucx_allocator_realloc) ucx_mempool_realloc}
+
 #define ucx_mempool_new_default() ucx_mempool_new(16)
 UcxMempool *ucx_mempool_new(size_t n);
 int ucx_mempool_chcap(UcxMempool *pool, size_t newcap);
--- a/src/server/ucx/objs.mk	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/objs.mk	Sat Oct 06 13:00:07 2012 +0200
@@ -36,6 +36,7 @@
 UCXOBJ += mempool.o
 UCXOBJ += string.o
 UCXOBJ += atomic.o
+UCXOBJ += allocator.o
 
 UCXOBJS = $(UCXOBJ:%=$(UCX_OBJPRE)%)
 UCXSOURCE = $(UCXOBJ:%.o=ucx/%.c)
--- a/src/server/ucx/string.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/string.c	Sat Oct 06 13:00:07 2012 +0200
@@ -6,11 +6,10 @@
  */
 
 #include <stdlib.h>
-#include <string.h>
+#include <strings.h>
 #include <stdarg.h>
 
 #include "string.h"
-#include "mempool.h"
 
 sstr_t sstr (char *s) {
     sstr_t string;
@@ -35,6 +34,7 @@
         sstr_t str = va_arg(ap, sstr_t);
         size += str.length;
     }
+    va_end(ap);
 
     return size;
 }
@@ -49,6 +49,7 @@
         s.ptr = strncat (s.ptr, str.ptr, s.length);
         str = va_arg (ap, sstr_t);
     }
+    va_end(ap);
 
     return s;
 }
@@ -57,12 +58,26 @@
     va_list ap;
     va_start(ap, c1);
     s.ptr[0] = 0;
-
-    s.ptr = strncat (s.ptr, c1.ptr, s.length);
+    
+    size_t len = s.length;
+    size_t cplen = c1.length > len ? len : c1.length;
+    char   *ptr = s.ptr;
+    
+    memcpy(ptr, c1.ptr, cplen);
+    len -= cplen;
+    ptr += cplen;
     for (int i=0;i<n-1;i++) {
         sstr_t str = va_arg (ap, sstr_t);
-        s.ptr = strncat (s.ptr, str.ptr, s.length);
+        cplen = str.length > len ? len : str.length;
+        if(cplen <= 0) {
+            va_end(ap);
+            return s;
+        }
+        memcpy(ptr, str.ptr, cplen);
+        len -= cplen;
+        ptr += cplen;
     }
+    va_end(ap);
 
     return s;
 }
@@ -84,29 +99,76 @@
     return new_sstr;
 }
 
-int sstrcmp(sstr_t s1, sstr_t s2) {
-    return memcmp(s1.ptr, s2.ptr, s1.length>s2.length ? s2.length: s1.length);
+sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) {
+    if (d.length == 0) {
+        return NULL;
+    }
+
+    sstr_t* result;
+    size_t nmax = *n;
+    *n = 1;
+
+    /* special case: exact match - no processing needed */
+    if (s.length == d.length && strncmp(s.ptr, d.ptr, s.length) == 0) {
+        result = malloc(sizeof(sstr_t));
+        result[0] = sstrn("", 0);
+        return result;
+    }
+    sstr_t sv = sstrdup(s);
+
+    for (int i = 0 ; i < s.length ; i++) {
+        if (sv.ptr[i] == d.ptr[0]) {
+            _Bool match = 1;
+            for (int j = 1 ; j < d.length ; j++) {
+                if (j+i < s.length) {
+                    match &= (sv.ptr[i+j] == d.ptr[j]);
+                } else {
+                    match = 0;
+                    break;
+                }
+            }
+            if (match) {
+                (*n)++;
+                for (int j = 0 ; j < d.length ; j++) {
+                    sv.ptr[i+j] = 0;
+                }
+                i += d.length;
+            }
+        }
+        if ((*n) == nmax) break;
+    }
+    result = malloc(sizeof(sstr_t) * (*n));
+
+    char *pptr = sv.ptr;
+    for (int i = 0 ; i < *n ; i++) {
+        size_t l = strlen(pptr);
+        char* ptr = malloc(l + 1);
+        memcpy(ptr, pptr, l);
+        ptr[l] = 0;
+
+        result[i] = sstrn(ptr, l);
+        pptr += l + d.length;
+    }
+
+    free(sv.ptr);
+
+    return result;
 }
 
-sstr_t sstrdub(sstr_t s) {
-    sstr_t newstring;
-    newstring.ptr = malloc(s.length + 1);
-    newstring.length = s.length;
-    newstring.ptr[newstring.length] = 0;
-
-    memcpy(newstring.ptr, s.ptr, s.length);
-    
-    return newstring;
+int sstrcmp(sstr_t s1, sstr_t s2) {
+    return strncmp(s1.ptr, s2.ptr, s1.length>s2.length ? s2.length: s1.length);
 }
 
 sstr_t sstrdup(sstr_t s) {
     sstr_t newstring;
-    newstring.ptr = malloc(s.length + 1);
-    newstring.length = s.length;
-    newstring.ptr[newstring.length] = 0;
+    newstring.ptr = (char*) malloc(s.length + 1);
+    if (newstring.ptr != NULL) {
+        newstring.length = s.length;
+        newstring.ptr[newstring.length] = 0;
 
-    memcpy(newstring.ptr, s.ptr, s.length);
-    
+        memcpy(newstring.ptr, s.ptr, s.length);
+    }
+
     return newstring;
 }
 
@@ -135,15 +197,28 @@
     return newstr;
 }
 
-sstr_t sstrdup_mp(UcxMempool *mp, sstr_t s) {
+sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s) {
     sstr_t newstring;
-    newstring.ptr = ucx_mempool_malloc(mp, s.length + 1);
-    newstring.length = s.length;
-    newstring.ptr[newstring.length] = 0;
+    newstring.ptr = (char*)ucx_mempool_malloc(pool, s.length + 1);
+    if (newstring.ptr != NULL) {
+        newstring.length = s.length;
+        newstring.ptr[newstring.length] = 0;
 
-    /* TODO: sometimes memcpy and/or memmove destroy the source */
-    memcpy(newstring.ptr, s.ptr, s.length);
+        memcpy(newstring.ptr, s.ptr, s.length);
+    }
 
     return newstring;
 }
 
+sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s) {
+    sstr_t newstring;
+    newstring.ptr = (char*)pool_malloc(pool, s.length + 1);
+    if (newstring.ptr != NULL) {
+        newstring.length = s.length;
+        newstring.ptr[newstring.length] = 0;
+
+        memcpy(newstring.ptr, s.ptr, s.length);
+    }
+
+    return newstring;
+}
--- a/src/server/ucx/string.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/string.h	Sat Oct 06 13:00:07 2012 +0200
@@ -8,8 +8,12 @@
 #ifndef _SSTRING_H
 #define	_SSTRING_H
 
+#include <stddef.h>
+
 #include "mempool.h"
+#include "../util/pool.h"
 
+/* use macros for literals only */
 #define S(s) { s, sizeof(s)-1 }
 #define ST(s) sstrn(s, sizeof(s)-1)
 
@@ -66,16 +70,34 @@
 /*
  *
  */
-sstr_t sstrsubsl (sstr_t s, size_t start, size_t end);
+sstr_t sstrsubsl (sstr_t s, size_t start, size_t length);
 
+/*
+ * splits s into n parts
+ *
+ * s    the string to split
+ * d    the delimiter string
+ * n    the maximum size of the resulting list
+ *      a size of 0 indicates an unbounded list size
+ *      the actual size of the list will be stored here
+ *
+ *      Hint: use this value to avoid dynamic reallocation of the result list
+ *
+ * Returns a list of the split strings
+ * NOTE: this list needs to be freed manually after usage
+ *
+ * Returns NULL on error
+ */
+sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n);
 
 int sstrcmp(sstr_t s1, sstr_t s2);
 
-sstr_t sstrdub(sstr_t s);
 sstr_t sstrdup(sstr_t s);
 
+// webserver extension
 sstr_t sstrtrim(sstr_t string);
-sstr_t sstrdup_mp(UcxMempool *mp, sstr_t s);
+sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s);
+sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s);
 
 #ifdef	__cplusplus
 }
--- a/src/server/ucx/ucx.h	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/ucx/ucx.h	Sat Oct 06 13:00:07 2012 +0200
@@ -17,9 +17,6 @@
 #define UCX_FOREACH(type,list,elem) \
         for (type elem = list ; elem != NULL ; elem = elem->next)
     
-/* source,data -> errno */
-typedef int(*ucx_callback)(void*,void*);
-
 /* element1,element2,custom data -> {-1,0,1} */
 typedef int(*cmp_func)(void*,void*,void*);
 
--- a/src/server/webdav/webdav.c	Sat Aug 18 11:39:34 2012 +0200
+++ b/src/server/webdav/webdav.c	Sat Oct 06 13:00:07 2012 +0200
@@ -417,7 +417,7 @@
 }
 
 void dav_resource_response(PropfindRequest *davrq, sstr_t path, sstr_t uri) {
-    printf("dav_resource_response %s %s\n", sstrdub(path).ptr, sstrdub(uri).ptr);
+    printf("dav_resource_response %s %s\n", sstrdup(path).ptr, sstrdup(uri).ptr);
     
     sbuf_puts(davrq->out, "<D:response>\n");
     sbuf_puts(davrq->out, "<D:href>");
@@ -675,7 +675,8 @@
     }
     
     UcxMapIterator iter = ucx_map_iterator(propstat->map);
-    UCX_MAP_FOREACH(UcxDlist*, proplist, propstat->map, iter) { 
+    UcxDlist *proplist;
+    UCX_MAP_FOREACH(proplist, iter) { 
         if(proplist) {
             sbuf_puts(out, "<D:propstat>\n<D:prop>\n");
             

mercurial