Пример #1
0
int _ribified_pipe2(int pipefd[2], int flags) {

    if (0 > pipe2(pipefd, flags | O_NONBLOCK))
        return -1;

    if (0 == ribs_epoll_add(pipefd[0], EPOLLIN | EPOLLET, event_loop_ctx) &&
        0 == ribs_epoll_add(pipefd[1], EPOLLOUT | EPOLLET, event_loop_ctx))
        return 0;

    int my_error = errno;
    close(pipefd[0]);
    close(pipefd[1]);
    errno = my_error;
    return -1;
}
Пример #2
0
int _ribified_socket(int domain, int type, int protocol) {
    int sockfd = socket(domain, type | SOCK_NONBLOCK, protocol);
    if (0 > sockfd)
        return sockfd;
    if (0 > ribs_epoll_add(sockfd, EPOLLIN | EPOLLOUT | EPOLLET, event_loop_ctx))
        return close(sockfd), -1;
    return sockfd;
}
Пример #3
0
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;
}
Пример #4
0
int _ribified_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
    int flags=fcntl(sockfd, F_GETFL);
    if (0 > fcntl(sockfd, F_SETFL, flags | O_NONBLOCK))
        return LOGGER_PERROR("fcntl"), -1;

    int res = connect(sockfd, addr, addrlen);
    if (res < 0 && errno != EINPROGRESS) {
        return res;
    }
    return ribs_epoll_add(sockfd, EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP, event_loop_ctx);
}
Пример #5
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;
}
Пример #6
0
static void http_server_accept_connections(void) {
    struct http_server **server_ref = (struct http_server **)current_ctx->reserved;
    struct http_server *server = *server_ref;
    for (;; yield()) {
        struct sockaddr_in new_addr;
        socklen_t new_addr_size = sizeof(struct sockaddr_in);
        int fd = accept4(server->fd, (struct sockaddr *)&new_addr, &new_addr_size, SOCK_CLOEXEC | SOCK_NONBLOCK);
        if (0 > fd)
            continue;

        if (0 > ribs_epoll_add(fd, EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP, server->idle_ctx)) {
            close(fd);
            continue;
        }

        timeout_handler_add_fd_data(&server->timeout_handler, epoll_worker_fd_map + fd);
    }
}
Пример #7
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);
}
Пример #8
0
struct http_client_context *http_client_pool_create_client(struct http_client_pool *http_client_pool, struct in_addr addr, uint16_t port, struct ribs_context *rctx) {
    int cfd;
    struct http_client_key key = { .addr = addr, .port = port };
    uint32_t ofs = hashtable_lookup(&ht_persistent_clients, &key, sizeof(struct http_client_key));
    struct list *head;
    if (ofs > 0 && !list_empty(head = client_heads + *(uint32_t *)hashtable_get_val(&ht_persistent_clients, ofs))) {
        struct list *client = list_pop_head(head);
        cfd = client - client_chains;
        struct epoll_worker_fd_data *fd_data = epoll_worker_fd_map + cfd;
        TIMEOUT_HANDLER_REMOVE_FD_DATA(fd_data);
    } else {
        cfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
        if (0 > cfd)
            return LOGGER_PERROR("socket"), NULL;

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

        if (0 > setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)))
            return LOGGER_PERROR("setsockopt TCP_NODELAY"), close(cfd), NULL;

        struct sockaddr_in saddr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr = addr };
        if (0 > connect(cfd, (struct sockaddr *)&saddr, sizeof(saddr)) && EINPROGRESS != errno)
            return LOGGER_PERROR("connect"), close(cfd), NULL;
        if (0 > ribs_epoll_add(cfd, EPOLLIN | EPOLLOUT | EPOLLET, event_loop_ctx))
            return close(cfd), NULL;
    }
    struct ribs_context *new_ctx = ctx_pool_get(&http_client_pool->ctx_pool);
    struct epoll_worker_fd_data *fd_data = epoll_worker_fd_map + cfd;
    fd_data->ctx = new_ctx;
    ribs_makecontext(new_ctx, rctx ? rctx : current_ctx, http_client_fiber_main);
    struct http_client_context *cctx = (struct http_client_context *)new_ctx->reserved;
    cctx->fd = cfd;
    cctx->pool = http_client_pool;
    cctx->key = (struct http_client_key){ .addr = addr, .port = port };
    vmbuf_init(&cctx->request, 4096);
    vmbuf_init(&cctx->response, 4096);
    timeout_handler_add_fd_data(&http_client_pool->timeout_handler, fd_data);
    return cctx;
}
Пример #9
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");
}
Пример #10
0
int http_server_init_acceptor(struct http_server *server) {
    if (0 > ribs_epoll_add(server->fd, EPOLLIN, server->accept_ctx))
        return -1;
    return timeout_handler_init(&server->timeout_handler);
}
Пример #11
0
int sendemail2(struct sendemail_mta *mta, struct email *email) {
    if (NULL == mta) {
        mta = global_mta;
    }

    int cfd = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, IPPROTO_TCP);
    if (0 > cfd)
        return LOGGER_PERROR("sendemail: socket"), -1;

    const int option = 1;
    if (0 > setsockopt(cfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option)))
        return LOGGER_PERROR("sendemail: setsockopt SO_REUSEADDR"), close(cfd), -1;

    if (0 > setsockopt(cfd, IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option)))
        return LOGGER_PERROR("sendemail: setsockopt TCP_NODELAY"), close(cfd), -1;

    if (0 > connect(cfd, (struct sockaddr *)&mta->saddr, sizeof(mta->saddr)) && EINPROGRESS != errno)
        return LOGGER_PERROR("sendemail: connect"), close(cfd), -1;

    if (0 > ribs_epoll_add(cfd, EPOLLIN | EPOLLOUT | EPOLLET, current_ctx))
        return close(cfd), -1;

    struct vmbuf response = VMBUF_INITIALIZER;
    struct vmbuf request  = VMBUF_INITIALIZER;
    vmbuf_init(&response, 4096);
    vmbuf_init(&request, 4096);

    int code = -1;
    size_t ofs = 0;

    READ_AND_CHECK(220);

    vmbuf_sprintf(&request, "EHLO %s\r\n", mta->myhost);
    SEND_DATA;

    READ_AND_CHECK(250);

    vmbuf_sprintf(&request, "MAIL FROM:<%s>\r\n", email->from);
    SEND_DATA;

    READ_AND_CHECK(250);

    struct rcptlist *rcpt = &email->rcpt;
    while (rcpt) {
        vmbuf_sprintf(&request, "RCPT TO:<%s>\r\n", rcpt->to);
        SEND_DATA;

        READ_AND_CHECK(250);

        rcpt = rcpt->next;
    }

    vmbuf_strcpy(&request, "DATA\r\n");
    SEND_DATA;

    READ_AND_CHECK(354);

    struct iovec iov[2]= {
        [0] = {
            .iov_base = email->data,
            .iov_len = strlen(email->data)
        },