From b18f214d555d353daee304b69718e0acc2e8440d Mon Sep 17 00:00:00 2001 From: Philipp Moritz Date: Sun, 18 Sep 2016 13:35:43 -0700 Subject: [PATCH] Make it possible to read and write data that is not null-terminated (#9) * Make it possible to read and write data that is not null-terminated * formating --- Makefile | 12 ++--- sockets.c => io.c | 74 +++++++++++++++++------------ io.h | 21 ++++++++ sockets.h | 11 ----- task.c | 2 +- test/{socket_tests.c => io_tests.c} | 25 ++++++---- 6 files changed, 87 insertions(+), 58 deletions(-) rename sockets.c => io.c (70%) create mode 100644 io.h delete mode 100644 sockets.h rename test/{socket_tests.c => io_tests.c} (57%) diff --git a/Makefile b/Makefile index d02a9cb53..e1c894737 100644 --- a/Makefile +++ b/Makefile @@ -9,11 +9,11 @@ CFLAGS += -Wmissing-declarations $(BUILD)/db_tests: hiredis test/db_tests.c thirdparty/greatest.h event_loop.c state/redis.c common.c $(CC) -o $@ test/db_tests.c event_loop.c state/redis.c common.c thirdparty/hiredis/libhiredis.a $(CFLAGS) -I. -Ithirdparty -$(BUILD)/socket_tests: test/socket_tests.c thirdparty/greatest.h sockets.c - $(CC) -o $@ test/socket_tests.c sockets.c $(CFLAGS) -I. -Ithirdparty +$(BUILD)/io_tests: test/io_tests.c thirdparty/greatest.h io.c + $(CC) -o $@ test/io_tests.c io.c $(CFLAGS) -I. -Ithirdparty -$(BUILD)/task_tests: test/task_tests.c task.c sockets.c common.h - $(CC) -o $@ test/task_tests.c task.c sockets.c $(CFLAGS) -I. -Ithirdparty +$(BUILD)/task_tests: test/task_tests.c task.c io.c common.h + $(CC) -o $@ test/task_tests.c task.c io.c $(CFLAGS) -I. -Ithirdparty clean: rm -r $(BUILD)/* @@ -24,8 +24,8 @@ redis: hiredis: git submodule update --init --recursive -- "thirdparty/hiredis" ; cd thirdparty/hiredis ; make -test: hiredis redis $(BUILD)/db_tests $(BUILD)/socket_tests $(BUILD)/task_tests FORCE +test: hiredis redis $(BUILD)/db_tests $(BUILD)/io_tests $(BUILD)/task_tests FORCE ./thirdparty/redis-3.2.3/src/redis-server & - sleep 1s ; ./build/db_tests ; ./build/socket_tests ; ./build/task_tests + sleep 1s ; ./build/db_tests ; ./build/io_tests ; ./build/task_tests FORCE: diff --git a/sockets.c b/io.c similarity index 70% rename from sockets.c rename to io.c index 82ca490f7..1d16a78e0 100644 --- a/sockets.c +++ b/io.c @@ -1,4 +1,4 @@ -#include "sockets.h" +#include "io.h" #include #include @@ -6,6 +6,7 @@ #include #include #include +#include #include "common.h" @@ -74,22 +75,6 @@ int connect_ipc_sock(const char *socket_pathname) { return socket_fd; } -/* Sends a message on the given socket file descriptor. */ -void send_ipc_sock(int socket_fd, char *message) { - int length = strlen(message); - int nbytes; - nbytes = write(socket_fd, (char *) &length, sizeof(length)); - if (nbytes == -1) { - LOG_ERR("Error sending to socket.\n"); - return; - } - nbytes = write(socket_fd, (char *) message, length * sizeof(char)); - if (nbytes == -1) { - LOG_ERR("Error sending to socket.\n"); - return; - } -} - /* Accept a new client connection on the given socket * descriptor. Returns a descriptor for the new socket. */ int accept_client(int socket_fd) { @@ -105,25 +90,52 @@ int accept_client(int socket_fd) { return client_fd; } -/* Receives a message on the given socket file descriptor. Allocates and - * returns a pointer to the message. - * NOTE: Caller must free the message! */ -char *recv_ipc_sock(int socket_fd) { - int length; - int nbytes; - nbytes = read(socket_fd, &length, sizeof(length)); +/* Write a sequence of bytes on a file descriptor. */ +void write_bytes(int fd, uint8_t *bytes, int64_t length) { + ssize_t nbytes = write(fd, (char *) &length, sizeof(length)); + if (nbytes == -1) { + LOG_ERR("Error sending to socket.\n"); + return; + } + nbytes = write(fd, (char *) bytes, length * sizeof(char)); + if (nbytes == -1) { + LOG_ERR("Error sending to socket.\n"); + return; + } +} + +/* Read a sequence of bytes written by write_bytes from a file descriptor. + * Allocates and returns a pointer to the bytes. + * NOTE: Caller must free the memory! */ +void read_bytes(int fd, uint8_t **bytes, int64_t *length) { + ssize_t nbytes = read(fd, length, sizeof(int64_t)); if (nbytes < 0) { LOG_ERR("Error reading length of message from socket."); - return NULL; + *bytes = NULL; + return; } - char *message = malloc((length + 1) * sizeof(char)); - nbytes = read(socket_fd, message, length); + *bytes = malloc(*length * sizeof(uint8_t)); + nbytes = read(fd, *bytes, *length); if (nbytes < 0) { LOG_ERR("Error reading message from socket."); - free(message); - return NULL; + free(*bytes); + *bytes = NULL; } - message[length] = '\0'; - return message; +} + +/* Write a null-terminated string to a file descriptor. */ +void write_string(int fd, char *message) { + /* Account for the \0 at the end of the string. */ + write_bytes(fd, (uint8_t *) message, strlen(message) + 1); +} + +/* Reads a null-terminated string from the file descriptor that has been + * written by write_string. Allocates and returns a pointer to the string. + * NOTE: Caller must free the memory! */ +char *read_string(int fd) { + uint8_t *bytes; + int64_t length; + read_bytes(fd, &bytes, &length); + return (char *) bytes; } diff --git a/io.h b/io.h new file mode 100644 index 000000000..c6dd3bb30 --- /dev/null +++ b/io.h @@ -0,0 +1,21 @@ +#ifndef IO_H +#define IO_H + +#include + +/* Helper functions for socket communication. */ + +int bind_ipc_sock(const char *socket_pathname); +int connect_ipc_sock(const char *socket_pathname); + +int accept_client(int socket_fd); + +/* Reading and writing data */ + +void write_bytes(int fd, uint8_t *bytes, int64_t length); +void read_bytes(int fd, uint8_t **bytes, int64_t *length); + +void write_string(int fd, char *message); +char *read_string(int fd); + +#endif diff --git a/sockets.h b/sockets.h deleted file mode 100644 index a563470c9..000000000 --- a/sockets.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef SOCKETS_H -#define SOCKETS_H - -/* Helper functions for socket communication. */ -int bind_ipc_sock(const char* socket_pathname); -int connect_ipc_sock(const char* socket_pathname); -void send_ipc_sock(int socket_fd, char* message); -int accept_client(int socket_fd); -char* recv_ipc_sock(int socket_fd); - -#endif diff --git a/task.c b/task.c index c337cc1a3..3f3c01661 100644 --- a/task.c +++ b/task.c @@ -4,7 +4,7 @@ #include "task.h" #include "common.h" -#include "sockets.h" +#include "io.h" /* Tasks are stored in a consecutive chunk of memory, the first * sizeof(task_spec) bytes are arranged according to the struct diff --git a/test/socket_tests.c b/test/io_tests.c similarity index 57% rename from test/socket_tests.c rename to test/io_tests.c index b57ab9000..9216aa56e 100644 --- a/test/socket_tests.c +++ b/test/io_tests.c @@ -2,32 +2,39 @@ #include #include +#include -#include "sockets.h" +#include "io.h" -SUITE(socket_tests); +SUITE(io_tests); TEST ipc_socket_test(void) { - const char* socket_pathname = "test-socket"; + const char *socket_pathname = "test-socket"; int socket_fd = bind_ipc_sock(socket_pathname); ASSERT(socket_fd >= 0); - char* test_string = "hello world"; + char *test_string = "hello world"; + char *test_bytes = "another string"; pid_t pid = fork(); if (pid == 0) { close(socket_fd); socket_fd = connect_ipc_sock(socket_pathname); ASSERT(socket_fd >= 0); - send_ipc_sock(socket_fd, test_string); + write_string(socket_fd, test_string); + write_bytes(socket_fd, (uint8_t *) test_bytes, strlen(test_bytes)); close(socket_fd); exit(0); } else { int client_fd = accept_client(socket_fd); ASSERT(client_fd >= 0); - char* message = recv_ipc_sock(client_fd); + char *message = read_string(client_fd); ASSERT(message != NULL); ASSERT_STR_EQ(test_string, message); free(message); + int64_t len; + uint8_t *bytes; + read_bytes(client_fd, &bytes, &len); + ASSERT(memcmp(test_bytes, bytes, len) == 0); close(client_fd); close(socket_fd); unlink(socket_pathname); @@ -36,14 +43,14 @@ TEST ipc_socket_test(void) { PASS(); } -SUITE(socket_tests) { +SUITE(io_tests) { RUN_TEST(ipc_socket_test); } GREATEST_MAIN_DEFS(); -int main(int argc, char** argv) { +int main(int argc, char **argv) { GREATEST_MAIN_BEGIN(); - RUN_SUITE(socket_tests); + RUN_SUITE(io_tests); GREATEST_MAIN_END(); }