Exemplo n.º 1
0
int http_server_init(struct http_server *server) {
    /*
     * one time global initializers
     */
    if (0 > mime_types_init())
        return LOGGER_ERROR("failed to initialize mime types"), -1;
    if (0 > http_headers_init())
        return LOGGER_ERROR("failed to initialize http headers"), -1;
    /*
     * idle connection handler
     */
    server->idle_ctx = ribs_context_create(SMALL_STACK_SIZE, http_server_idle_handler);
    server->idle_ctx->data.ptr = server;
    /*
     * context pool
     */
    if (0 == server->stack_size || 0 == server->num_stacks) {
        struct rlimit rlim;
        if (0 > getrlimit(RLIMIT_STACK, &rlim))
            return LOGGER_PERROR("getrlimit(RLIMIT_STACK)"), -1;

        long total_mem = sysconf(_SC_PHYS_PAGES);
        if (total_mem < 0)
            return LOGGER_PERROR("sysconf"), -1;
        total_mem *= getpagesize();
        size_t num_ctx_in_one_map = total_mem / rlim.rlim_cur;
        /* half of total mem to start with so we don't need to enable overcommit */
        num_ctx_in_one_map >>= 1;
        LOGGER_INFO("http server pool: initial=%zu, grow=%zu", num_ctx_in_one_map, num_ctx_in_one_map);
        ctx_pool_init(&server->ctx_pool, num_ctx_in_one_map, num_ctx_in_one_map, rlim.rlim_cur, sizeof(struct http_server_context) + server->context_size);
    } else {
Exemplo n.º 2
0
int http_client_pool_init(struct http_client_pool *http_client_pool, size_t initial, size_t grow) {
    LOGGER_INFO("http client pool: initial=%zu, grow=%zu", initial, grow);
    if (0 > ctx_pool_init(&http_client_pool->ctx_pool, initial, grow, CLIENT_STACK_SIZE, sizeof(struct http_client_context)))
        return -1;

    /* Global to all clients */
    if (!client_chains) {
        struct rlimit rlim;
        if (0 > getrlimit(RLIMIT_NOFILE, &rlim))
            return LOGGER_PERROR("getrlimit(RLIMIT_NOFILE)"), -1;

        client_chains = calloc(rlim.rlim_cur, sizeof(struct list));
        if (!client_chains)
            return LOGGER_PERROR("calloc client_chains"), -1;

        /* storage for multiple client chains */
        client_heads = calloc(rlim.rlim_cur, sizeof(struct list));
        struct list *tmp = client_heads, *tmp_end = tmp + rlim.rlim_cur;
        if (!client_heads)
            return LOGGER_PERROR("calloc client_heads"), -1;
        for (; tmp != tmp_end; ++tmp)
            list_insert_tail(&free_list, tmp);

        idle_ctx = ribs_context_create(SMALL_STACK_SIZE, http_client_idle_handler);

        hashtable_init(&ht_persistent_clients, rlim.rlim_cur);
    }
    return timeout_handler_init(&http_client_pool->timeout_handler);
}
Exemplo n.º 3
0
Arquivo: timer.c Projeto: Pferd/ribs2
int ribs_timer_create(void (*handler)(int)) {
    int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    if (0 > tfd)
        return LOGGER_PERROR("timerfd_create"), -1;
    struct ribs_context *ctx = ribs_context_create(1024 * 1024, sizeof(void (*)(void)), _ribs_timer_wrapper);
    void (**ref)(int) = (void (**)(int))ctx->reserved;
    *ref = handler;
    if (0 > ribs_epoll_add(tfd, EPOLLIN, ctx))
        return LOGGER_PERROR("epoll_add"), close(tfd), -1;
    return tfd;
}
Exemplo n.º 4
0
int ribs_epoll_add(int fd, uint32_t events, struct ribs_context* ctx) {
    struct epoll_event ev = { .events = events, .data.fd = fd };
    if (0 > epoll_ctl(ribs_epoll_fd, EPOLL_CTL_ADD, fd, &ev))
        return LOGGER_PERROR("epoll_ctl"), -1;
    epoll_worker_set_fd_ctx(fd, ctx);
    return 0;
}

struct ribs_context* small_ctx_for_fd(int fd, void (*func)(void)) {
    void *ctx=ribs_context_create(SMALL_STACK_SIZE, func);
    if (NULL == ctx)
        return LOGGER_PERROR("ribs_context_create"), NULL;
    if (0 > ribs_epoll_add(fd, EPOLLIN, ctx))
        return NULL;
    return ctx;
}
Exemplo n.º 5
0
int epoll_worker_init(void) {
    struct rlimit rlim;
    if (0 > getrlimit(RLIMIT_NOFILE, &rlim))
        return LOGGER_PERROR("getrlimit(RLIMIT_NOFILE)"), -1;
    epoll_worker_fd_map = calloc(rlim.rlim_cur, sizeof(struct epoll_worker_fd_data));

    ribs_epoll_fd = epoll_create1(EPOLL_CLOEXEC);
    if (ribs_epoll_fd < 0)
        return LOGGER_PERROR("epoll_create1"), -1;

    /* block some signals */
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGPIPE);
    if (-1 == sigprocmask(SIG_BLOCK, &set, NULL))
        return LOGGER_PERROR("sigprocmask"), -1;

#ifdef UGLY_GETADDRINFO_WORKAROUND
    sigemptyset(&set);
    sigaddset(&set, SIGRTMIN);
    if (-1 == sigprocmask(SIG_BLOCK, &set, NULL))
        return LOGGER_PERROR("sigprocmask"), -1;

    /* sigrtmin to context */
    int sfd = signalfd(-1, &set, SFD_NONBLOCK);
    if (0 > sfd)
        return LOGGER_PERROR("signalfd"), -1;
    if (NULL == small_ctx_for_fd(sfd, sigrtmin_to_context))
        return -1;
#endif

    event_loop_ctx = ribs_context_create(SMALL_STACK_SIZE, event_loop);

    /* pipe to conetxt */
    int pipefd[2];
    if (0 > pipe2(pipefd, O_NONBLOCK))
        return LOGGER_PERROR("pipe"), -1;
    if (NULL == small_ctx_for_fd(pipefd[0], pipe_to_context))
        return -1;
    queue_ctx_fd = pipefd[1];
    return ribs_epoll_add(queue_ctx_fd, EPOLLOUT | EPOLLET, event_loop_ctx);
}
Exemplo n.º 6
0
static int _set_signals(void) {
    struct sigaction sa = {
        .sa_handler = signal_handler,
        .sa_flags = 0
    };
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);

    sigset_t sigset;
    sigemptyset(&sigset);
    sigaddset(&sigset, SIGCHLD);
    if (0 > sigprocmask(SIG_BLOCK, &sigset, NULL))
        return LOGGER_PERROR("sigprocmask"), -1;
    sigfd = signalfd(-1, &sigset, SFD_NONBLOCK | SFD_CLOEXEC);
    if (0 > sigfd)
        return LOGGER_PERROR("signalfd"), -1;
    if (NULL == (sigfd_ctx = ribs_context_create(SIG_CHLD_STACK_SIZE, 0, _handle_sig_child)))
        return -1;
    return 0;
}

