commit 9bea995bf74df0a3afe9f42093cdf902af3b32f8 Author: talksik Date: Sun Sep 20 11:11:09 2026 -0700 scaffold basics of tcp and http sockets, connections, receiving data, sending data diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba2906d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +main diff --git a/main.c b/main.c new file mode 100644 index 0000000..1ae048a --- /dev/null +++ b/main.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { + printf("hello world\n"); + + // http is built on top of tcp + // http/1.0 creates a new tcp connection every request + + // for an http server implmentation, we listen for packets in a loop, and group request packets + // then we respond with a response broken down into separate packets (headers, body, etc) + int fd = socket(AF_INET, SOCK_STREAM, 0); + // ?? connect or bind the socket to the address? + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_port = htons(8080), + .sin_addr = INADDR_ANY, + }; + + int yes = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + + int r = bind(fd, (struct sockaddr *) &addr, sizeof(addr)); + if (r == -1) { + printf("ERROR: unable to bind to address\n"); + return r; + } + + // go ahead and listen for incoming connections + r = listen(fd, 3); + if (r == -1) { + printf("ERROR: unable to use socket to listen for incoming connections\n"); + return r; + } + + printf("Listening on port 8080\n"); + fflush(stdout); + + // we loop and do blocking accept calls for incoming connections + while (true) { + // we pass in a sockaddr which is filled with the incoming client's information + struct sockaddr client_addr; + int addr_len = sizeof(client_addr); + int client_fd = accept(fd, &client_addr, (socklen_t *) &addr_len); + if (client_fd == -1) { + printf("ERROR: unable to accept incoming client connection\n"); + return -1; + } + + // new socket is created for the one client connection + // we can recv from this socket + size_t size = 1000; + char *buf = malloc(size); + // TCP is a byte stream so we need to keep calling recv until an end condition (\r\n). HTTP is the protocol which specifies this, not TCP streams + + ssize_t received_bytes = recv(client_fd, buf, size, 0); + if (received_bytes > 0) { + printf("received bytes: %d\n", (int) received_bytes); + printf("%.*s\n", received_bytes, buf); + } + + // parse the request + char current_line[1000]; + int current_line_char = 0; + for (int i = 0; i < received_bytes; i++) { + printf("%c", buf[i]); + current_line[current_line_char] = buf[i]; + current_line_char++; + + if (buf[i] == '\n') { + printf("line complete: %.*s\n", current_line_char, current_line); + current_line_char = 0; + } + + // TODO: find the path from the first header `GET /bootstrap HTTP/1.1` + // decode the request further + } + fflush(stdout); + + free(buf); + + const char *response = + "HTTP/1.1 200 OK\r\n" + "Content-Length: 5\r\n" + "Content-Type: text/plain\r\n" + "Connection: close\r\n" + "\r\n" + "hello"; + r = send(client_fd, response, strlen(response), 0); + if (r == -1) { + printf("ERROR: in sending response"); + fflush(stdout); + } + printf("sent %zd of %zu bytes\n", r, strlen(response)); + fflush(stdout); + + close(client_fd); + } + + + // TODO: scaffolding + // keep track of multiple requests, examine the request data + // decode the request data + // then respond with particular html page + + // close socket + close(fd); + + // for an http client library, we need to create a tcp connection, send headers, and then body and other parts of the request in a structure that follows the protocol RFC +} +