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
This commit is contained in:
Philipp Moritz 2016-09-18 13:35:43 -07:00 committed by Robert Nishihara
parent ff11ee21ef
commit b18f214d55
6 changed files with 87 additions and 58 deletions

View file

@ -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:

View file

@ -1,4 +1,4 @@
#include "sockets.h"
#include "io.h"
#include <stdlib.h>
#include <unistd.h>
@ -6,6 +6,7 @@
#include <sys/un.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
#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;
}

21
io.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef IO_H
#define IO_H
#include <stdint.h>
/* 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

View file

@ -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

2
task.c
View file

@ -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

View file

@ -2,32 +2,39 @@
#include <assert.h>
#include <unistd.h>
#include <inttypes.h>
#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();
}