示例#1
0
/**
 * Invoked when a client connection has data 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 int read_client_data(conn_info *conn) {
    /**
     * Figure out how much space we have to write.
     * If we have < 50% free, we resize the buffer using
     * a multiplier.
     */
    int avail_buf = circbuf_avail_buf(&conn->input);
    if (avail_buf < conn->input.buf_size / 2) {
        circbuf_grow_buf(&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
    ssize_t read_bytes = readv(conn->client.fd, (struct iovec*)&vectors, num_vectors);

    // Make sure we actually read something
    if (read_bytes == 0) {
        syslog(LOG_DEBUG, "Closed client connection. [%d]\n", conn->client.fd);
        return 1;
    } else if (read_bytes == -1) {
        if (errno != EAGAIN && errno != EINTR) {
            syslog(LOG_ERR, "Failed to read() from connection [%d]! %s.",
                    conn->client.fd, strerror(errno));
        }
        return 1;
    }

    // Update the write cursor
    circbuf_advance_write(&conn->input, read_bytes);
    return 0;
}
示例#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);
    }
}