Example #1
0
static void mk_socket_safe_event_write(int socket)
{
    struct sched_list_node *sched;

    sched = mk_sched_get_thread_conf();
    MK_TRACE("[FD %i] Safe event write ON", socket);
    mk_event_add(sched->loop, socket, MK_EVENT_WRITE, NULL);
}
Example #2
0
/* Create a new mqtt request instance */
struct tcp_conn *tcp_conn_add(int fd, struct flb_in_tcp_config *ctx)
{
    int ret;
    struct tcp_conn *conn;
    struct mk_event *event;

    conn = flb_malloc(sizeof(struct tcp_conn));
    if (!conn) {
        return NULL;
    }

    /* Set data for the event-loop */
    event = &conn->event;
    MK_EVENT_NEW(event);
    event->fd           = fd;
    event->type         = FLB_ENGINE_EV_CUSTOM;
    event->handler      = tcp_conn_event;

    /* Connection info */
    conn->fd      = fd;
    conn->ctx     = ctx;
    conn->buf_len = 0;
    conn->rest    = 0;
    conn->status  = TCP_NEW;

    conn->buf_data = flb_malloc(ctx->chunk_size);
    if (!conn->buf_data) {
        perror("malloc");
        close(fd);
        flb_error("[in_tcp] could not allocate new connection");
        flb_free(conn);
        return NULL;
    }
    conn->buf_size = ctx->chunk_size;
    conn->in       = ctx->in;

    /* Initialize JSON parser */
    flb_pack_state_init(&conn->pack_state);

    /* Register instance into the event loop */
    ret = mk_event_add(ctx->evl, fd, FLB_ENGINE_EV_CUSTOM, MK_EVENT_READ, conn);
    if (ret == -1) {
        flb_error("[in_tcp] could not register new connection");
        close(fd);
        flb_free(conn->buf_data);
        flb_free(conn);
        return NULL;
    }

    mk_list_add(&conn->_head, &ctx->connections);

