static inline int _mk_event_del(struct mk_event_ctx *ctx, struct mk_event *event)
{
    int ret;
    struct kevent ke = {0, 0, 0, 0, 0, 0};

    if (event->mask & MK_EVENT_READ) {
        EV_SET(&ke, event->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
        ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
        if (ret < 0) {
            mk_libc_error("kevent");
            return ret;
        }
    }

    if (event->mask & MK_EVENT_WRITE) {
        EV_SET(&ke, event->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
        ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
        if (ret < 0) {
            mk_libc_error("kevent");
            return ret;
        }
    }

    return 0;
}
static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
                                           int expire, void *data)
{
    int fd;
    int ret;
    struct mk_event *event;
    struct kevent ke;

    /*
     * We just need a file descriptor number, we don't care from where it
     * comes from.
     */
    fd = open("/dev/null", 0);
    if (fd == -1) {
        mk_libc_error("open");
        return -1;
    }

    event = data;
    event->fd = fd;
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

    EV_SET(&ke, fd, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, expire, event);

    ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
    if (ret < 0) {
        close(fd);
        mk_libc_error("kevent");
        return -1;
    }

    event->mask = MK_EVENT_READ;
    return fd;
}
Exemple #3
0
/* Register a timeout file descriptor */
static inline int _mk_event_timeout_create(mk_event_ctx_t *ctx, int expire)
{
    int ret;
    int timer_fd;
    struct itimerspec its;

    /* expiration interval */
    its.it_interval.tv_sec  = expire;
    its.it_interval.tv_nsec = 0;

    /* initial expiration */
    its.it_value.tv_sec  = time(NULL) + expire;
    its.it_value.tv_nsec = 0;

    timer_fd = timerfd_create(CLOCK_REALTIME, 0);
    if (timer_fd == -1) {
        mk_libc_error("timerfd");
        return -1;
    }

    ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
    if (ret < 0) {
        mk_libc_error("timerfd_settime");
        return -1;
    }

    /* register the timer into the epoll queue */
    ret = _mk_event_add(ctx, timer_fd, MK_EVENT_READ);
    if (ret != 0) {
        close(timer_fd);
        return ret;
    }

    return timer_fd;
}
static inline int _mk_event_add(struct mk_event_ctx *ctx, int fd,
                                int type, uint32_t events, void *data)
{
    int ret;
    int set = MK_FALSE;
    struct mk_event *event;
    struct kevent ke = {0, 0, 0, 0, 0, 0};

    event = (struct mk_event *) data;
    if (event->mask == MK_EVENT_EMPTY) {
        event->fd   = fd;
        event->type = type;
    }

    /* Read flag */
    if ((event->mask ^ MK_EVENT_READ) && (events & MK_EVENT_READ)) {
        EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, event);
        set = MK_TRUE;
        //printf("[ADD] fd=%i READ\n", fd);
    }
    else if ((event->mask & MK_EVENT_READ) && (events ^ MK_EVENT_READ)) {
        EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, event);
        set = MK_TRUE;
        //printf("[DEL] fd=%i READ\n", fd);
    }

    if (set == MK_TRUE) {
        ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
        if (ret < 0) {
            mk_libc_error("kevent");
            return ret;
        }
    }

    /* Write flag */
    set = MK_FALSE;
    if ((event->mask ^ MK_EVENT_WRITE) && (events & MK_EVENT_WRITE)) {
        EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, event);
        set = MK_TRUE;
        //printf("[ADD] fd=%i WRITE\n", fd);
    }
    else if ((event->mask & MK_EVENT_WRITE) && (events ^ MK_EVENT_WRITE)) {
        EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, event);
        set = MK_TRUE;
        //printf("[DEL] fd=%i WRITE\n", fd);
    }

    if (set == MK_TRUE) {
        ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
        if (ret < 0) {
            mk_libc_error("kevent");
            return ret;
        }
    }

    event->mask = events;
    return 0;
}
Exemple #5
0
static inline int _mk_event_channel_create(struct mk_event_ctx *ctx,
                                           int *r_fd, int *w_fd, void *data)
{
    int ret;
    int fd[2];
    struct mk_event *event;

    ret = pipe(fd);
    if (ret < 0) {
        mk_libc_error("pipe");
        return ret;
    }

    event = data;
    event->fd = fd[0];
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

    ret = _mk_event_add(ctx, fd[0],
                        MK_EVENT_NOTIFICATION, MK_EVENT_READ, event);
    if (ret != 0) {
        close(fd[0]);
        close(fd[1]);
        return ret;
    }

    *r_fd = fd[0];
    *w_fd = fd[1];

    return 0;
}
Exemple #6
0
/*
 * It register certain events for the file descriptor in question, if
 * the file descriptor have not been registered, create a new entry.
 */
