src/server/daemon/config.c

Mon, 23 Jul 2012 15:13:19 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 23 Jul 2012 15:13:19 +0200
changeset 32
ebba53de8b18
parent 31
280250e45ba6
child 33
96dbfe4f91e5
permissions
-rw-r--r--

added solaris 10 support

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2011 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 "../public/nsapi.h"

#include <stdio.h>
#include <stdlib.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/mman.h>

#include "../ucx/string.h"

#include "httplistener.h"
#include "config.h"
#include "func.h"
#include "log.h"
#include "event.h"
#include "threadpools.h"
#include "configmanager.h"

#include "vserver.h"
#include "../util/pblock.h"
#include "../util/util.h"

pool_handle_t *cfg_pool;

// TODO: Funktion für ConfigDirective -> directive
// TODO: Funktion für UcxList parameter list -> pblock

void load_init_conf(char *file) {
    printf("load_init_conf\n");

    InitConfig *cfg = load_init_config(file);
    if(cfg == NULL) {
        return;
    }

    cfg_pool = pool_create(); // one pool for one Configuration
    UcxDlist *dirs = cfg->directives;
    while(dirs != NULL) {
        ConfigDirective *dir = dirs->data;

        /* create NSAPI directive */
        directive *d = malloc(sizeof(directive));
        d->param = pblock_create_pool(cfg_pool, 8);
        UcxList *param = dir->param;
        while(param != NULL) {
            ConfigParam *p = param->data;
            pblock_nvlinsert(
                    p->name.ptr,
                    p->name.length,
                    p->value.ptr,
                    p->value.length,
                    d->param);
            
            param = param->next;
        }

        /* get function */
        char *func_name = pblock_findval("fn", d->param);
        d->func = get_function(func_name);
        if(d->func == NULL) {
            free(d);
            dirs = dirs->next;
            continue;
        }

        /* execute init directive */
        d->func->func(d->param, NULL, NULL);

        dirs = dirs->next;
    }
    
    free_init_config(cfg);
}

ServerConfiguration* load_server_conf(ServerConfiguration *old, char *file) {
    printf("load_server_conf\n");

    ServerConfig *serverconf = load_server_config(file);
    if(serverconf == NULL) {
        fprintf(stderr, "Cannot load server.conf\n");
    }
    ServerConfiguration *serverconfig = malloc(sizeof(ServerConfiguration));
    serverconfig->pool = pool_create();
    serverconfig->listeners = NULL;
    serverconfig->host_vs = ucx_map_new(16);
    // TODO: init serverconfig stuff
    
    /* init logfile first */
    UcxList *lfl= ucx_map_sstr_get(serverconf->objects, sstrn("LogFile", 7));
    if(lfl != NULL) {
        ServerConfigObject *logobj = lfl->data;
        if(logobj == NULL) {
            /* error */
            return NULL;
        }
        
        int ret = cfg_handle_logfile(serverconfig, logobj);
        if(ret != 0) {
            /* cannot initialize log file */
            return NULL;
        }
    } else {
        /* horrible error */
        return NULL;
    }
    
    /* convert ServerConfig to ServerConfiguration */
    UcxMapIterator iter = ucx_map_iterator(serverconf->objects);
    UCX_MAP_FOREACH(UcxList*, list, serverconf->objects, iter) {
        UCX_FOREACH(UcxList*, list, elm) {
            
            ServerConfigObject *scfgobj = elm->data;
            
            /* handle config object */
            int hr = 0;
            if(!sstrcmp(scfgobj->type, sstr("Runtime"))) {
                hr = cfg_handle_runtime(serverconfig, scfgobj);
            } else if(!sstrcmp(scfgobj->type, sstr("EventHandler"))) {
                hr = cfg_handle_eventhandler(serverconfig, scfgobj);
            } else if(!sstrcmp(scfgobj->type, sstr("AuthDB"))) {
                hr = cfg_handle_authdb(serverconfig, scfgobj);
            } else if(!sstrcmp(scfgobj->type, sstr("Listener"))) {
                hr = cfg_handle_listener(serverconfig, scfgobj);
            } else if(!sstrcmp(scfgobj->type, sstr("VirtualServer"))) {
                hr = cfg_handle_vs(serverconfig, scfgobj);
            }


            /* next object */
            list = list->next;
        }
    }

    /* check event handler config */
    if(check_event_handler_cfg() != 0) {
        /* critical error */
        return NULL;
    }
    
    /* check thread pool config */
    if(check_thread_pool_cfg() != 0) {
        /* critical error */
        return NULL;
    }

    /* 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;
        iter = ucx_map_iterator(serverconfig->host_vs);
        UCX_MAP_FOREACH(VirtualServer*, vs, serverconfig->host_vs, iter) {
            if(!sstrcmp(vsname, vs->name)) {
                listener->default_vs.vs = vs;
                break;
            }
        }

        ls = ls->next;
    }

    return serverconfig;
}


void init_server_config_parser() {
    
}

int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) {
    cfg->user = sstrdub(cfg_directivelist_get_str(
            obj->directives,
            sstr("User")));
    cfg->tmp = sstrdub(cfg_directivelist_get_str(
            obj->directives,
            sstr("Temp")));

    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"));
    
    if(file.ptr == NULL || lvl.ptr == NULL) {
        /* missing log file parameters */
        return -1;
    }
    
    LogConfig logcfg;
    logcfg.file = sstrdup(file).ptr;
    logcfg.level = sstrdub(lvl).ptr;
    /* TODO: stdout, stderr config */
    
    int ret = init_log_file(&logcfg);
    
    free(logcfg.file);
    free(logcfg.level);

    return ret;
}

