/** * 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; }
/** * 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); } }