/**
 * Reads the thread specific userdata to figure out what
 * we need to handle. Things that purely effect the network
 * stack should be handled here, but otherwise we should defer
 * to the connection handlers.
 */
static void invoke_event_handler(worker_ev_userdata* data) {
    // Get the offending handle
    ev_io *watcher = data->watcher;
    int fd = watcher->fd;

    // Check if this is either of the listeners
    if (watcher == &data->netconf->tcp_client) {
        // Accept the new client
        handle_new_client(fd, data);

        // Reschedule the listener
        schedule_async(data->netconf, SCHEDULE_WATCHER, watcher);
        return;

    // If it is write ready, dispatch the write handler
    }  else if (data->ready_events & EV_WRITE) {
        handle_client_writebuf(watcher, data);
        return;
    }

    // Check for UDP inbound
    if (watcher == &data->netconf->udp_client) {
        // Read the message and process
        if (!handle_udp_message(watcher, data)) {
            statsite_proxy_conn_handler handle = {data->netconf->config, data->netconf->proxy, watcher->data};
            handle_client_connect(&handle);
        }

        // Reschedule the listener
        schedule_async(data->netconf, SCHEDULE_WATCHER, watcher);
        return;
    }

    /*
     * If it is not a listener, it must be a connected
     * client. We should just read all the available data,
     * append it to the buffers, and then invoke the
     * connection handlers.
     */
    conn_info *conn = watcher->data;
    incref_client_connection(conn);

    if (!handle_client_data(watcher, data)) {
        statsite_proxy_conn_handler handle = {data->netconf->config, data->netconf->proxy, watcher->data};
        handle_client_connect(&handle);
    }

    // Reschedule the watcher, unless told otherwise.
    if (conn->should_schedule) {
        schedule_async(data->netconf, SCHEDULE_WATCHER, watcher);
    }
    decref_client_connection(conn);
}
Exemple #2
0
/**
 * Invoked when a UDP connection has a message ready to be read.
 * We need to take care to add the data to our buffers, and then
 * invoke the connection handlers who have the business logic
 * of what to do.
 */
static void handle_udp_message(ev_io *watch, int ready_events) {
    while (1) {
        // Get the associated connection struct
        conn_info *conn = watch->data;

        // Clear the input buffer
        circbuf_clear(&conn->input);

        // Build the IO vectors to perform the read
        struct iovec vectors[2];
        int num_vectors;
        circbuf_setup_readv_iovec(&conn->input, (struct iovec*)&vectors, &num_vectors);

        /*
         * Issue the read, always use the first vector.
         * since we just cleared the buffer, and it should
         * be a contiguous buffer.
         */
        assert(num_vectors == 1);
        ssize_t read_bytes = recv(watch->fd, vectors[0].iov_base,
                                    vectors[0].iov_len, 0);

        // Make sure we actually read something
        if (read_bytes == 0) {
            syslog(LOG_DEBUG, "Got empty UDP packet. [%d]\n", watch->fd);
            return;

        } else if (read_bytes == -1) {
            if (errno != EAGAIN && errno != EINTR) {
                syslog(LOG_ERR, "Failed to recv() from connection [%d]! %s.",
                        watch->fd, strerror(errno));
            }
            return;
        }

        // Update the write cursor
        circbuf_advance_write(&conn->input, read_bytes);

        // UDP clients don't need to append newlines to the messages like
        // TCP clients do, but our parser requires them.  Append one if
        // it's not present.
        if (conn->input.buffer[conn->input.write_cursor - 1] != '\n')
            circbuf_write(&conn->input, "\n", 1);

        // Get the user data
        worker_ev_userdata *data = ev_userdata();

        // Invoke the connection handler
        statsite_conn_handler handle = {data->netconf->config, watch->data};
        handle_client_connect(&handle);
    }
}
Exemple #3
0
/**
 * Reads the thread specific userdata to figure out what
 * we need to handle. Things that purely effect the network
 * stack should be handled here, but otherwise we should defer
 * to the connection handlers.
 */
static void invoke_event_handler(ev_io *watcher, int ready_events) {
    // Get the user data
    worker_ev_userdata *data = ev_userdata();

    // Read in the data, and close on issues
    conn_info *conn = watcher->data;
    if (read_client_data(conn)) {
        close_client_connection(conn);
        return;
    }

    // Invoke the connection handler, and close connection on error
    statsite_conn_handler handle = {data->netconf->config, watcher->data};
    if (handle_client_connect(&handle))
        close_client_connection(conn);
}
Exemple #4
0
/*
 * Invoked when client read data is ready.
 * We just read all the available data,
 * append it to the buffers, and then invoke the
 * connection handlers.
 */
static void invoke_event_handler(ev_loop *lp, ev_io *watcher, int ready_events) {
    // Get the user data
    worker_ev_userdata *data = ev_userdata(lp);

    // Read in the data, and close on issues
    conn_info *conn = watcher->data;
    if (read_client_data(conn)) {
        close_client_connection(conn);
        return;
    }

    // Prepare to invoke the handler
    bloom_conn_handler handle;
    handle.config = data->netconf->config;
    handle.mgr = data->netconf->mgr;
    handle.conn = conn;

    // Reschedule the watcher, unless it's non-active now
    if (handle_client_connect(&handle) || !conn->active)
        close_client_connection(conn);
}