static int _init_subprocesses(const char *pidfilename, int num_forks) {
    if (0 >= num_forks) {
        num_forks = sysconf(_SC_NPROCESSORS_CONF);
        if (0 > num_forks)
            exit(EXIT_FAILURE);
    }
    LOGGER_INFO("num forks = %d", num_forks);
    num_instances = num_forks;
    daemon_instance = 0;
    children_pids = calloc(num_forks - 1, sizeof(pid_t));
    int i;
    for (i = 1; i < num_forks; ++i) {
        LOGGER_INFO("starting sub-process %d", i);
        pid_t pid = fork();
        if (0 > pid) return LOGGER_PERROR("fork"), -1;
        if (0 == pid) {
            daemon_instance = i;
            if (0 > prctl(PR_SET_PDEATHSIG, SIGTERM))
                return LOGGER_PERROR("prctl"), -1;
            if (0 > _set_signals())
                return LOGGER_ERROR("failed to set signals"), -1;
            LOGGER_INFO("sub-process %d started", i);
            return 0;
        } else
            children_pids[i-1] = pid;
    }
    if (pidfilename && 0 > _set_pidfile(pidfilename))
        return LOGGER_ERROR("failed to set pidfile"), -1;
    if (0 > _set_signals())
        return LOGGER_ERROR("failed to set signals"), -1;
    return 0;
}

static int ribs_server_init_daemon(const char *pidfilename, const char *logfilename, int num_forks) {
    if (0 > pipe2(child_is_up_pipe, O_CLOEXEC))
        return LOGGER_ERROR("failed to create pipe"), -1;

    pid_t pid = fork();
    if (pid < 0)
        return LOGGER_PERROR("ribs_server_init_daemon, fork"), -1;

    if (pid > 0) {
        close(child_is_up_pipe[1]); /* close the write side */
        /* wait for child to come up */
        uint8_t t;
        int res;
        LOGGER_INFO("waiting for the child process [%d] to start...", pid);
        if (0 >= (res = read(child_is_up_pipe[0], &t, sizeof(t)))) {
            if (0 > res)
                LOGGER_PERROR("pipe");
            LOGGER_ERROR("child process failed to start");
            return -1;
        }
        LOGGER_INFO("child process started successfully");
        exit(EXIT_SUCCESS);
    }
    close(child_is_up_pipe[0]); /* close the read side */

    umask(0);

    if (0 > setsid())
        return LOGGER_PERROR("daemonize, setsid"), -1;

    int fdnull = open("/dev/null", O_RDWR);
    if (0 > fdnull)
        return LOGGER_PERROR("/dev/null"), -1;

    dup2(fdnull, STDIN_FILENO);
    if (logfilename) {
        if (0 > _logger_init(logfilename))
            return -1;
    } else {
        dup2(fdnull, STDOUT_FILENO);
        dup2(fdnull, STDERR_FILENO);
    }
    close(fdnull);
    LOGGER_INFO("child process started");
    return _init_subprocesses(pidfilename, num_forks);
}

