static int send_client_response_buffered(conn_info *conn, char **response_buffers, int *buf_sizes, int num_bufs) { // Copy the buffers to the output buffer int res = 0; for (int i=0; i< num_bufs; i++) { res = circbuf_write(&conn->output, response_buffers[i], buf_sizes[i]); if (res) break; } return res; }
static int send_client_response_direct(conn_info *conn, char **response_buffers, int *buf_sizes, int num_bufs) { // Stack allocate the iovectors struct iovec *vectors = alloca(num_bufs * sizeof(struct iovec)); // Setup all the pointers ssize_t total_bytes = 0; for (int i=0; i < num_bufs; i++) { vectors[i].iov_base = response_buffers[i]; vectors[i].iov_len = buf_sizes[i]; total_bytes += buf_sizes[i]; } // Perform the write ssize_t sent = writev(conn->client.fd, vectors, num_bufs); if (sent == total_bytes) return 0; // Check for a fatal error if (sent == -1) { if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { syslog(LOG_ERR, "Failed to send() to connection [%d]! %s.", conn->client.fd, strerror(errno)); close_client_connection(conn); return 1; } } // Figure out which buffer we left off on int skip_bytes = 0; int index = 0; for (index; index < num_bufs; index++) { skip_bytes += buf_sizes[index]; if (skip_bytes > sent) { skip_bytes -= buf_sizes[index]; break; } } // Copy the buffers int res, offset; for (int i=index; i < num_bufs; i++) { offset = 0; if (i == index && skip_bytes < sent) { offset = sent - skip_bytes; } res = circbuf_write(&conn->output, response_buffers[i] + offset, buf_sizes[i] - offset); if (res) return 1; } // Setup the async write conn->use_write_buf = 1; ev_io_start(conn->thread_ev->loop, &conn->write_client); // Done return 0; }
static int send_proxy_msg_buffered(conn_info *conn, char *msg_buffer, int buf_size) { // Might not be using buffered writes anymore if (!conn->use_write_buf) { return send_proxy_msg_direct(conn, msg_buffer, buf_size); } // Copy the buffers to the output buffer int res = 0; return circbuf_write(&conn->output, msg_buffer, buf_size); }
/** * 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); } }
static int send_proxy_msg_direct(conn_info *conn, char *msg_buffer, int buf_size) { // Stack allocate the iovectors struct iovec vector; // Setup all the pointers vector.iov_base = msg_buffer; vector.iov_len = buf_size; // Perform the write ssize_t sent = writev(conn->client.fd, &vector, 1); if (sent == buf_size) return 0; // Check for a fatal error if (sent == -1) { if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) { syslog(LOG_ERR, "Failed to send() to connection [%d]! %s.", conn->client.fd, strerror(errno)); // Probably want to try and reopen connection here??? close_client_connection(conn); return 1; } } // Copy unsent data to circ buffer int res; if (sent < buf_size) { res = circbuf_write(&conn->output, msg_buffer + sent, buf_size - sent); if (res) { return 1; } } // Setup the async write conn->use_write_buf = 1; incref_client_connection(conn); schedule_async(conn->netconf, SCHEDULE_WATCHER, &conn->write_client); // Done return 0; }