    return conn;
}
Example #3
0
static inline int io_tls_event_switch(struct flb_io_upstream *u, int mask)
{
    int ret;
    struct mk_event *event;

    event = &u->event;
    if (event->mask & ~mask) {
        ret = mk_event_add(u->evl,
                           event->fd,
                           FLB_ENGINE_EV_THREAD,
                           mask, &u->event);
        if (ret == -1) {
            flb_error("[io_tls] error changing mask to %i", mask);
            return -1;
        }
    }

    return 0;
}
Example #4
0
static inline
struct mk_sched_conn *mk_server_listen_handler(struct mk_sched_worker *sched,
                                               void *data)
{
    int ret;
    int client_fd = -1;
    struct mk_sched_conn *conn;
    struct mk_server_listen *listener = data;

    client_fd = mk_socket_accept(listener->server_fd);
    if (mk_unlikely(client_fd == -1)) {
        MK_TRACE("[server] Accept connection failed: %s", strerror(errno));
        goto error;
    }

    conn = mk_sched_add_connection(client_fd, listener, sched);
    if (mk_unlikely(!conn)) {
        goto error;
    }

    ret = mk_event_add(sched->loop, client_fd,
                       MK_EVENT_CONNECTION, MK_EVENT_READ, conn);
    if (mk_unlikely(ret != 0)) {
        mk_err("[server] Error registering file descriptor: %s",
               strerror(errno));
        goto error;
    }

    sched->accepted_connections++;
    MK_TRACE("[server] New connection arrived: FD %i", client_fd);
    return conn;

error:
    if (client_fd != -1) {
        listener->network->network->close(client_fd);
    }

    return NULL;
}
Example #5
0
int mk_conn_read(int socket)
{
    int ret;
    int status;
    struct mk_http_session *cs;
    struct mk_http_request *sr;
    struct sched_list_node *sched;

    MK_TRACE("[FD %i] Connection Handler / read", socket);

    /* Plugin hook */
    ret = mk_plugin_event_read(socket);

    switch (ret) {
    case MK_PLUGIN_RET_EVENT_OWNED:
        return MK_PLUGIN_RET_CONTINUE;
    case MK_PLUGIN_RET_EVENT_CLOSE:
        return -1;
    case MK_PLUGIN_RET_EVENT_CONTINUE:
        break; /* just return controller to invoker */
    }

    sched = mk_sched_get_thread_conf();
    cs = mk_http_session_get(socket);
    if (!cs) {
        /* Check if is this a new connection for the Scheduler */
        if (!mk_sched_get_connection(sched, socket)) {
            MK_TRACE("[FD %i] Registering new connection");
            if (mk_sched_register_client(socket, sched) == -1) {
                MK_TRACE("[FD %i] Close requested", socket);
                return -1;
            }
            /*
             * New connections are not registered yet into the
             * events loop, we need to do it manually:
             */
            mk_event_add(sched->loop, socket, MK_EVENT_READ, NULL);
            return 0;
        }

        /* Create session for the client */
        MK_TRACE("[FD %i] Create session", socket);
        cs = mk_http_session_create(socket, sched);
        if (!cs) {
            return -1;
        }
    }

    /* Invoke the read handler, on this case we only support HTTP (for now :) */
    ret = mk_http_handler_read(socket, cs);
    if (ret > 0) {
        if (mk_list_is_empty(&cs->request_list) == 0) {
            /* Add the first entry */
            sr = &cs->sr_fixed;
            mk_list_add(&sr->_head, &cs->request_list);
            mk_http_request_init(cs, sr);
        }
        else {
            sr = mk_list_entry_first(&cs->request_list, struct mk_http_request, _head);
        }

        status = mk_http_parser(sr, &cs->parser,
                                cs->body, cs->body_length);
        if (status == MK_HTTP_PARSER_OK) {
            MK_TRACE("[FD %i] HTTP_PARSER_OK", socket);
            mk_http_status_completed(cs);
            mk_event_add(sched->loop, socket, MK_EVENT_WRITE, NULL);
        }
        else if (status == MK_HTTP_PARSER_ERROR) {
            mk_http_session_remove(socket);
            MK_TRACE("[FD %i] HTTP_PARSER_ERROR", socket);
            return -1;
        }
        else {
            MK_TRACE("[FD %i] HTTP_PARSER_PENDING", socket);
        }
    }

    if (ret == -EAGAIN) {
        return 1;
    }

    return ret;
}
Example #6
0
int mk_conn_write(int socket)
{
    int ret = -1;
    struct mk_http_session *cs;
    struct sched_list_node *sched;
    struct sched_connection *conx;

    MK_TRACE("[FD %i] Connection Handler / write", socket);

    /* Plugin hook */
    ret = mk_plugin_event_write(socket);
    switch(ret) {
    case MK_PLUGIN_RET_EVENT_OWNED:
        return MK_PLUGIN_RET_CONTINUE;
    case MK_PLUGIN_RET_EVENT_CLOSE:
        return -1;
    case MK_PLUGIN_RET_EVENT_CONTINUE:
        break; /* just return controller to invoker */
    }

    MK_TRACE("[FD %i] Normal connection write handling", socket);

    sched = mk_sched_get_thread_conf();
    conx = mk_sched_get_connection(sched, socket);
    if (!conx) {
        MK_TRACE("[FD %i] Registering new connection");
        if (mk_sched_register_client(socket, sched) == -1) {
            MK_TRACE("[FD %i] Close requested", socket);
            return -1;
        }

        mk_event_add(sched->loop, socket, MK_EVENT_READ, NULL);
        return 0;
    }

    mk_sched_update_conn_status(sched, socket, MK_SCHEDULER_CONN_PROCESS);

    /* Get node from schedule list node which contains
     * the information regarding to the current client/socket
     */
    cs = mk_http_session_get(socket);
    if (!cs) {
        /* This is a ghost connection that doesn't exist anymore.
         * Closing it could accidentally close some other thread's
         * socket, so pass it to remove_client that checks it's ours.
         */
        mk_sched_drop_connection(socket);
        return 0;
    }

    ret = mk_http_handler_write(socket, cs);

    /*
     * if ret < 0, means that some error happened in the writer call,
     * in the other hand, 0 means a successful request processed, if
     * ret > 0 means that some data still need to be send.
     */
    if (ret < MK_CHANNEL_ERROR) {
        mk_sched_drop_connection(socket);
        return -1;
    }
    else if (ret == MK_CHANNEL_DONE) {
        MK_TRACE("[FD %i] Request End", socket);
        return mk_http_request_end(socket);
    }
    else if (ret == MK_CHANNEL_FLUSH) {
        return 0;
    }

    /* avoid to make gcc cry :_( */
    return -1;
}
Example #7
0
FLB_INLINE int flb_io_net_connect(struct flb_io_upstream *u,
                                  struct flb_thread *th)
{
    int fd;
    int ret;
    int error = 0;
    socklen_t len = sizeof(error);

    if (u->fd > 0) {
        close(u->fd);
    }

