diff options
author | Johnny Richard <johnny@johnnyrichard.com> | 2022-04-11 04:57:48 +0200 |
---|---|---|
committer | Johnny Richard <johnny@johnnyrichard.com> | 2022-04-11 04:57:48 +0200 |
commit | e83f1e89da0a8fb5527435a61743b9f0769caa7c (patch) | |
tree | 76c4d06874e6981b737406e80515acc8236e94c9 | |
parent | 6108b3a1c10d66f8c446ee54acdbe52efcfdf4e8 (diff) |
server.c: Reply to USER messages from client
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | server.c | 80 | ||||
-rw-r--r-- | test.py | 13 |
3 files changed, 73 insertions, 22 deletions
@@ -7,7 +7,7 @@ all: main.c server.c log.c .PHONY: test test: libpapo.so - @python test.py + @python test.py -v --locals libpapo.so: server.o log.o $(CC) $(CFLAGS) -shared -o libpapo.so server.o log.o @@ -28,12 +28,20 @@ #include <unistd.h> #include <errno.h> -#define BUFFER_SIZE 1024 +#define BUFFER_SIZE 4096 #define EXIT_COMMAND "exit" #define EMPTY_CCLIENT_SPOT -1 +typedef struct client { + int fd; + char buf[BUFFER_SIZE]; + char msg_buf[BUFFER_SIZE]; + int msg_buf_i; +} client_t; + static void server_handle_client_data(server_t *server, struct epoll_event *event); static void server_handle_server_data(server_t *server, struct epoll_event *event); +static void server_on_client_msg(server_t *server, client_t *client); void server_init(server_t *server, uint32_t port) @@ -122,10 +130,10 @@ server_run(server_t *server) static void server_handle_server_data(server_t *server, struct epoll_event *event) { - struct sockaddr_in client; - socklen_t client_len = sizeof(client); + struct sockaddr_in clientaddr; + socklen_t client_len = sizeof(clientaddr); - int client_fd = accept(server->fd, (struct sockaddr *) &client, &client_len); + int client_fd = accept(server->fd, (struct sockaddr *) &clientaddr, &client_len); if (client_fd == -1) { log_error("could not accept connection: %s", strerror(errno)); close(server->fd); @@ -134,7 +142,16 @@ server_handle_server_data(server_t *server, struct epoll_event *event) struct epoll_event client_event; client_event.events = EPOLLIN; - client_event.data.fd = client_fd; + + client_t* client = (client_t *) malloc(sizeof(client_t)); + if (client == NULL) { + log_error("could not create client_t", strerror(errno)); + close(client_fd); + return; + } + + client->fd = client_fd; + client_event.data.ptr = (void *) client; if (epoll_ctl(server->epoll_fd, EPOLL_CTL_ADD, client_fd, &client_event) == -1) { log_error("could not add server to epoll: %s", strerror(errno)); @@ -157,7 +174,8 @@ server_handle_server_data(server_t *server, struct epoll_event *event) static void server_handle_client_data(server_t *server, struct epoll_event *event) { - int client_fd = event->data.fd; + client_t* client = event->data.ptr; + int client_fd = client->fd; if (event->events & EPOLLHUP) { for (int j = 0; j < MAXEVENTS; ++j) { if (server->connected_clients[j] == client_fd) { @@ -167,31 +185,55 @@ server_handle_client_data(server_t *server, struct epoll_event *event) } return; } - char client_buf[BUFFER_SIZE]; - memset(client_buf, 0, BUFFER_SIZE); + memset(client->buf, 0, BUFFER_SIZE); - if (recv(client_fd, client_buf, BUFFER_SIZE, 0) == -1) { + int readn = recv(client_fd, client->buf, BUFFER_SIZE, 0); + if (readn == -1) { log_error("could not read data from client: %s", strerror(errno)); return; } - if (!strncasecmp(client_buf, EXIT_COMMAND, strlen(EXIT_COMMAND) - 1)) { + + size_t buf_i = 0; + while (buf_i < readn) { + for (; client->buf[buf_i] != '\n' && buf_i < readn; ++client->msg_buf_i, ++buf_i) { + client->msg_buf[client->msg_buf_i] = client->buf[buf_i]; + } + if (buf_i < readn) { + client->msg_buf[client->msg_buf_i] = '\0'; + client->msg_buf_i = 0; + + log_debug("Message received from client (%d): %s", client->fd, client->msg_buf); + + server_on_client_msg(server, client); + + buf_i++; + } + } + + if (!strncasecmp(client->buf, EXIT_COMMAND, strlen(EXIT_COMMAND) - 1)) { log_debug("exiting program. bye bye!"); server->running = false; } +} - for (int j = 0; j < MAXEVENTS; ++j) { - if (server->connected_clients[j] == EMPTY_CCLIENT_SPOT) { - continue; - } +static void +server_on_client_msg(server_t *server, client_t *client) +{ + char* msg = strdup(client->msg_buf); + char* token = strtok(msg, " "); - char message[BUFFER_SIZE]; - memset(message, 0, sizeof(char) * BUFFER_SIZE); + if (!strcmp(token, "USER")) { + token = strtok(NULL, " "); - sprintf(message, "client_%d :%s", client_fd, client_buf); - if (send(server->connected_clients[j], message, BUFFER_SIZE, 0) == -1) { + log_debug("Sending message: 001 %s :Welcome!", token); + char reply[128]; + sprintf(reply, "001 %s :Welcome!\r\n", token); + if (send(client->fd, reply, strlen(reply) + 1, 0) == -1) { log_error("could not send data to client: %s", strerror(errno)); - continue; + goto exit; } } +exit: + free(msg); } @@ -4,10 +4,14 @@ import threading import time import unittest + libpapo = ctypes.CDLL('./libpapo.so') +unittest.util._MAX_LENGTH=2000 + class PapoServerTest(unittest.TestCase): + @classmethod def setUpClass(cls): server = papo_server(); @@ -15,23 +19,27 @@ class PapoServerTest(unittest.TestCase): thread.start() time.sleep(2) + @classmethod def tearDownClass(cls): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(('localhost', 6667)) s.sendall(b'exit') + @classmethod def run_papo_server(cls, server): libpapo.server_init(ctypes.byref(server), 6667) libpapo.server_run(ctypes.byref(server)) + def test_server_run(self): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.connect(('localhost', 6667)) - s.sendall(b'A msg from client') + s.sendall(b'USER username 0 * :User Name\r\n') data = s.recv(1024) - self.assertIn(b':A msg from client', data) + self.assertIn(b'001 username :Welcome!\r\n', data) + class epoll_data(ctypes.Union): _fields_ = [('ptr', ctypes.c_void_p), @@ -39,6 +47,7 @@ class epoll_data(ctypes.Union): ('u32', ctypes.c_uint), ('u64', ctypes.c_ulong)] + class epoll_event(ctypes.Structure): _fields_ = [('events', ctypes.c_uint), ('epoll_data_t', epoll_data)] |