int cfg_handle_eventhandler(ServerConfiguration *c, ServerConfigObject *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"));
    
    evcfg.name = name;
    
    sstr_t s = sstrdup(threads);
    evcfg.nthreads = atoi(s.ptr);
    free(s.ptr);
    
    evcfg.isdefault = util_getboolean(isdefault.ptr, 0);
    
    int ret = create_event_handler(&evcfg);
    
    return ret;
}

int cfg_handle_authdb(ServerConfiguration *cfg, ServerConfigObject *obj) {
    /* TODO: authdb*/

    return 0;
}

int cfg_handle_listener(ServerConfiguration *cfg, ServerConfigObject *obj) {
    ListenerConfig lc;
    lc.port = 8080;
    lc.nacceptors = 1;

    lc.name = sstrdub(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(
            obj->directives,
            sstr("DefaultVS")));
    

    HttpListener *listener = http_listener_new(&lc);
    listener->default_vs.vs_name = lc.vs.ptr;
    cfg->listeners = ucx_list_append(cfg->listeners, listener); 

    return 0;
}

int cfg_handle_vs(ServerConfiguration *cfg, ServerConfigObject *obj) {
    VirtualServer *vs = vs_new();

    vs->name = sstrdub(cfg_directivelist_get_str(
            obj->directives,
            sstr("Name")));
    vs->host = sstrdub(cfg_directivelist_get_str(
            obj->directives,
            sstr("Host")));
    vs->document_root = sstrdub(cfg_directivelist_get_str(
            obj->directives,
            sstr("DocRoot")));
    sstr_t objfile = cfg_directivelist_get_str(
            obj->directives,
            sstr("ObjectFile"));
    sstr_t base = sstr("conf/");
    sstr_t file;
    file.length = base.length + objfile.length + 1;
    file.ptr = alloca(file.length);
    file.ptr[file.length] = 0;
    file = sstrncat(2, file, base, objfile);

    ConfigFile *f = cfgmgr_get_file(file);
    if(f == NULL) {
        f = malloc(sizeof(ConfigFile));
        f->file = sstrdub(file);
        f->reload = object_conf_reload;
        f->reload(f, cfg);
        cfgmgr_attach_file(f);
    }
    vs->objects = (HTTPObjectConfig*)f->data;

    ucx_map_sstr_put(cfg->host_vs, vs->host, vs);
    
    return 0;
}


int object_conf_reload(ConfigFile *file, ServerConfiguration *cfg) {
    file->data = load_obj_conf(file->file.ptr);
    struct stat s;
    if(stat(file->file.ptr, &s) != 0) {
        perror("object_conf_reload: stat");
        return -1;
    }
    file->last_modified = s.st_mtim.tv_sec;
    return 0;
}

HTTPObjectConfig* load_obj_conf(char *file) {
    printf("load_obj_conf\n");

    // new conf function test
    ObjectConfig *cfg = load_object_config(file);
    if(cfg == NULL) {
        return NULL;
    }

    /* create object config */
    HTTPObjectConfig *conf = calloc(sizeof(HTTPObjectConfig), 1);
    conf->pool = pool_create();

    /* convert ObjectConfig to HTTPObjectConfig */

    /* add objects */
    conf->nobj = ucx_dlist_size(cfg->objects);
    conf->objects = calloc(1, sizeof(httpd_object*));
    
    UcxDlist *objlist = cfg->objects;
    int i = 0;
    while(objlist != NULL) {
        ConfigObject *cob = objlist->data;

        /* get name and ppath */
        char *name = NULL;
        char *ppath = NULL;
        if(cob->name.length > 0) {
            name = sstrdub(cob->name).ptr;
        }
        if(cob->ppath.length > 0) {
            ppath = sstrdub(cob->ppath).ptr;
        }

        /* create and add object */
        httpd_object *obj = object_new(name);
        obj->path = NULL;

        conf->objects[i] = obj; // TODO: beyond array bounds write

        /* add directives */
        for(int i=0;i<6;i++) {
            UcxDlist *dirs = cob->directives[i];
            while(dirs != NULL) {
                ConfigDirective *cfgdir = dirs->data;

                directive *d = malloc(sizeof(directive));
                d->cond = NULL;
                d->param = pblock_create_pool(conf->pool, 8);

                /* add params */
                UcxList *param = cfgdir->param;
                while(param != NULL) {
                    ConfigParam *p = param->data;
                    pblock_nvlinsert(
                            p->name.ptr,
                            p->name.length,
                            p->value.ptr,
                            p->value.length,
                            d->param);
                    param = param->next;
                }

                /* get function */
                char *func_name = pblock_findval("fn", d->param);
                d->func = get_function(func_name);

                dirs = dirs->next;

                /* add function to dtable */
                object_add_directive(obj, d, cfgdir->type_num);
            }
        }

        /* next */
        i++;
        objlist = objlist->next;
    }

    free_object_config(cfg);

    return conf;
}

mercurial