Summary Files Commits Branches @commit @diff @stats
path: root / src / sockets / socket_server.c
diff options
context:
space:
mode:
Commit74630b4bfe1aa887ef57ee57b22241d030b38d76 (patch)
Author
 Syndamia <kamen@syndamia.com>
2025-11-15 21:37:37 +0200
Committer
 Syndamia <kamen@syndamia.com>
2025-11-15 21:37:37 +0200
Files3d39c585df1551d69fdb83980c010ec4b579f211 /src/sockets/socket_server.c
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar.gz
tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.zip
Parent3bca23eaaa49fa01f60ecbc5e0a329d29f088506 (diff)
feat!: Initial web server base implementation
1 files changed, 99 insertions, 0 deletions
-rw-r--r--src/sockets/socket_server.c99
diff --git a/src/sockets/socket_server.c b/src/sockets/socket_server.c
new file mode 100644
index 0000000..5280341
--- /dev/null
+++ b/src/sockets/socket_server.c
@@ -0,0 +1,99 @@
+#include "socket_server.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static socket_server* __new_socket_server(uint16_t port, uint32_t incoming_ip) {
+ socket_server* srv = malloc(sizeof(socket_server));
+
+ srv->socket = socket(AF_INET, SOCK_STREAM, 0);
+
+ struct sockaddr_in addr = {
+ .sin_family = AF_INET, // Address Family Internet
+ .sin_port = htons(port), // Host to network short
+ .sin_addr.s_addr = htonl(incoming_ip), // Host to network long
+ };
+
+ while (bind(srv->socket, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
+ perror("Socket bind");
+ sleep(5);
+ }
+
+ return srv;
+}
+
+/*** Single Request Server ***/
+
+static int start_single_req(socket_server* this);
+static void destroy_single_req(socket_server* this);
+
+socket_server* new_socket_server_single_req(uint16_t port, uint32_t incoming_ip) {
+ socket_server* res = __new_socket_server(port, incoming_ip);
+ res->start = start_single_req;
+ res->destroy = destroy_single_req;
+ return res;
+}
+
+static int ends_on_two_newlines(char str[2]) {
+ return (str[0] == '\n' || str[0] == '\r') && (str[1] == '\n' || str[1] == '\r');
+}
+
+static int start_single_req(socket_server* this) {
+ if (this == NULL) return -1;
+
+ listen(this->socket, 1);
+
+ struct sockaddr_in client = {
+ .sin_family = AF_INET,
+ .sin_port = 0,
+ .sin_addr.s_addr = 0,
+ };
+ socklen_t client_size = sizeof(client);
+
+ int client_socket = accept(this->socket, (struct sockaddr*)&client, &client_size);
+
+ char input[1024] = { 0 };
+ size_t input_size = 0;
+
+ char line[256] = { 0 };
+ size_t line_size = 0;
+ do {
+ input_size += line_size = recv(client_socket, line, 255, 0);
+ line[line_size] = '\0';
+ strcat(input, line);
+ } while (input_size > 0 && !ends_on_two_newlines(input + input_size - 2));
+
+ callback_args ca_args = {
+ .input = input,
+ .input_size = input_size,
+
+ .output = NULL,
+ .output_size = 0,
+ .free_output = 0,
+
+ .extra = this->callback_args,
+ .extra_size = this->callback_argc,
+ };
+
+ if (this->callback != NULL)
+ this->callback(&ca_args);
+
+ if (ca_args.output != NULL && ca_args.output_size > 0)
+ send(client_socket, ca_args.output, ca_args.output_size, 0);
+
+ if (ca_args.free_output)
+ free(ca_args.output);
+
+ close(client_socket);
+
+ return 0;
+}
+
+static void destroy_single_req(socket_server* this) {
+ if (this == NULL) return;
+
+ close(this->socket);
+ free(this);
+ this = NULL;
+}