static inline int _mk_event_add(mk_event_ctx_t *ctx, int fd, int events)
{
    int op;
    int ret;
    struct mk_event_fd_state *fds;
    struct epoll_event event = {0, {0}};

    /* Verify the FD status and desired operation */
    fds = mk_event_get_state(fd);
    if (fds->mask == MK_EVENT_EMPTY) {
        op = EPOLL_CTL_ADD;
    }
    else {
        op = EPOLL_CTL_MOD;
    }

    event.data.fd = fd;
    event.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP;

    if (events & MK_EVENT_READ) {
        event.events |= EPOLLIN;
    }
    if (events & MK_EVENT_WRITE) {
        event.events |= EPOLLOUT;
    }

    ret = epoll_ctl(ctx->efd, op, fd, &event);
    if (ret < 0) {
        mk_libc_error("epoll_ctl");
        return -1;
    }

    fds->mask = events;
    return ret;
}
Exemple #7
0
static inline void *_mk_event_loop_create(int size)
{
    mk_event_ctx_t *ctx;

    /* Main event context */
    ctx = mk_mem_malloc_z(sizeof(mk_event_ctx_t));
    if (!ctx) {
        return NULL;
    }

    /* Create the epoll instance */
    ctx->efd = epoll_create1(EPOLL_CLOEXEC);
    if (ctx->efd == -1) {
        mk_libc_error("epoll_create");
        mk_mem_free(ctx);
        return NULL;
    }

    /* Allocate space for events queue */
    ctx->events = mk_mem_malloc_z(sizeof(struct epoll_event) * size);
    if (!ctx->events) {
        close(ctx->efd);
        mk_mem_free(ctx);
        return NULL;
    }
    ctx->queue_size = size;
    return ctx;
}
Exemple #8
0
static inline void *_mk_event_loop_create(int size)
{
    struct mk_event_ctx *ctx;

    /* Main event context */
    ctx = mk_mem_malloc_z(sizeof(struct mk_event_ctx));
    if (!ctx) {
        return NULL;
    }

    /* Create the epoll instance */
    ctx->kfd = kqueue();
    if (ctx->kfd == -1) {
        mk_libc_error("kqueue");
        mk_mem_free(ctx);
        return NULL;
    }

    /* Allocate space for events queue */
    ctx->events = mk_mem_malloc_z(sizeof(struct kevent) * size);
    if (!ctx->events) {
        close(ctx->kfd);
        mk_mem_free(ctx);
        return NULL;
    }
    ctx->queue_size = size;
    return ctx;
}
Exemple #9
0
/* Register a timeout file descriptor */
static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
                                           time_t sec, long nsec, void *data)
{
    int ret;
    int timer_fd;
    struct itimerspec its;
    struct mk_event *event;

    mk_bug(!data);
    memset(&its, '\0', sizeof(struct itimerspec));

    /* expiration interval */
    its.it_interval.tv_sec  = sec;
    its.it_interval.tv_nsec = nsec;

    /* initial expiration */
    its.it_value.tv_sec  = time(NULL) + sec;
    its.it_value.tv_nsec = 0;

    timer_fd = timerfd_create(CLOCK_REALTIME, 0);
    if (timer_fd == -1) {
        mk_libc_error("timerfd");
        return -1;
    }

    ret = timerfd_settime(timer_fd, TFD_TIMER_ABSTIME, &its, NULL);
    if (ret < 0) {
        mk_libc_error("timerfd_settime");
        return -1;
    }

    event = data;
    event->fd   = timer_fd;
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

    /* register the timer into the epoll queue */
    ret = _mk_event_add(ctx, timer_fd,
                        MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
    if (ret != 0) {
        close(timer_fd);
        return ret;
    }

    return timer_fd;
}
Exemple #10
0
static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
                                           int expire, void *data)
{
    int fd;
    int ret;
    struct mk_event *event;
    struct kevent ke;

    /*
     * We just need a file descriptor number, we don't care from where it
     * comes from.
     */
    fd = open("/dev/null", 0);
    if (fd == -1) {
        mk_libc_error("open");
        return -1;
    }

    event = data;
    event->fd = fd;
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

#ifdef NOTE_SECONDS
    /* FreeBSD or LINUX_KQUEUE defined */
    EV_SET(&ke, fd, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, expire, event);
#else
    /* Other BSD have no NOTE_SECONDS & specify milliseconds */
    EV_SET(&ke, fd, EVFILT_TIMER, EV_ADD, 0, expire * 1000, event);
#endif
    ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
    if (ret < 0) {
        close(fd);
        mk_libc_error("kevent");
        return -1;
    }

    /*
     * FIXME: the timeout event is not triggered when using libkqueue, need
     * to confirm how it behave on native OSX.
     */
    event->mask = MK_EVENT_READ;

    return fd;
}
Exemple #11
0
int mk_socket_create()
{
    int sockfd;

    if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) {
        mk_libc_error("socket");
        return -1;
    }

    return sockfd;
}
Exemple #12
0
int mk_socket_reset(int socket)
{
    int status = 1;

    if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &status, sizeof(int)) == -1) {
        mk_libc_error("socket");
        exit(EXIT_FAILURE);
    }

    return 0;
}
Exemple #13
0
static inline int _mk_event_del(struct mk_event_ctx *ctx, int fd)
{
    int ret;
    struct kevent ke = {0, 0, 0, 0, 0, 0};

    EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
    ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
    if (ret < 0) {
        mk_libc_error("kevent");
        return ret;
    }

    EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
    ret = kevent(ctx->kfd, &ke, 1, NULL, 0, NULL);
    if (ret < 0) {
        mk_libc_error("kevent");
        return ret;
    }

    return 0;
}
Exemple #14
0
/* Delete an event */
static inline int _mk_event_del(mk_event_ctx_t *ctx, int fd)
{
    int ret;

    ret = epoll_ctl(ctx->efd, EPOLL_CTL_DEL, fd, NULL);
    MK_TRACE("[FD %i] Epoll, remove from QUEUE_FD=%i, ret=%i",
             fd, ctx->efd, ret);
    if (ret < 0) {
        mk_libc_error("epoll_ctl");
    }

    return ret;
}
Exemple #15
0
int mk_utils_worker_spawn(void (*func) (void *), void *arg, pthread_t *tid)
{
    pthread_attr_t thread_attr;

    pthread_attr_init(&thread_attr);
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
    if (pthread_create(tid, &thread_attr, (void *) func, arg) < 0) {
        mk_libc_error("pthread_create");
        return -1;
    }

    return 0;
}
Exemple #16
0
int mk_kernel_version()
{
    int a, b, c;
    int len;
    int pos;
    char *p, *t;
    char *tmp;
    struct utsname uts;

    if (uname(&uts) == -1) {
        mk_libc_error("uname");
    }
    len = strlen(uts.release);

    /* Fixme: this don't support Linux Kernel 10.x.x :P */
    a = (*uts.release - '0');

    /* Second number */
    p = (uts.release) + 2;
    pos = mk_string_char_search(p, '.', len - 2);
    if (pos <= 0) {
        /* Some Debian systems uses a different notation, e.g: 3.14-2-amd64 */
        pos = mk_string_char_search(p, '-', len - 2);
        if (pos <= 0) {
            return -1;
        }
    }

    tmp = mk_string_copy_substr(p, 0, pos);
    if (!tmp) {
        return -1;
    }
    b = atoi(tmp);
    mk_mem_free(tmp);

    /* Last number (it needs filtering) */
    t = p = p + pos + 1;
    do {
        t++;
    } while (isdigit(*t));

    tmp = mk_string_copy_substr(p, 0, t - p);
    if (!tmp) {
        return -1;
    }
    c = atoi(tmp);
    mk_mem_free(tmp);

    MK_TRACE("Kernel detected: %i.%i.%i", a, b, c);
    return MK_KERNEL_VERSION(a, b, c);
}
Exemple #17
0
pthread_t mk_utils_worker_spawn(void (*func) (void *), void *arg)
{
    pthread_t tid;
    pthread_attr_t thread_attr;

    pthread_attr_init(&thread_attr);
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
    if (pthread_create(&tid, &thread_attr, (void *) func, arg) < 0) {
        mk_libc_error("pthread_create");
        exit(EXIT_FAILURE);
    }

    return tid;
}
Exemple #18
0
/*
 * This routine creates a timer, since this select(2) backend aims to be used
 * in very old systems to be compatible, we cannot trust timerfd_create(2)
 * will be available (e.g: Cygwin), so our workaround is to create a pipe(2)
 * and a thread, this thread writes a byte upon the expiration time is reached.
 */