    /* Create the socket */
    fd = flb_net_socket_create(AF_INET, FLB_TRUE);
    if (fd == -1) {
        flb_error("[io] could not create socket");
        return -1;
    }
    u->fd = fd;

    /* Make the socket non-blocking */
    flb_net_socket_nonblocking(u->fd);

    /* Start the connection */
    ret = flb_net_tcp_fd_connect(fd, u->tcp_host, u->tcp_port);
    if (ret == -1) {
        if (errno == EINPROGRESS) {
            flb_debug("[upstream] connection in process");
        }
        else {
        }

        u->event.mask = MK_EVENT_EMPTY;
        u->event.status = MK_EVENT_NONE;
        u->thread = th;

        ret = mk_event_add(u->evl,
                           fd,
                           FLB_ENGINE_EV_THREAD,
                           MK_EVENT_WRITE, &u->event);
        if (ret == -1) {
            /*
             * If we failed here there no much that we can do, just
             * let the caller we failed
             */
            close(fd);
            return -1;
        }

        /*
         * Return the control to the parent caller, we need to wait for
         * the event loop to get back to us.
         */
        flb_thread_yield(th, FLB_FALSE);

        /* We got a notification, remove the event registered */
        ret = mk_event_del(u->evl, &u->event);
        assert(ret == 0);

        /* Check the connection status */
        if (u->event.mask & MK_EVENT_WRITE) {
            ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
            if (ret == -1) {
                flb_error("[io] could not validate socket status");
                return -1;
            }

            if (error != 0) {
                /* Connection is broken, not much to do here */
                flb_debug("[io] connection failed");
                return -1;
            }
            u->event.mask   = MK_EVENT_EMPTY;
            u->event.status = MK_EVENT_NONE;
        }
        else {
            return -1;
        }
    }

    flb_debug("[io] connection OK");
    return 0;
}
Example #8
0
/* This routine is called from a co-routine thread */
FLB_INLINE int net_io_write(struct flb_thread *th, struct flb_io_upstream *u,
                            void *data, size_t len, size_t *out_len)
{
    int ret = 0;
    ssize_t bytes;
    size_t total = 0;

 retry:
    bytes = write(u->fd, data + total, len - total);
    flb_debug("[io] write(2)=%d", bytes);

    if (bytes == -1) {
        if (errno == EAGAIN) {
            return 0;
        }
        else {
            /* The connection routine may yield */
            flb_debug("[io] trying to reconnect");
            ret = flb_io_net_connect(u, th);
            if (ret == -1) {
                return -1;
            }

            /*
             * Reach here means the connection was successful, let's retry
             * to write(2).
             *
             * note: the flb_io_connect() uses asyncronous sockets, register
             * the file descriptor with the main event loop and yields until
             * the main event loop returns the control back (resume), doing a
             * 'retry' it's pretty safe.
             */
            goto retry;
        }
    }

    /* Update statistics */
    //flb_stats_update(out->stats_fd, ret, 0);

    /* Update counters */
    total += bytes;
    if (total < len) {
        if (u->event.status == MK_EVENT_NONE) {
            u->event.mask = MK_EVENT_EMPTY;
            u->thread = th;
            ret = mk_event_add(u->evl,
                               u->fd,
                               FLB_ENGINE_EV_THREAD,
                               MK_EVENT_WRITE, &u->event);
            if (ret == -1) {
                /*
                 * If we failed here there no much that we can do, just
                 * let the caller we failed
                 */
                close(u->fd);
                return -1;
            }
        }
        flb_thread_yield(th, MK_FALSE);
        goto retry;
    }

    if (u->event.status == MK_EVENT_REGISTERED) {
        /* We got a notification, remove the event registered */
        ret = mk_event_del(u->evl, &u->event);
        assert(ret == 0);
    }

    *out_len = total;
    return bytes;
}
Example #9
0
static inline void thread_cb_init_vars()
{
    int close;
    int type = libco_param.type;
    struct mk_vhost_handler *handler = libco_param.handler;
    struct mk_http_session *session = libco_param.session;
    struct mk_http_request *request = libco_param.request;
    struct mk_thread *th = libco_param.th;
    struct mk_http_thread *mth;
    //struct mk_plugin *plugin;

    /*
     * Until this point the th->callee already set the variables, so we
     * wait until the core wanted to resume so we really trigger the
     * output callback.
     */
    co_switch(th->caller);

    if (type == MK_HTTP_THREAD_LIB) {
        /* Invoke the handler callback */
        handler->cb(request, handler->data);

        /*
         * Once the callback finished, we need to sanitize the connection
         * so other further requests can be processed.
         */
        int ret;
        struct mk_sched_worker *sched;
        struct mk_channel *channel;

        channel = request->session->channel;
        sched = mk_sched_get_thread_conf();

        MK_EVENT_NEW(channel->event);
        ret = mk_event_add(sched->loop,
                           channel->fd,
                           MK_EVENT_CONNECTION,
                           MK_EVENT_READ, channel->event);
        if (ret == -1) {
            //return -1;
        }

        /* Save temporal session */
        mth = request->thread;

        /*
         * Finalize request internally, if ret == -1 means we should
         * ask to shutdown the connection.
         */
        ret = mk_http_request_end(session, session->server);
        if (ret == -1) {
            close = MK_TRUE;
        }
        else {
            close = MK_FALSE;
        }
        mk_http_thread_purge(mth, close);

        /* Return control to caller */
        mk_thread_yield(th);
    }
    else if (type == MK_HTTP_THREAD_PLUGIN) {
        /* FIXME: call plugin handler callback with params */
    }
}
Example #10
0
/*
 * This routine perform a TCP connection and the required TLS/SSL
 * handshake,
 */
