aboutsummaryrefslogtreecommitdiff
path: root/src/ramen
diff options
context:
space:
mode:
authorPreston Pan <ret2pop@gmail.com>2024-12-28 16:47:43 -0800
committerPreston Pan <ret2pop@gmail.com>2024-12-28 16:47:43 -0800
commit1fd608288ee47c2c560817f12f14b21069fed2f6 (patch)
treee6460b92dba5bb0d089c8c2a4e794e3504098359 /src/ramen
parent63f11aaec8d21844a07fd27003a992c102a3a297 (diff)
makefile and directory structure change completely to build client and server
Diffstat (limited to 'src/ramen')
-rw-r--r--src/ramen/main.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/src/ramen/main.c b/src/ramen/main.c
new file mode 100644
index 0000000..e98b452
--- /dev/null
+++ b/src/ramen/main.c
@@ -0,0 +1,201 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "../include/tsv.h"
+#include "../include/array.h"
+#include "../include/better_string.h"
+#include "../include/hash_table.h"
+#include "../include/helpers.h"
+#include "../include/opcodes.h"
+#include "../include/protocol.h"
+
+int PORT = DEFAULT_PORT;
+int nfds = 1;
+struct pollfd fds[MAX_CONNECTIONS * 2];
+
+ht_t *USERS;
+ht_t *CHAN;
+
+void handle_sigint(int sig) {
+ for (int i = 0; i < nfds; i++) {
+ if (fds[i].fd >= 0) {
+ close(fds[i].fd);
+ }
+ }
+
+ exit(0);
+}
+
+array_t *parse_args(char *buf) {
+ tsv_t *tsv = init_tsv(buf);
+ string_t *s = tsv_next(tsv);
+ array_t *a = init_array();
+ while (s) {
+ array_push(a, s);
+ s = tsv_next(tsv);
+ }
+
+ a = array_reverse(a);
+ return a;
+}
+
+void set_non_blocking(int sock) {
+ int flags = fcntl(sock, F_GETFL, 0);
+ int code = fcntl(sock, F_SETFL, flags | O_NONBLOCK);
+ die_lz(code, "fcntl()");
+}
+
+int main(int argc, char **argv) {
+ char buffer[MAX_BUFSIZE];
+ char res_buffer[MAX_BUFSIZE];
+ struct pollfd *local_fds1 = fds;
+ struct pollfd *local_fds2 = fds + MAX_CONNECTIONS;
+ struct pollfd *local_fds = local_fds1;
+
+ /* We start by initializing our net-related structs */
+ signal(SIGINT, handle_sigint);
+
+ int listen_sd = socket(AF_INET6, SOCK_STREAM, 0);
+ int optval = 1;
+ die_lz(listen_sd, "socket()");
+
+ int reuse = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *)&optval,
+ sizeof(optval));
+ die_lz(reuse, "setsockopt()");
+
+ int nonblock = ioctl(listen_sd, FIONBIO, (char *)&optval);
+ die_lz(nonblock, "ioctl()");
+
+ set_non_blocking(listen_sd);
+
+ /* Make new address */
+ struct sockaddr_in6 addr;
+ alloc_zero(&addr, sizeof(addr));
+
+ addr.sin6_family = AF_INET6;
+ memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
+ addr.sin6_port = htons(DEFAULT_PORT);
+
+ int sock_bind = bind(listen_sd, (struct sockaddr *)&addr, sizeof(addr));
+ die_lz(sock_bind, "bind()");
+
+ int sock_listen = listen(listen_sd, 32);
+ die_lz(sock_listen, "listen()");
+
+ /*
+ The first fd entry is the listening socket for new connections;
+ all the rest are sockets we read from and write to. Whenever a client
+ connects, we know from the listening socket.
+ */
+
+ alloc_zero(fds, sizeof(fds));
+ fds[0].fd = listen_sd;
+ fds[0].events = POLLIN;
+
+ int timeout = 6000;
+ int sock_poll;
+ bool end_server = false;
+
+ /* mainloop */
+ do {
+ bool compress_array = false;
+ /*
+ if an fd loses connection, we want to remove all -1's from the fds array
+ */
+
+ sock_poll = poll(local_fds, nfds, timeout);
+ die_lz(sock_poll, "poll()");
+
+ for (int i = 0; i < nfds; i++) {
+ if (local_fds[i].revents == 0)
+ continue;
+
+ if (local_fds[i].revents != POLLIN) {
+ end_server = true;
+ break;
+ }
+
+ if (local_fds[i].fd == listen_sd) {
+ printf("socket is readable\n");
+ int new_sd;
+
+ do {
+ new_sd = accept(listen_sd, NULL, NULL);
+
+ if (new_sd < 0 && errno != EWOULDBLOCK) {
+ perror("accept() failed");
+ end_server = true;
+ break;
+ }
+
+ local_fds[nfds].fd = new_sd;
+ local_fds[nfds].events = POLLIN;
+ nfds++;
+ } while (new_sd >= 0);
+ } else {
+ bool close_conn = false;
+ int fd_recv;
+ int fd_send;
+ fd_recv = recv(local_fds[i].fd, buffer, sizeof(buffer), 0);
+
+ if (fd_recv < 0 && errno != EWOULDBLOCK) {
+ perror("recv() failed");
+ close_conn = true;
+ } else if (fd_recv == 0) {
+ printf("Connection closed\n");
+ close_conn = true;
+ } else {
+ /* echo server -- replace this with buffer parsing */
+ /* TODO: reply to client based on user input */
+ fd_send = send(local_fds[i].fd, buffer, fd_recv, 0);
+ if (fd_send < 0) {
+ perror("send()");
+ close_conn = true;
+ }
+ }
+
+ if (close_conn) {
+ close(local_fds[i].fd);
+ local_fds[i].fd = 0;
+ compress_array = true;
+ }
+ }
+ }
+
+ if (compress_array) {
+ printf("switching...\n");
+ int cur_nfds = nfds;
+ nfds = 0;
+ for (int i = 0; i < cur_nfds; i++) {
+ if (local_fds[i].fd != 0) {
+ local_fds2[nfds] = local_fds[i];
+ nfds ++;
+ }
+ }
+
+ local_fds1 = local_fds2;
+ local_fds2 = local_fds;
+ local_fds = local_fds1;
+ alloc_zero(local_fds2, MAX_CONNECTIONS);
+ }
+ } while (!end_server);
+
+ for (int i = 0; i < nfds; i++) {
+ if (fds[i].fd >= 0) {
+ close(fds[i].fd);
+ }
+ }
+
+ return 0;
+}