static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
                                           time_t sec, long nsec, void *data)
{
    int ret;
    int fd[2];
    struct mk_event *event;
    struct fd_timer *timer;

    timer = mk_mem_alloc(sizeof(struct fd_timer));
    if (!timer) {
        return -1;
    }

    ret = pipe(fd);
    if (ret < 0) {
        mk_mem_free(timer);
        mk_libc_error("pipe");
        return ret;
    }

    event = (struct mk_event *) data;
    event->fd = fd[0];
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

    _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
    event->mask = MK_EVENT_READ;

    /* Compose the timer context, this is released inside the worker thread */
    timer->fd   = fd[1];
    timer->sec  = sec;
    timer->nsec = nsec;
    timer->run  = MK_TRUE;

    event->data = timer;

    /* Now the dirty workaround, create a thread */
    ret = mk_utils_worker_spawn(_timeout_worker, timer, &timer->tid);
    if (ret < 0) {
        close(fd[0]);
        close(fd[1]);
        mk_mem_free(timer);
        return -1;
    }

    return fd[0];
}
Exemple #19
0
int mk_socket_create(int domain, int type, int protocol)
{
    int fd;

#ifdef SOCK_CLOEXEC
    fd = socket(domain, type | SOCK_CLOEXEC, protocol);
#else
    fd = socket(domain, type, protocol);
    fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif

    if (fd == -1) {
        mk_libc_error("socket");
        return -1;
    }

    return fd;
}
Exemple #20
0
/*
 * It register certain events for the file descriptor in question, if
 * the file descriptor have not been registered, create a new entry.
 */
