summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnny Richard <johnny@johnnyrichard.com>2022-04-11 04:57:48 +0200
committerJohnny Richard <johnny@johnnyrichard.com>2022-04-11 04:57:48 +0200
commite83f1e89da0a8fb5527435a61743b9f0769caa7c (patch)
tree76c4d06874e6981b737406e80515acc8236e94c9
parent6108b3a1c10d66f8c446ee54acdbe52efcfdf4e8 (diff)
server.c: Reply to USER messages from client
-rw-r--r--Makefile2
-rw-r--r--server.c80
-rw-r--r--test.py13
3 files changed, 73 insertions, 22 deletions
diff --git a/Makefile b/Makefile
index 58bf569..d9a3929 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/server.c b/server.c
index 9a74222..16b3354 100644
--- a/server.c
+++ b/server.c
@@ -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);
}
diff --git a/test.py b/test.py
index e1e3028..9f6421e 100644
--- a/test.py
+++ b/test.py
@@ -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)]