FLB_INLINE int flb_io_net_tls_connect(struct flb_io_upstream *u,
                                      struct flb_thread *th)
{
    int fd;
    int ret;
    int error = 0;
    int flag;
    socklen_t len = sizeof(error);
    struct flb_tls_session *session;

    if (u->fd > 0) {
        close(u->fd);
    }

    /* Create the socket */
    fd = flb_net_socket_create(AF_INET, FLB_TRUE);
    if (fd == -1) {
        flb_error("[io] could not create socket");
        return -1;
    }
    u->fd = fd;

    /* Make the socket non-blocking */
    flb_net_socket_nonblocking(u->fd);

    /* Start the connection */
    ret = flb_net_tcp_fd_connect(fd, u->tcp_host, u->tcp_port);
    if (ret == -1) {
        if (errno == EINPROGRESS) {
            flb_debug("[upstream] connection in process");
        }
        else {
            close(u->fd);
            if (u->tls_session) {
                tls_session_destroy(u->tls_session);
                u->tls_session = NULL;
            }
            return -1;
        }

        MK_EVENT_NEW(&u->event);
        u->thread = th;

        ret = mk_event_add(u->evl,
                           fd,
                           FLB_ENGINE_EV_THREAD,
                           MK_EVENT_WRITE, &u->event);
        if (ret == -1) {
            /*
             * If we failed here there no much that we can do, just
             * let the caller we failed
             */
            flb_error("[io_tls] connect failed registering event");
            close(fd);
            return -1;
        }

        /*
         * Return the control to the parent caller, we need to wait for
         * the event loop to get back to us.
         */
        flb_thread_yield(th, FLB_FALSE);

        /* Check the connection status */
        if (u->event.mask & MK_EVENT_WRITE) {
            ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len);
            if (ret == -1) {
                flb_error("[io_tls] could not validate socket status");
                goto error;
            }

            if (error != 0) {
                /* Connection is broken, not much to do here */
                flb_error("[io_tls] connection failed");
                goto error;
            }
        }
        else {
            return -1;
        }
    }

    /* Configure TLS and prepare handshake */
    session = u->tls_session;
    mbedtls_ssl_set_bio(&session->ssl,
                        u,
                        mbedtls_net_send, mbedtls_net_recv, NULL);

 retry_handshake:
    ret = mbedtls_ssl_handshake(&session->ssl);

    if (ret != 0) {
        if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
            ret !=  MBEDTLS_ERR_SSL_WANT_WRITE) {
            io_tls_error(ret);
            goto error;
        }

        if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
            flag = MK_EVENT_WRITE;
        }
        else if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
            flag = MK_EVENT_READ;
        }
        else {

        }

        /*
         * FIXME: if we need multiple reads we are invoking the same
         * system call multiple times.
         */
        ret = mk_event_add(u->evl,
                           u->event.fd,
                           FLB_ENGINE_EV_THREAD,
                           flag, &u->event);
        if (ret == -1) {
            goto error;
        }

        flb_thread_yield(th, FLB_FALSE);
        goto retry_handshake;
    }
    else {
        flb_debug("[io_tls] Handshake OK");
    }

    if (u->event.status == MK_EVENT_REGISTERED) {
        mk_event_del(u->evl, &u->event);
    }
    flb_debug("[io_tls] connection OK");
    return 0;

 error:
    if (u->event.status == MK_EVENT_REGISTERED) {
        mk_event_del(u->evl, &u->event);
    }

    return -1;
}