aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPreston Pan <ret2pop@gmail.com>2024-12-24 21:11:06 -0800
committerPreston Pan <ret2pop@gmail.com>2024-12-24 21:11:06 -0800
commite75d6f6b8f4512a5bbfecbfa8c17f0bb687e3d55 (patch)
tree7a96002751a1ca3b173762a13b181ebea4123817 /src
first commit
Diffstat (limited to 'src')
-rw-r--r--src/array.c37
-rw-r--r--src/better_string.c51
-rw-r--r--src/helpers.c28
-rw-r--r--src/main.c211
-rw-r--r--src/opcodes.c26
5 files changed, 353 insertions, 0 deletions
diff --git a/src/array.c b/src/array.c
new file mode 100644
index 0000000..84ed938
--- /dev/null
+++ b/src/array.c
@@ -0,0 +1,37 @@
+#include <array.h>
+#include <helpers.h>
+#include <stdlib.h>
+
+array_t *init_array() {
+ array_t *a = safe_calloc(1, sizeof(array_t));
+ a->capacity = DEFAULT_ARR_LEN;
+ a->size = 0;
+ a->items = safe_calloc(a->capacity, sizeof(void *));
+ return a;
+}
+
+void array_push(array_t *a, void *item) {
+ if (a->size >= a->capacity - 2) {
+ a->capacity *= 2;
+ a->items = realloc(a->items, a->capacity);
+ }
+ a->items[a->size] = item;
+ a->size++;
+}
+
+void *array_pop(array_t *a) {
+ if (a->size <= 0)
+ return NULL;
+ void *retval = a->items[a->size];
+ a->size--;
+ return retval;
+}
+
+void array_free(void *x, void (*freefunc)(void *)) {
+ array_t *a = (array_t *)x;
+ for (int i = 0; i < a->size; i++) {
+ freefunc(a->items[i]);
+ }
+ free(a->items);
+ free(a);
+}
diff --git a/src/better_string.c b/src/better_string.c
new file mode 100644
index 0000000..4413f77
--- /dev/null
+++ b/src/better_string.c
@@ -0,0 +1,51 @@
+#include <better_string.h>
+#include <helpers.h>
+#include <stdlib.h>
+#include <string.h>
+
+string_t *init_string(const char *src) {
+ string_t *s = safe_calloc(1, sizeof(string_t));
+ size_t len = src ? strlen(src) : DEFAULT_STR_SIZE;
+ size_t size = len * 2;
+ s->buf = safe_calloc(size, sizeof(char));
+ s->buf[0] = '\0';
+
+ if (src)
+ strcpy(s->buf, src);
+ s->len = len;
+ s->size = size;
+ return s;
+}
+
+void string_push(string_t *s, char c) {
+ if (s->len >= s->size - 2) {
+ s->size *= 2;
+ s->buf = safe_realloc(s->buf, s->size);
+ }
+ s->buf[s->len] = c;
+ s->len++;
+}
+
+char string_pop(string_t *s) {
+ char c = s->buf[s->len];
+ s->len--;
+ return c;
+}
+
+void string_concat_const(string_t *s1, const char *s2) {
+ for (int i = 0; i < strlen(s2); i++) {
+ string_push(s1, s2[i]);
+ }
+}
+
+void string_concat(string_t *s1, string_t *s2) {
+ for (int i = 0; i < s2->len; i++) {
+ string_push(s1, s2->buf[i]);
+ }
+}
+
+void string_free(void *x) {
+ string_t *s = x;
+ free(s->buf);
+ free(s);
+}
diff --git a/src/helpers.c b/src/helpers.c
new file mode 100644
index 0000000..ad7228e
--- /dev/null
+++ b/src/helpers.c
@@ -0,0 +1,28 @@
+#include <helpers.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void die(const char *msg) {
+ fprintf(stderr, "panic: ");
+ perror(msg);
+ exit(EXIT_FAILURE);
+}
+
+void *safe_calloc(unsigned int i, size_t size) {
+ void *x = calloc(i, size);
+ if (x == NULL) {
+ die("abort: calloc()");
+ }
+ return x;
+}
+
+void *safe_realloc(void *x, size_t size) {
+ void *p = realloc(x, size);
+ if (x == NULL) {
+ die("abort: realloc()");
+ }
+ return p;
+}
+
+void alloc_zero(void *ptr, size_t size) { memset(ptr, 0, size); }
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..8555da1
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,211 @@
+#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 <array.h>
+#include <better_string.h>
+#include <helpers.h>
+#include <opcodes.h>
+#include <protocol.h>
+
+int PORT = DEFAULT_PORT;
+int nfds = 1;
+struct pollfd fds[MAX_CONNECTIONS * 2];
+
+void handle_sigint(int sig) {
+ for (int i = 0; i < nfds; i++) {
+ if (fds[i].fd >= 0) {
+ close(fds[i].fd);
+ }
+ }
+
+ exit(0);
+}
+
+/* modifying function: modifies `in` to point to new location after opcode */
+int parse_op(char *in) {
+ char buf[MAX_OP_LEN];
+ buf[0] = '\0';
+
+ char cur;
+ cur = in[0];
+
+ bool found = false;
+ for (int i = 0; i < 11; i++) {
+ if (cur == '\t') {
+ found = true;
+ in++;
+ break;
+ } else if (cur == '\0') {
+ break;
+ }
+
+ buf[i] = in[0];
+ in++;
+ cur = in[0];
+ }
+
+ return found ? encode_client_opcode(buf) : CO_UNRECOGNIZED;
+}
+
+array_t *parse_args(char *buf) { return NULL; }
+
+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;
+}
diff --git a/src/opcodes.c b/src/opcodes.c
new file mode 100644
index 0000000..66742db
--- /dev/null
+++ b/src/opcodes.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <opcodes.h>
+#include <helpers.h>
+
+
+void die_lz(int code, const char *msg) {
+ if (code < 0) {
+ die(msg);
+ }
+}
+
+char *decode_client_opcode(int op) {
+ return "implement me";
+}
+
+char *decode_server_opcode(int op) {
+ return "implement me";
+}
+
+int encode_client_opcode(char *c) {
+ return -1;
+}
+
+int encode_server_opcode(char *c) {
+ return -1;
+}