mirror of
https://github.com/wassname/ray.git
synced 2026-08-08 11:25:28 +08:00
Sockets (#3)
* Socket methods to be used by an event loop * Git ignore build files * File renames * Some fixes * Fixes * Fixes * Memory leakage fix
This commit is contained in:
committed by
Philipp Moritz
parent
7d629d4e48
commit
73f4b96253
@@ -33,3 +33,6 @@
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
|
||||
# Build files
|
||||
build/*
|
||||
|
||||
@@ -9,6 +9,9 @@ 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
|
||||
|
||||
clean:
|
||||
rm -r $(BUILD)/*
|
||||
|
||||
@@ -18,7 +21,8 @@ redis:
|
||||
hiredis:
|
||||
git submodule update --init --recursive -- "thirdparty/hiredis" ; cd thirdparty/hiredis ; make
|
||||
|
||||
test: hiredis redis $(BUILD)/db_tests FORCE
|
||||
./thirdparty/redis-3.2.3/src/redis-server & sleep 1s ; ./build/db_tests
|
||||
test: hiredis redis $(BUILD)/db_tests $(BUILD)/socket_tests FORCE
|
||||
./thirdparty/redis-3.2.3/src/redis-server &
|
||||
sleep 1s ; ./build/db_tests ; ./build/socket_tests
|
||||
|
||||
FORCE:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "event_loop.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
UT_icd item_icd = {sizeof(event_loop_item), NULL, NULL, NULL};
|
||||
UT_icd poll_icd = {sizeof(struct pollfd), NULL, NULL, NULL};
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
#include "sockets.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/* Binds to a Unix domain datagram socket at the given
|
||||
* pathname. Removes any existing file at the pathname. Returns
|
||||
* a file descriptor for the socket, or -1 if an error
|
||||
* occurred. */
|
||||
int bind_ipc_sock(const char *socket_pathname) {
|
||||
struct sockaddr_un socket_address;
|
||||
int socket_fd;
|
||||
|
||||
socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (socket_fd < 0) {
|
||||
LOG_ERR("socket() failed for pathname %s.", socket_pathname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
unlink(socket_pathname);
|
||||
memset(&socket_address, 0, sizeof(struct sockaddr_un));
|
||||
socket_address.sun_family = AF_UNIX;
|
||||
if (strlen(socket_pathname) + 1 > sizeof(socket_address.sun_path)) {
|
||||
LOG_ERR("Socket pathname is too long.");
|
||||
return -1;
|
||||
}
|
||||
strncpy(socket_address.sun_path, socket_pathname,
|
||||
strlen(socket_pathname) + 1);
|
||||
|
||||
if (bind(socket_fd, (struct sockaddr *) &socket_address,
|
||||
sizeof(struct sockaddr_un)) != 0) {
|
||||
LOG_ERR("Bind failed for pathname %s.", socket_pathname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return socket_fd;
|
||||
}
|
||||
|
||||
/* Connects to a Unix domain datagram socket at the given
|
||||
* pathname. Returns a file descriptor for the socket, or -1 if
|
||||
* an error occurred. */
|
||||
int connect_ipc_sock(const char *socket_pathname) {
|
||||
struct sockaddr_un socket_address;
|
||||
int socket_fd;
|
||||
|
||||
socket_fd = socket(AF_UNIX, SOCK_DGRAM, 0);
|
||||
if (socket_fd < 0) {
|
||||
LOG_ERR("socket() failed for pathname %s.", socket_pathname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&socket_address, 0, sizeof(struct sockaddr_un));
|
||||
socket_address.sun_family = AF_UNIX;
|
||||
if (strlen(socket_pathname) + 1 > sizeof(socket_address.sun_path)) {
|
||||
LOG_ERR("Socket pathname is too long.");
|
||||
return -1;
|
||||
}
|
||||
strncpy(socket_address.sun_path, socket_pathname,
|
||||
strlen(socket_pathname) + 1);
|
||||
|
||||
if (connect(socket_fd, (struct sockaddr *) &socket_address,
|
||||
sizeof(struct sockaddr_un)) != 0) {
|
||||
LOG_ERR("Connection to socket failed for pathname %s.", socket_pathname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 = send(socket_fd, (char *) &length, sizeof(length), 0);
|
||||
if (nbytes == -1) {
|
||||
fprintf(stderr, "Error sending to socket.\n");
|
||||
return;
|
||||
}
|
||||
nbytes = send(socket_fd, (char *) message, length * sizeof(char), 0);
|
||||
if (nbytes == -1) {
|
||||
fprintf(stderr, "Error sending to socket.\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 = recv(socket_fd, &length, sizeof(length), 0);
|
||||
if (nbytes == -1) {
|
||||
fprintf(stderr, "Error receiving from socket.\n");
|
||||
return NULL;
|
||||
}
|
||||
char *message = malloc((length + 1) * sizeof(char));
|
||||
nbytes = recv(socket_fd, message, length * sizeof(char), 0);
|
||||
if (nbytes == -1) {
|
||||
fprintf(stderr, "Error receiving from socket.\n");
|
||||
return NULL;
|
||||
}
|
||||
message[length] = '\0';
|
||||
return message;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#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);
|
||||
char* recv_ipc_sock(int socket_fd);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#include "greatest.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sockets.h"
|
||||
|
||||
SUITE(event_loop_tests);
|
||||
|
||||
TEST ipc_socket_test(void) {
|
||||
const char* socket_pathname = "test-socket";
|
||||
int socket_fd = bind_ipc_sock(socket_pathname);
|
||||
ASSERT(socket_fd >= 0);
|
||||
|
||||
char* test_string = "hello world";
|
||||
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);
|
||||
close(socket_fd);
|
||||
} else {
|
||||
char* message = recv_ipc_sock(socket_fd);
|
||||
ASSERT(message != NULL);
|
||||
ASSERT_STR_EQ(test_string, message);
|
||||
free(message);
|
||||
close(socket_fd);
|
||||
unlink(socket_pathname);
|
||||
}
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
SUITE(event_loop_tests) {
|
||||
RUN_TEST(ipc_socket_test);
|
||||
}
|
||||
|
||||
GREATEST_MAIN_DEFS();
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
GREATEST_MAIN_BEGIN();
|
||||
RUN_SUITE(event_loop_tests);
|
||||
GREATEST_MAIN_END();
|
||||
}
|
||||
Reference in New Issue
Block a user