#include <errno.h>
#include <netinet/tcp.h>
+#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <sys/epoll.h>
}
}
+const char ZERO[SOCKET_SEND_BUFFER_SIZE] = { 0 };
+
+struct fireperf_random_pool {
+ char* data;
+ size_t size;
+};
+
+static void fireperf_random_pool_free(struct fireperf_random_pool* pool) {
+ if (pool->data)
+ free(pool->data);
+
+ free(pool);
+}
+
+static struct fireperf_random_pool* fireperf_random_pool_create(struct fireperf_config* conf, size_t size) {
+ struct fireperf_random_pool* pool = calloc(1, sizeof(*pool));
+ if (!pool)
+ return NULL;
+
+ pool->size = size;
+
+ // Allocate the data array
+ pool->data = malloc(pool->size);
+ if (!pool->data)
+ goto ERROR;
+
+ size_t offset = 0;
+ while (offset < pool->size) {
+ offset += getrandom(pool->data + offset, pool->size - offset, 0);
+ }
+
+ DEBUG(conf, "Allocated random pool of %zu bytes(s)\n", pool->size);
+
+ return pool;
+
+ERROR:
+ fireperf_random_pool_free(pool);
+
+ return NULL;
+}
+
+static const char* fireperf_random_pool_get_slice(struct fireperf_random_pool* pool, size_t size) {
+ if (size > pool->size)
+ return NULL;
+
+ // Find a random value between the start and end of
+ // the data region that is at least size bytes long.
+ off_t offset = random() % (pool->size - size);
+
+ return pool->data + offset;
+}
+
static int connect_socket(struct fireperf_config* conf, int fd) {
DEBUG(conf, "(Re-)connecting socket %d...\n", fd);
return 0;
}
-/*
- This is just an example implementation because getrandom() is too slow for
- this purpose. I would need a really fast pseudo-RNG.
-*/
-static int randomize_buffer(char* buffer, size_t s) {
- ssize_t r = getrandom(buffer, s, 0);
-
- // Error
- if (r < 0)
- return 1;
-
- // We received less data than we wanted
- else if (r > 0 && (size_t)r < s)
- return 1;
-
- return 0;
-}
-
-static int send_data_to_server(struct fireperf_config* conf, int fd) {
- char buffer[SOCKET_SEND_BUFFER_SIZE] = { 0 };
+static int send_data_to_server(struct fireperf_config* conf, int fd,
+ struct fireperf_random_pool* pool) {
+ const char* buffer = ZERO;
ssize_t bytes_sent;
- DEBUG(conf, "Sending %zu bytes of data to server\n", sizeof(buffer));
-
- // Randomize the buffer if requested, otherwise just send an empty buffer
- if (!conf->zero) {
- int r = randomize_buffer(buffer, sizeof(buffer));
- if (r) {
- ERROR(conf, "Could not generate a random block of data: %s\n",
- strerror(errno));
- return 1;
- }
+ if (pool) {
+ buffer = fireperf_random_pool_get_slice(pool, SOCKET_SEND_BUFFER_SIZE);
}
do {
- bytes_sent = send(fd, buffer, sizeof(buffer), 0);
+ bytes_sent = send(fd, buffer, SOCKET_SEND_BUFFER_SIZE, 0);
} while (bytes_sent < 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
DEBUG(conf, "bytes_sent = %zu\n", bytes_sent);
}
int fireperf_client(struct fireperf_config* conf) {
+ struct fireperf_random_pool* pool = NULL;
+
DEBUG(conf, "Launching " PACKAGE_NAME " in client mode\n");
+ // Initialize random pool
+ if (!conf->zero) {
+ pool = fireperf_random_pool_create(conf, CLIENT_RANDOM_POOL_SIZE);
+ if (!pool) {
+ ERROR(conf, "Could not allocate random data\n");
+ return 1;
+ }
+ }
+
int r = 1;
int epollfd = -1;
goto ERROR;
} else if (events[i].events & EPOLLOUT) {
- r = send_data_to_server(conf, fd);
+ r = send_data_to_server(conf, fd, pool);
if (r)
goto ERROR;
}
if (epollfd > 0)
close(epollfd);
+ if (pool)
+ fireperf_random_pool_free(pool);
+
return r;
}