/** * Writes the data from a given input buffer * into the circular buffer. * @return 0 on success. */ int circbuf_write(circular_buffer *buf, char *in, uint64_t bytes) { // Check for available space uint64_t avail = circbuf_avail_buf(buf); while (avail < bytes) { circbuf_grow_buf(buf); avail = circbuf_avail_buf(buf); } if (buf->write_cursor < buf->read_cursor) { memcpy(buf->buffer+buf->write_cursor, in, bytes); buf->write_cursor += bytes; } else { uint64_t end_size = buf->buf_size - buf->write_cursor; if (end_size >= bytes) { memcpy(buf->buffer+buf->write_cursor, in, bytes); buf->write_cursor += bytes; } else { // Copy the first end_size bytes memcpy(buf->buffer+buf->write_cursor, in, end_size); // Copy the remaining data memcpy(buf->buffer, in+end_size, (bytes - end_size)); buf->write_cursor = (bytes - end_size); } } return 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; }
/** * Initializes the UDP Listener. * @arg netconf The network configuration * @return 0 on success. */ static int setup_udp_listener(statsite_networking *netconf) { if (netconf->config->udp_port == 0) { syslog(LOG_INFO, "UDP port is disabled"); return 0; } struct sockaddr_in addr; struct in_addr bind_addr; bzero(&addr, sizeof(addr)); bzero(&bind_addr, sizeof(bind_addr)); addr.sin_family = PF_INET; addr.sin_port = htons(netconf->config->udp_port); int ret = inet_pton(AF_INET, netconf->config->bind_address, &bind_addr); if (ret != 1) { syslog(LOG_ERR, "Invalid IPv4 address '%s'!", netconf->config->bind_address); return 1; } addr.sin_addr = bind_addr; // Make the socket, bind and listen int udp_listener_fd = socket(PF_INET, SOCK_DGRAM, 0); int optval = 1; if (setsockopt(udp_listener_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { syslog(LOG_ERR, "Failed to set SO_REUSEADDR! Err: %s", strerror(errno)); close(udp_listener_fd); return 1; } if (bind(udp_listener_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) { syslog(LOG_ERR, "Failed to bind on UDP socket! Err: %s", strerror(errno)); close(udp_listener_fd); return 1; } // Put the socket in non-blocking mode int flags = fcntl(udp_listener_fd, F_GETFL, 0); fcntl(udp_listener_fd, F_SETFL, flags | O_NONBLOCK); // Allocate a connection object for the UDP socket, // ensure a min-buffer size of 64K conn_info *conn = get_conn(); while (circbuf_avail_buf(&conn->input) < 65536) { circbuf_grow_buf(&conn->input); } netconf->udp_client.data = conn; syslog(LOG_INFO, "Listening on udp '%s:%d'.", netconf->config->bind_address, netconf->config->udp_port); // Create the libev objects ev_io_init(&netconf->udp_client, handle_udp_message, udp_listener_fd, EV_READ); ev_io_start(&netconf->udp_client); return 0; }
/** * Initializes the UDP Listener. * @arg netconf The network configuration * @return 0 on success. */ static int setup_udp_listener(statsite_proxy_networking *netconf) { struct sockaddr_in addr; bzero(&addr, sizeof(addr)); addr.sin_family = PF_INET; addr.sin_port = htons(netconf->config->udp_port); addr.sin_addr.s_addr = INADDR_ANY; // Make the socket, bind and listen int udp_listener_fd = socket(PF_INET, SOCK_DGRAM, 0); int optval = 1; if (setsockopt(udp_listener_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { syslog(LOG_ERR, "Failed to set SO_REUSEADDR! Err: %s", strerror(errno)); close(udp_listener_fd); return 1; } if (bind(udp_listener_fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) { syslog(LOG_ERR, "Failed to bind on UDP socket! Err: %s", strerror(errno)); close(udp_listener_fd); return 1; } // Allocate a connection object for the UDP socket, // ensure a min-buffer size of 64K conn_info *conn = get_conn(netconf); while (circbuf_avail_buf(&conn->input) < 65536) { circbuf_grow_buf(&conn->input); } netconf->udp_client.data = conn; // Create the libev objects ev_io_init(&netconf->udp_client, prepare_event, udp_listener_fd, EV_READ); ev_io_start(&netconf->udp_client); return 0; }
/** * Initializes the UDP Listener. * @arg netconf The network configuration * @return 0 on success. */ static int setup_udp_listener(statsite_networking *netconf) { if (netconf->config->udp_port == 0) { syslog(LOG_INFO, "UDP port is disabled"); return 0; } struct addrinfo hints; struct addrinfo *result, *rp; int s; int udp_listener_fd; int optval = 1; char udp_port[MAX_PORT_LEN]; memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = AI_PASSIVE; hints.ai_protocol = 0; /* Any protocol */ hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; snprintf(udp_port, MAX_PORT_LEN, "%d", netconf->config->udp_port); s = getaddrinfo(netconf->config->bind_address, udp_port, &hints, &result); if (s != 0) { syslog(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(s)); return 1; } for (rp = result; rp != NULL; rp = rp->ai_next) { udp_listener_fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (udp_listener_fd == -1) continue; if (setsockopt(udp_listener_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))) { syslog(LOG_ERR, "Failed to set SO_REUSEADDR! Err: %s", strerror(errno)); close(udp_listener_fd); continue; } if (bind(udp_listener_fd, rp->ai_addr, rp->ai_addrlen) == 0) break; syslog(LOG_ERR, "Failed to bind on UDP socket! Err: %s", strerror(errno)); close(udp_listener_fd); } if (rp == NULL) { /* No address succeeded */ syslog(LOG_ERR, "Failed to bind on any UDP socket!\n"); return 1; } // Put the socket in non-blocking mode int flags = fcntl(udp_listener_fd, F_GETFL, 0); fcntl(udp_listener_fd, F_SETFL, flags | O_NONBLOCK); // Allocate a connection object for the UDP socket, // ensure a min-buffer size of 64K conn_info *conn = get_conn(); while (circbuf_avail_buf(&conn->input) < 65536) { circbuf_grow_buf(&conn->input); } netconf->udp_client.data = conn; syslog(LOG_INFO, "Listening on udp '%s:%d'.", netconf->config->bind_address, netconf->config->udp_port); // Create the libev objects ev_io_init(&netconf->udp_client, handle_udp_message, udp_listener_fd, EV_READ); ev_io_start(&netconf->udp_client); return 0; }