int ribs_server_init(int daemonize, const char *pidfilename, const char *logfilename, int num_forks) {
    if (0 > hashtable_init(&ht_pid_to_ctx, 0))
        return -1;
    if (daemonize)
        return ribs_server_init_daemon(pidfilename, logfilename, num_forks);
    /* if (logfilename && 0 > _logger_init(logfilename)) */
    /*     exit(EXIT_FAILURE); */
    return _init_subprocesses(pidfilename, num_forks);
}

int ribs_server_signal_children(int sig) {
    if (0 >= num_instances || 0 != daemon_instance)
        return 0;
    int i, res = 0;
    for (i = 0; i < num_instances-1; ++i) {
        if (0 < children_pids[i] && 0 > kill(children_pids[i], sig)) {
            LOGGER_PERROR("kill [%d] %d", sig, children_pids[i]);
            res = -1;
        }
    }
    return res;
}

void ribs_server_start(void) {
    daemon_finalize();
    if (0 <= sigfd && 0 > ribs_epoll_add(sigfd, EPOLLIN, sigfd_ctx))
        return LOGGER_ERROR("ribs_epoll_add: sigfd");
    epoll_worker_loop();
    if (0 >= num_instances || 0 != daemon_instance)
        return;
    LOGGER_INFO("sending SIGTERM to sub-processes");
    ribs_server_signal_children(SIGTERM);
    LOGGER_INFO("waiting for sub-processes to exit");
    int i, status;
    for (i = 0; i < num_instances-1; ++i) {
        if (0 < children_pids[i] && 0 > waitpid(children_pids[i], &status, 0))
            LOGGER_PERROR("waitpid %d", children_pids[i]);
    }
    LOGGER_INFO("sub-processes terminated");
}
Exemplo n.º 7
0
int http_server_init(struct http_server *server) {
    /*
     * one time global initializers
     */
    if (0 > mime_types_init())
        return LOGGER_ERROR("failed to initialize mime types"), -1;
    if (0 > http_headers_init())
        return LOGGER_ERROR("failed to initialize http headers"), -1;
    /*
     * idle connection handler
     */
    server->idle_ctx = ribs_context_create(SMALL_STACK_SIZE, sizeof(struct http_server *), http_server_idle_handler);
    struct http_server **server_ref = (struct http_server **)server->idle_ctx->reserved;
    *server_ref = server;
    /*
     * context pool
     */
    if (0 == server->num_stacks)
        server->num_stacks = DEFAULT_NUM_STACKS;
    if (0 == server->stack_size) {
        struct rlimit rlim;
        if (0 > getrlimit(RLIMIT_STACK, &rlim))
            return LOGGER_PERROR("getrlimit(RLIMIT_STACK)"), -1;
        server->stack_size = rlim.rlim_cur;
    }
    LOGGER_INFO("http server pool: initial=%zu, grow=%zu, stack_size=%zu", server->num_stacks, server->num_stacks, server->stack_size);
    ctx_pool_init(&server->ctx_pool, server->num_stacks, server->num_stacks, server->stack_size, sizeof(struct http_server_context) + server->context_size);
    /*
     * listen socket
     */
    const int LISTEN_BACKLOG = 32768;
    LOGGER_INFO("listening on port: %d, backlog: %d", server->port, LISTEN_BACKLOG);
    int lfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
    if (0 > lfd)
        return -1;

    int rc;
    const int option = 1;
    rc = setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
    if (0 > rc)
        return LOGGER_PERROR("setsockopt, SO_REUSEADDR"), rc;

    rc = setsockopt(lfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
    if (0 > rc)
        return LOGGER_PERROR("setsockopt, TCP_NODELAY"), rc;

    struct linger ls;
    ls.l_onoff = 0;
    ls.l_linger = 0;
    rc = setsockopt(lfd, SOL_SOCKET, SO_LINGER, (void *)&ls, sizeof(ls));
    if (0 > rc)
        return LOGGER_PERROR("setsockopt, SO_LINGER"), rc;

    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(struct sockaddr_in));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(server->port);
    addr.sin_addr.s_addr = INADDR_ANY;
    if (0 > bind(lfd, (struct sockaddr *)&addr, sizeof(addr)))
        return LOGGER_PERROR("bind"), -1;

    if (0 > listen(lfd, LISTEN_BACKLOG))
        return LOGGER_PERROR("listen"), -1;

    server->accept_ctx = ribs_context_create(ACCEPTOR_STACK_SIZE, sizeof(struct http_server *), http_server_accept_connections);
    server->fd = lfd;
    server_ref = (struct http_server **)server->accept_ctx->reserved;
    *server_ref = server;

    if (server->max_req_size == 0)
        server->max_req_size = DEFAULT_MAX_REQ_SIZE;
    return 0;
}