static inline int _mk_event_add(struct mk_event_ctx *ctx, int fd,
                                int type, uint32_t events, void *data)
{
    int op;
    int ret;
    struct mk_event *event;
    struct epoll_event ep_event;

    /* Verify the FD status and desired operation */
    event = (struct mk_event *) data;
    if (event->mask == MK_EVENT_EMPTY) {
        op = EPOLL_CTL_ADD;
        event->fd   = fd;
        event->status = MK_EVENT_REGISTERED;
        event->type = type;

    }
    else {
        op = EPOLL_CTL_MOD;
        if (type != MK_EVENT_UNMODIFIED) {
            event->type = type;
        }
    }
    ep_event.events = EPOLLERR | EPOLLHUP | EPOLLRDHUP;
    ep_event.data.ptr = data;

    if (events & MK_EVENT_READ) {
        ep_event.events |= EPOLLIN;
    }
    if (events & MK_EVENT_WRITE) {
        ep_event.events |= EPOLLOUT;
    }

    ret = epoll_ctl(ctx->efd, op, fd, &ep_event);
    if (ret < 0) {
        mk_libc_error("epoll_ctl");
        return -1;
    }

    event->mask = events;
    return ret;
}
Exemple #21
0
static inline int _mk_event_channel_create(mk_event_ctx_t *ctx, int *r_fd, int *w_fd)
{
    int fd;
    int ret;

    fd = eventfd(0, EFD_CLOEXEC);
    if (fd == -1) {
        mk_libc_error("eventfd");
        return -1;
    }

    ret = _mk_event_add(ctx, fd, MK_EVENT_READ);
    if (ret != 0) {
        close(fd);
        return ret;
    }

    *w_fd = *r_fd = fd;
    return 0;
}
Exemple #22
0
static inline void *_mk_event_loop_create(int size)
{
    int efd;
    struct mk_event_ctx *ctx;

    /* Main event context */
    ctx = mk_mem_alloc_z(sizeof(struct mk_event_ctx));
    if (!ctx) {
        return NULL;
    }

    /* Create the epoll instance */
 #ifdef EPOLL_CLOEXEC
    efd = epoll_create1(EPOLL_CLOEXEC);
 #else
    efd = epoll_create(1);
    if (efd > 0) {
        if (fcntl(efd, F_SETFD, FD_CLOEXEC) == -1) {
            perror("fcntl");
        }
    }
 #endif

    if (efd == -1) {
        mk_libc_error("epoll_create");
        mk_mem_free(ctx);
        return NULL;
    }
    ctx->efd = efd;

    /* Allocate space for events queue */
    ctx->events = mk_mem_alloc_z(sizeof(struct epoll_event) * size);
    if (!ctx->events) {
        close(ctx->efd);
        mk_mem_free(ctx);
        return NULL;
    }
    ctx->queue_size = size;
    return ctx;
}
/*
 * This routine creates a timer, since this select(2) backend aims to be used
 * in very old systems to be compatible, we cannot trust timerfd_create(2)
 * will be available (e.g: Cygwin), so our workaround is to create a pipe(2)
 * and a thread, this thread writes a byte upon the expiration time is reached.
 */
