diff options
| Commit | 74630b4bfe1aa887ef57ee57b22241d030b38d76 (patch) | |
|---|---|---|
| Author | 2025-11-15 21:37:37 +0200 | |
| Committer | 2025-11-15 21:37:37 +0200 | |
| Files | 3d39c585df1551d69fdb83980c010ec4b579f211 /src/sockets/socket_server.c | |
| tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.tar.gz tergiv-74630b4bfe1aa887ef57ee57b22241d030b38d76.zip | ||
| Parent | 3bca23eaaa49fa01f60ecbc5e0a329d29f088506 (diff) | |
feat!: Initial web server base implementation
1 files changed, 99 insertions, 0 deletions
| -rw-r--r-- | src/sockets/socket_server.c | 99 |
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; +} |
