示例#1
0
文件: httpd.c 项目: ijz/ribs2
int main(int argc, char *argv[]) {
    static struct option long_options[] = {
        {"port", 1, 0, 'p'},
        {"daemonize", 0, 0, 'd'},
        {"forks", 1, 0, 'f'},
        {0, 0, 0, 0}
    };

    int port = 8080;
    int daemon_mode = 0;
    int forks = 0;
    for (;;) {
        int option_index = 0;
        int c = getopt_long(argc, argv, "p:f:d", long_options, &option_index);
        if (c == -1)
            break;
        switch (c) {
        case 'p':
            port = atoi(optarg);
            break;
        case 'd':
            daemon_mode = 1;
            break;
        case 'f':
            forks = atoi(optarg);
            break;
        }
    }

    /* server config */
    struct http_server server = {
        /* port number */
        .port = port,

        /* call simple_file_server upon receiving http request */
        .user_func = simple_file_server,

        /* set idle connection timeout to 60 seconds */
        .timeout_handler.timeout = 60000,

        /* set fiber's stack size to automatic (0) */
        .stack_size = 0,

        /* start the server with 100 stacks */
        /* more stacks will be created if necessary */
        .num_stacks =  100,

        /* we expect most of our requests to be less than 8K */
        .init_request_size = 8192,

        /* we expect most of our response headers to be less than
           8K */
        .init_header_size = 8192,

        /* we expect most of our response payloads to be less than
           8K */
        .init_payload_size = 8192,

        /* no limit on the request size, this should be set to
           something reasonable if you want to protect your server
           against denial of service attack */
        .max_req_size = 0,

        /* no additional space is needed in the context to store app
           specified data (fiber local storage) */
        .context_size = 0
    };

    /* initialize server, but don't accept connections yet */
    if (0 > http_server_init(&server))
        exit(EXIT_FAILURE);

    /* run as daemon if specified */
    if (daemon_mode)
        daemonize(), daemon_finalize();

    /* assume autoconfiguration if forks is not a positive value */
    if (0 >= forks) {
        forks = sysconf(_SC_NPROCESSORS_CONF);
        if (0 > forks)
            exit(EXIT_FAILURE);
    }

    for(; forks > 1; --forks){
        if (0 >= fork()) {
            break;
        }
    }

    /* initialize the event loop */
    if (0 > epoll_worker_init())
        exit(EXIT_FAILURE);

    /* start accepting connections, must be called after initializing
       epoll worker */
    if (0 > http_server_init_acceptor(&server))
        exit(EXIT_FAILURE);

    epoll_worker_loop();
    return 0;
}
示例#2
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");
}
示例#3
0
static int _set_signals(void) {
    struct sigaction sa = {
        .sa_handler = signal_handler,
        .sa_flags = 0
    };
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    if (0 == daemon_instance) sigaction(SIGCHLD, &sa, NULL);
    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 > pipe(child_is_up_pipe))
        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 (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 > 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();
    epoll_worker_loop();
    if (0 >= num_instances || 0 != daemon_instance)
        return;
    struct sigaction sa = {
        .sa_handler = SIG_DFL,
        .sa_flags = 0
    };
    sigaction(SIGCHLD, &sa, NULL);
    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 > waitpid(children_pids[i], &status, 0))
            LOGGER_PERROR("waitpid %d", children_pids[i]);
    }
    LOGGER_INFO("sub-processes terminated");
}

int ribs_get_daemon_instance(void) {
    return daemon_instance;
}

int daemonize(void) {
    if (0 > pipe(child_is_up_pipe))
        return LOGGER_ERROR("failed to create pipe"), -1;

    pid_t pid = fork();
    if (pid < 0) {
        LOGGER_PERROR("daemonize, fork");
        exit(EXIT_FAILURE);
    }

    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");
            exit(EXIT_FAILURE);
        }
        LOGGER_INFO("child process started successfully");
        exit(EXIT_SUCCESS);
    }

    close(child_is_up_pipe[0]); /* close the read side */

    umask(0);

    if (0 > setsid()) {
        LOGGER_PERROR("daemonize, setsid");
        exit(EXIT_FAILURE);
    }

    int fdnull = open("/dev/null", O_RDWR);
    dup2(fdnull, STDIN_FILENO);
    dup2(fdnull, STDOUT_FILENO);
    dup2(fdnull, STDERR_FILENO);
    close(fdnull);

    pid = getpid();

    LOGGER_INFO("child process started (pid=%d)", pid);

    return 0;
}

void daemon_finalize(void) {
    if (daemon_instance > 0)
        return;
    if (0 > child_is_up_pipe[1])
        return;
    uint8_t t = 0;
    if (0 > write(child_is_up_pipe[1], &t, sizeof(t))) {
        LOGGER_PERROR("pipe");
        exit(EXIT_FAILURE);
    }
    close(child_is_up_pipe[1]);
}

int ribs_logger_init(const char *filename) {
    return _logger_init(filename);
}

int ribs_set_signals(void) {
    return _set_signals();
}

int ribs_set_pidfile(const char *filename) {
    if (0 > _set_pidfile(filename))
        return -1;
    return _set_signals();
}