Esempio n. 1
0
Host *Host_create(bstring name, bstring matching)
{
    if(!MAX_URL_PATH || !MAX_HOST_NAME) {
        MAX_URL_PATH = Setting_get_int("limits.url_path", 256);
        MAX_HOST_NAME = Setting_get_int("limits.host_name", 256);
        log_info("MAX limits.url_path=%d, limits.host_name=%d",
                MAX_URL_PATH, MAX_HOST_NAME);
    }

    Host *host = h_calloc(sizeof(Host), 1);
    check_mem(host);

    host->name = bstrcpy(name);
    check(blength(host->name) < MAX_HOST_NAME, "Host name too long (max %d): '%s'\n", 
            MAX_HOST_NAME, bdata(name));

    host->matching = bstrcpy(matching);

    check(blength(host->matching) < MAX_HOST_NAME, "Host matching pattern too long (max %d): '%s'\n", 
            MAX_HOST_NAME, bdata(name));

    host->routes = RouteMap_create(backend_destroy_cb);
    check(host->routes, "Failed to create host route map for %s.", bdata(name));
    
    return host;

error:
    return NULL;
}
Esempio n. 2
0
void tickertask(void *v)
{
    (void)v;

    taskname("ticker");

    while(!task_was_signaled()) {
        THE_CURRENT_TIME_IS = time(NULL);

        int min_wait = Setting_get_int("limits.tick_timer", 10);
        taskdelay(min_wait * 1000);

        // avoid doing this during a reload attempt
        if(!RELOAD) {
            // don't bother if these are all 0
            int min_ping = Setting_get_int("limits.min_ping", DEFAULT_MIN_PING);
            int min_write_rate = Setting_get_int("limits.min_write_rate", DEFAULT_MIN_READ_RATE);
            int min_read_rate = Setting_get_int("limits.min_read_rate", DEFAULT_MIN_WRITE_RATE);

            if(min_ping > 0 || min_write_rate > 0 || min_read_rate > 0) {
                int cleared = Register_cleanout();

                if(cleared > 0) {
                    log_warn("Timeout task killed %d tasks, waiting %d seconds for more.", cleared, min_wait);
                } else {
                    debug("No connections timed out.");
                }
            }

            // do a server queue cleanup to get rid of dead servers
            Server_queue_cleanup();
        }
    }
}
Esempio n. 3
0
Dir *Dir_create(const char *base, const char *index_file, const char *default_ctype)
{
    Dir *dir = calloc(sizeof(Dir), 1);
    check_mem(dir);

    if(!MAX_SEND_BUFFER || !MAX_DIR_PATH) {
        MAX_SEND_BUFFER = Setting_get_int("limits.dir_send_buffer", 16 * 1024);
        MAX_DIR_PATH = Setting_get_int("limits.dir_max_path", 256);
        log_info("MAX limits.dir_send_buffer=%d, limits.dir_max_path=%d",
                MAX_SEND_BUFFER, MAX_DIR_PATH);
    }

    dir->base = bfromcstr(base);
    check(blength(dir->base) < MAX_DIR_PATH, "Base directory is too long, must be less than %d", MAX_DIR_PATH);
    check(bchar(dir->base, 0) != '/', "Don't start the base with / in %s, that will fail when not in chroot.", base);
    check(bchar(dir->base, blength(dir->base) - 1) == '/', "End directory base with / in %s or it won't work right.", base);

    dir->index_file = bfromcstr(index_file);
    dir->default_ctype = bfromcstr(default_ctype);

    dir->fr_cache = Cache_create(FR_CACHE_SIZE, filerecord_cache_lookup,
                                 filerecord_cache_evict);
    check(dir->fr_cache, "Failed to create FileRecord cache");

    return dir;

error:
    if(dir)
        free(dir);

    return NULL;
}
Esempio n. 4
0
int Register_cleanout()
{
    int i = 0;
    int nkilled = 0;
    int nscanned = 0;
    time_t now = THE_CURRENT_TIME_IS;
    int min_ping = Setting_get_int("limits.min_ping", DEFAULT_MIN_PING);
    int min_write_rate = Setting_get_int("limits.min_write_rate", DEFAULT_MIN_READ_RATE);
    int min_read_rate = Setting_get_int("limits.min_read_rate", DEFAULT_MIN_WRITE_RATE);
    int kill_limit = Setting_get_int("limits.kill_limit", DEFAULT_KILL_LIMIT);

    for(i = 0, nscanned = 0; i < darray_max(REGISTRATIONS) && nscanned < NUM_REG_FD; i++) {
        Registration *reg = darray_get(REGISTRATIONS, i);

        if(Register_valid(reg)) {
            nscanned++; // avoid scanning the whole array if we've found them all

            int last_ping = ZERO_OR_DELTA(now, reg->last_ping);
            off_t read_rate = reg->bytes_read / (ZERO_OR_DELTA(now, reg->last_read) + 1);
            off_t write_rate = reg->bytes_written / (ZERO_OR_DELTA(now, reg->last_write) + 1);
            int should_kill = 0;

            debug("Checking fd=%d:conn_id=%d against last_ping: %d, read_rate: %d, write_rate: %d",
                    i, reg->id, last_ping, read_rate, write_rate);

            // these are weighted so they are not if-else statements
            if(min_ping != 0 && last_ping > min_ping) {
                debug("Connection fd=%d:conn_id=%d over limits.min_ping time: %d < %d",
                        i, reg->id, min_ping, last_ping);
                should_kill++;
            }
            
            if(min_read_rate != 0 && read_rate < min_read_rate) {
                debug("Connection fd=%d:conn_id=%d read rate lower than allowed: %d < %d",
                        i, reg->id, read_rate, min_read_rate);
                should_kill++;
            } 

            if(min_write_rate != 0 && write_rate < min_write_rate) {
                debug("Connection fd=%d:conn_id=%d write rate lower than allowed: %d < %d",
                        i, reg->id, write_rate, min_write_rate);
                should_kill++;
            }

            if(should_kill > kill_limit) {
                nkilled++;
                Register_disconnect(i);
            }
        }
    }

    if(nkilled) {
        log_warn("Killed %d connections according to min_ping: %d, min_write_rate: %d, min_read_rate: %d", nkilled, min_ping, min_write_rate, min_read_rate);
    }

    return nkilled;
}
Esempio n. 5
0
Handler *Handler_create(bstring send_spec, bstring send_ident,
        bstring recv_spec, bstring recv_ident)
{
    debug("Creating handler %s:%s", bdata(send_spec), bdata(send_ident));

    if(!HANDLER_STACK) {
        HANDLER_STACK = Setting_get_int("limits.handler_stack", DEFAULT_HANDLER_STACK);
        log_info("MAX limits.handler_stack=%d", HANDLER_STACK);
    }

    Handler *handler = calloc(sizeof(Handler), 1);
    check_mem(handler);

    handler->send_ident = bstrcpy(send_ident);
    handler->recv_ident = bstrcpy(recv_ident);
    handler->recv_spec = bstrcpy(recv_spec);
    handler->send_spec = bstrcpy(send_spec);
    handler->running = 0;
    handler->raw = 0;
    handler->protocol = HANDLER_PROTO_JSON;

    return handler;
error:

    if(handler) free(handler);
    return NULL;
}
Esempio n. 6
0
Handler *Handler_create(const char *send_spec, const char *send_ident,
        const char *recv_spec, const char *recv_ident)
{
    debug("Creating handler %s:%s", send_spec, send_ident);

    if(!HANDLER_STACK) {
        HANDLER_STACK = Setting_get_int("limits.handler_stack", 100 * 1024);
        log_info("MAX limits.handler_stack=%d", HANDLER_STACK);
    }

    Handler *handler = calloc(sizeof(Handler), 1);
    check_mem(handler);

    handler->send_ident = bfromcstr(send_ident);
    handler->recv_ident = bfromcstr(recv_ident);
    handler->recv_spec = bfromcstr(recv_spec);
    handler->send_spec = bfromcstr(send_spec);
    handler->running = 0;
    handler->raw = 0;

    return handler;
error:

    if(handler) free(handler);
    return NULL;
}
Esempio n. 7
0
int MIME_add_type(const char *ext, const char *type)
{
    if(!MAX_EXT_LEN) {
        MAX_EXT_LEN = Setting_get_int("limits.mime_ext_len", 128);
        log_info("MAX limits.mime_ext_len=%d", MAX_EXT_LEN);
    }

    bstring ext_rev = bfromcstr(ext);
    bReverse(ext_rev);
    bstring type_str = bfromcstr(type);

    check(blength(ext_rev) > 0, "No zero length MIME extensions allowed: %s:%s", ext, type);
    check(blength(type_str) > 0, "No zero length MIME types allowed: %s:%s", ext, type);
    check(ext[0] == '.', "Extensions must start with a . '%s:%s'", ext, type);

    check(blength(ext_rev) < MAX_EXT_LEN, "MIME extension %s:%s is longer than %d MAX (it's %d)", ext, type, MAX_EXT_LEN, blength(ext_rev));

    check(!tst_search(MIME_MAP, bdata(ext_rev), blength(ext_rev)), 
            "MIME extension %s already exists, can't add %s:%s",
            ext, ext, type);

    MIME_MAP = tst_insert(MIME_MAP, bdata(ext_rev), blength(ext_rev), type_str);

    bdestroy(ext_rev);

    return 0;
error:
    bdestroy(ext_rev);
    bdestroy(type_str);
    return -1;
}
Esempio n. 8
0
void Handler_task(void *v)
{
    int rc = 0;
    int i = 0;
    Handler *handler = (Handler *)v;
    HandlerParser *parser = NULL;
    int max_targets = Setting_get_int("limits.handler_targets", 128);
    log_info("MAX allowing limits.handler_targets=%d", max_targets);

    parser = HandlerParser_create(max_targets);
    check_mem(parser);

    check(Handler_setup(handler) == 0, "Failed to initialize handler, exiting.");

    while(handler->running && !task_was_signaled()) {
        taskstate("delivering");

        rc = handler_recv_parse(handler, parser);

        if(task_was_signaled()) {
            log_warn("Handler task signaled, exiting.");
            break;
        } else if( rc == -1 || parser->target_count <= 0) {
            log_warn("Skipped invalid message from handler: %s", bdata(handler->send_spec));
            taskdelay(100);
            continue;
        } else {
            for(i = 0; i < (int)parser->target_count; i++) {
                int id = (int)parser->targets[i];
                int fd = Register_fd_for_id(id);
                Connection *conn = fd == -1 ? NULL : Register_fd_exists(fd);

                // don't bother calling process request if there's nothing to handle
                if(conn && fd >= 0) {
                    handler_process_request(handler, id, fd, conn, parser->body);
                } else {
                    // TODO: I believe we need to notify the connection that it is dead too
                    Handler_notify_leave(handler, id);
                }
            }
        }

        HandlerParser_reset(parser);
    }

    handler->running = 0;
    handler->task = NULL;
    HandlerParser_destroy(parser);
    taskexit(0);

error:
    log_err("HANDLER TASK DIED: %s", bdata(handler->send_spec));
    handler->running = 0;
    handler->task = NULL;
    HandlerParser_destroy(parser);
    taskexit(1);
}
Esempio n. 9
0
static inline void startfdtask()
{
    if(!STARTED_FDTASK) {
        FDSTACK = Setting_get_int("limits.fdtask_stack", 100 * 1024);
        log_info("MAX limits.fdtask_stack=%d", FDSTACK);

        POLL = SuperPoll_create();
        STARTED_FDTASK = 1;
        taskcreate(fdtask, 0, FDSTACK);
    }
}
Esempio n. 10
0
void Server_init()
{
    int mq_threads = Setting_get_int("zeromq.threads", 1);

    if(mq_threads > 1) {
        log_info("WARNING: Setting zeromq.threads greater than 1 can cause lockups in your handlers.");
    }

    log_info("Starting 0MQ with %d threads.", mq_threads);
    mqinit(mq_threads);
    Register_init();
    Request_init();
    Connection_init();
}
Esempio n. 11
0
void Handler_task(void *v)
{
    int rc = 0;
    int i = 0;
    Handler *handler = (Handler *)v;
    HandlerParser *parser = NULL;
    int max_targets = Setting_get_int("limits.handler_targets", 128);
    log_info("MAX allowing limits.handler_targets=%d", 128);

    parser = HandlerParser_create(max_targets);
    check_mem(parser);

    check(Handler_setup(handler) == 0, "Failed to initialize handler, exiting.");

    while(handler->running) {
        taskstate("delivering");

        rc = handler_recv_parse(handler, parser);

        if(rc != -1 && parser->target_count > 0) {
            for(i = 0; i < (int)parser->target_count; i++) {
                int id = (int)parser->targets[i];
                int fd = Register_fd_for_id(id);
                Connection *conn = (Connection *)Register_fd_exists(fd);

                handler_process_request(handler, id, fd, conn, parser->body);
            }
        } else {
            debug("Skipped invalid message from handler: %s", bdata(handler->send_spec));
        }

        HandlerParser_reset(parser);
    }

    HandlerParser_destroy(parser);
    debug("HANDLER EXITED.");
    taskexit(0);

error:
    HandlerParser_destroy(parser);
    log_err("HANDLER TASK DIED");
    taskexit(1);
}
Esempio n. 12
0
void Connection_init()
{
    MAX_CONTENT_LENGTH = Setting_get_int("limits.content_length", 20 * 1024);
    BUFFER_SIZE = Setting_get_int("limits.buffer_size", 4 * 1024);
    CONNECTION_STACK = Setting_get_int("limits.connection_stack_size", 32 * 1024);
    CLIENT_READ_RETRIES = Setting_get_int("limits.client_read_retries", 5);


    log_info("MAX limits.content_length=%d, limits.buffer_size=%d, limits.connection_stack_size=%d, limits.client_read_retries=%d",
            MAX_CONTENT_LENGTH, BUFFER_SIZE, CONNECTION_STACK,
            CLIENT_READ_RETRIES);

    PROXY_READ_RETRIES = Setting_get_int("limits.proxy_read_retries", 100);
    PROXY_READ_RETRY_WARN = Setting_get_int("limits.proxy_read_retry_warn", 10);

    log_info("MAX limits.proxy_read_retries=%d, limits.proxy_read_retry_warn=%d",
            PROXY_READ_RETRIES, PROXY_READ_RETRY_WARN);

    IO_SSL_VERIFY_METHOD = Setting_get_int("ssl.verify_optional", 0) ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE;

}
Esempio n. 13
0
int attempt_chroot_drop(Server *srv)
{
    int rc = 0;

    log_info("All loaded up, time to turn into a server.");
    log_info("-- Starting " VERSION ". Copyright (C) Zed A. Shaw. Licensed BSD.\n");
    log_info("-- Look in %s for startup messages and errors.", bdata(srv->error_log));

    int testmode = 0;

    if(srv->chroot != NULL) {
        if(Unixy_chroot(srv->chroot) == 0) {
            if(Setting_get_int("server.daemonize", 1)) {
                rc = Unixy_daemonize(1); // 1 == chdir /
                check(rc == 0, "Failed to daemonize, looks like you're hosed.");
            }
            else {
                rc = chdir("/");
                check(rc == 0, "Failed to change working directory to '/'.");
            }
        } else {
            log_warn("Couldn't chroot to %s, assuming running in test mode.", bdata(srv->chroot));

            // rewrite the access log to be in the right location
            bstring temp = bformat("%s%s", bdata(srv->chroot), bdata(srv->access_log));
            bassign(srv->access_log, temp);
            bdestroy(temp);

            temp = bformat(".%s", bdata(srv->pid_file));
            bassign(srv->pid_file, temp);
            bdestroy(temp);

            testmode = 1;
        }
    } else {
        if(Setting_get_int("server.daemonize", 1)) {
            rc = Unixy_daemonize(0); // 0 == don't chdir
            check(rc == 0, "Failed to daemonize, looks like you're hosed.");
        }
    }

    rc = Unixy_pid_file(srv->pid_file);
    check(rc == 0, "Failed to make the PID file %s", bdata(srv->pid_file));

    if(srv->chroot != NULL && ! testmode) {
        rc = Unixy_drop_priv(&PRIV_DIR);
        check(rc == 0, "Failed to drop priv to the owner of %s", bdata(&PRIV_DIR));
    } else {
        rc = Unixy_drop_priv(NULL);
        check(rc == 0, "Failed to drop priv");
    }

    if(!testmode) {
        FILE *log = fopen(bdata(srv->error_log), "a+");
        check(log, "Couldn't open %s log file.", bdata(srv->error_log));
        setbuf(log, NULL);
        check(0==add_log_to_rotate_list(srv->error_log,log),"Unable to add error log to list of files to rotate.");

        dbg_set_log(log);
    }

    return 0;

error:
    return -1;
}
Esempio n. 14
0
void Request_init()
{
    MAX_HEADER_COUNT = Setting_get_int("limits.header_count", 128 * 10);
    log_info("MAX limits.header_count=%d", MAX_HEADER_COUNT);
}
Esempio n. 15
-1
int Log_init(bstring access_log, bstring log_spec)
{
    int rc = 0;
    LogConfig *config = NULL;

    if(LOG_SOCKET == NULL) 
    {
        check(ZMQ_CTX, "No ZMQ context, cannot start access log.");

        if(Setting_get_int("disable.access_logging", 0))
        {
            log_info("Access log is disabled according to disable.access_logging.");
        } 
        else 
        {
            config = LogConfig_create(access_log, log_spec);
            check(config, "Failed to configure access logging.");

            LOG_SOCKET = zmq_socket(ZMQ_CTX, ZMQ_PUB);
            check(LOG_SOCKET != NULL, "Failed to create access log socket");

#ifdef ZMQ_LINGER
            int opt = 0;
            rc = zmq_setsockopt(LOG_SOCKET, ZMQ_LINGER, &opt, sizeof(opt));
            check(rc == 0, "Could not set the linger option.");
#endif

            rc = zmq_bind(LOG_SOCKET, bdata(log_spec));
            check(rc == 0, "Failed to bind access_log zeromq socket.");

            pthread_create(&LOG_THREAD, NULL, Log_internal_thread, config);
        }
    }

    return 0;
error:

    LogConfig_destroy(config);
    return -1;
}