static inline int _mk_event_timeout_create(struct mk_event_ctx *ctx,
                                           int expire, void *data)
{
    int ret;
    int fd[2];
    pid_t tid;
    struct mk_event *event;
    struct fd_timer *timer;

    timer = mk_mem_malloc(sizeof(struct fd_timer));
    if (!timer) {
        return -1;
    }

    ret = pipe(fd);
    if (ret < 0) {
        mk_mem_free(timer);
        mk_libc_error("pipe");
        return ret;
    }

    event = (struct mk_event *) data;
    event->fd = fd[0];
    event->type = MK_EVENT_NOTIFICATION;
    event->mask = MK_EVENT_EMPTY;

    _mk_event_add(ctx, fd[0], MK_EVENT_NOTIFICATION, MK_EVENT_READ, data);
    event->mask = MK_EVENT_READ;

    /* Compose the timer context, this is released inside the worker thread */
    timer->fd = fd[1];
    timer->expiration = expire;

    /* Now the dirty workaround, create a thread */
    mk_utils_worker_spawn(_timeout_worker, timer);
    return fd[0];
}
Exemple #24
0
int mk_socket_open(char *path, int async)
{
    int ret;
    int socket_fd;
    struct sockaddr_un address;

    socket_fd = mk_socket_create(PF_UNIX, SOCK_STREAM, 0);
    if (socket_fd == -1) {
        return -1;
    }

    memset(&address, '\0', sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, sizeof(address.sun_path), "%s", path);

    if (async == MK_TRUE) {
        mk_socket_set_nonblocking(socket_fd);
    }

    ret = connect(socket_fd, (struct sockaddr *) &address,
                  sizeof(struct sockaddr_un));
    if (ret == -1) {
        if (errno == EINPROGRESS) {
            return socket_fd;
        }
        else {
#ifdef TRACE
            mk_libc_error("connect");
#endif
            close(socket_fd);
            return -1;
        }
    }

    return socket_fd;
}
Exemple #25
0
/*
 * Initialize the global Event structure used by threads to access the
 * global file descriptor table.
 */
int mk_event_initalize()
{
    int i;
    int ret;
    mk_event_fdt_t *efdt;
    struct rlimit rlim;

    /*
     * Event File Descriptor Table (EFDT)
     * ----------------------------------
     * The main requirement for this implementation is that we need to maintain
     * a state of each file descriptor registered events, such as READ, WRITE,
     * SLEEPING, etc. This is required not by Monkey core but is a fundamental
     * piece to let plugins perform safe operations over file descriptors and
     * their events.
     *
     * The EFDT is created in the main process context and aims to be used by
     * every Worker thread. Once a connection arrives and it's notified to the
     * Worker, this last one will register the file descriptor status on the
     * EFDT.
     *
     * The EFDT is a fixed size array that contains entries for each possible
     * file descriptor number assigned for a TCP connection. In order to make
     * sure the assigned number can be used as an index of the array, we have
     * verified that the Linux Kernel always assigns a number in a range as
     * defined in __alloc_fd() on file file.c:
     *
     *   start: > 2
     *
     *   end  : rlim.rlim.cur
     *
     * The maximum number assigned is always the process soft limit for
     * RLIMIT_NOFILE, so basically we are safe trusting on this model.
     *
     * Note: as we make sure each file descriptor number is only handled by one
     * thread, there is no race conditions.
     */

    efdt = mk_mem_malloc_z(sizeof(mk_event_fdt_t));
    if (!efdt) {
        mk_err("Event: could not allocate memory for event FD Table");
        return -1;
    }

    /*
     * Despites what config->server_capacity says, we need to prepare to handle
     * a high number of file descriptors as process limit allows.
     */
    ret = getrlimit(RLIMIT_NOFILE, &rlim);
    if (ret == -1) {
        mk_libc_error("getrlimit");
        return -1;
    }
    efdt->size = rlim.rlim_cur;
    efdt->states = mk_mem_malloc_z(sizeof(struct mk_event_fd_state) * efdt->size);
    if (!efdt->states) {
        mk_err("Event: could not allocate memory for events states on FD Table");
        return -1;
    }

    /* mark all file descriptors as available */
    for (i = 0; i < efdt->size; i++) {
        efdt->states[i].fd   = -1;
        efdt->states[i].mask = MK_EVENT_EMPTY;
    }

    mk_events_fdt = efdt;
    return 0;
}