Skip to content

Commit

Permalink
♻️ Refactored to split files
Browse files Browse the repository at this point in the history
  • Loading branch information
Saravenpi Shigeturi committed Jul 2, 2024
1 parent e540a69 commit ffb47e6
Show file tree
Hide file tree
Showing 8 changed files with 344 additions and 325 deletions.
8 changes: 4 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ project(Wave)

set(CMAKE_C_FLAGS "-Wall")

set(SRC wave.c)
set(OBJ wave.o)
set(SRCS src/wave.c src/connection.c src/endpoint.c src/response.c src/request.c)
set(OBJS src/wave.o src/connection.o src/endpoint.o src/response.o src/request.o)

set(NAME wave)
set(LIBRARY libwave.so)


add_library(${LIBRARY} SHARED ${SRC})
add_library(${LIBRARY} SHARED ${SRCS})
set_target_properties(${LIBRARY} PROPERTIES OUTPUT_NAME ${NAME})
target_compile_options(${LIBRARY} PRIVATE ${CMAKE_C_FLAGS})

84 changes: 84 additions & 0 deletions src/connection.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#include "wave.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

void findEndpointAndHandle(Server *server, int clientFd, const char *request);

void disconnectClient(Server *server, int clientFd)
{
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == clientFd) {
close(clientFd);
server->clients[i] = 0;
memset(server->buffers[i], 0, BUFFER_SIZE);
break;
}
}
}

void processClientData(Server *server, int clientFd, int index)
{
int valread;
char buffer[BUFFER_SIZE];
int requestComplete;
memset(buffer, 0, BUFFER_SIZE);

valread = read(clientFd, buffer, BUFFER_SIZE - 1);
if (valread == 0) {
return disconnectClient(server, clientFd);
}
if (valread < 0) {
perror("[WAVE] Read failed");
return disconnectClient(server, clientFd);
}
buffer[valread] = '\0';
strncat(server->buffers[index], buffer,
BUFFER_SIZE - strlen(server->buffers[index]) - 1);
requestComplete = strstr(server->buffers[index], "\r\n\r\n") != NULL;
if (requestComplete) {
findEndpointAndHandle(server, clientFd, server->buffers[index]);
return disconnectClient(server, clientFd);
}
}

void checkNewConnections(Server *server)
{
int newSocket;
if ((newSocket = accept(server->fd, (struct sockaddr *)&server->address,
(socklen_t *)&server->addrlen)) < 0) {
perror("[WAVE] Accept failed");
return;
}
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] == 0) {
server->clients[i] = newSocket;
break;
}
}
}

void addSocketsToSet(Server *server)
{
FD_ZERO(&server->readFdSet);
FD_SET(server->fd, &server->readFdSet);
server->maxFd = server->fd;
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] > 0) {
FD_SET(server->clients[i], &server->readFdSet);
if (server->clients[i] > server->maxFd) {
server->maxFd = server->clients[i];
}
}
}
}

void handleClientRequests(Server *server)
{
for (int i = 0; i < MAX_CLIENTS; i++) {
if (server->clients[i] > 0 &&
FD_ISSET(server->clients[i], &server->readFdSet)) {
processClientData(server, server->clients[i], i);
}
}
}
46 changes: 46 additions & 0 deletions src/endpoint.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "wave.h"
#include <stdio.h>
#include <string.h>

void addEndpoint(Server *server, const char *method, const char *path,
RequestHandler handler)
{
if (server->endpointCount < MAX_ENDPOINTS) {
server->endpoints[server->endpointCount].method = strdup(method);
server->endpoints[server->endpointCount].path = strdup(path);
server->endpoints[server->endpointCount].handler = handler;
server->endpointCount++;
} else {
fprintf(stderr, "[WAVE] Maximum number of endpoints reached\n");
}
}

void findEndpointAndHandle(Server *server, int clientFd, const char *request)
{
char *requestLine = strtok(strdup(request), "\r\n");
char *path = NULL;
char *method = NULL;

if (!requestLine)
return sendResponse(clientFd, "Bad Request", BAD_REQUEST);
method = strtok(requestLine, " ");
path = strtok(NULL, " ");
if (!path || !method)
return sendResponse(clientFd, "Bad Request", BAD_REQUEST);
printf("[WAVE] Request: %s %s\n", method, path);
for (int i = 0; i < server->endpointCount; i++) {
if (strcmp(path, server->endpoints[i].path) != 0)
continue;
if (strcmp(method, server->endpoints[i].method) != 0) {
return sendResponse(
clientFd, "Method Not Allowed", METHOD_NOT_ALLOWED);
}
return server->endpoints[i].handler(clientFd, request);
}
return sendFileResponse(clientFd, path + 1);
}

void defaultHandler(int clientFd, const char *request)
{
sendResponse(clientFd, "Hello, World!", OK);
}
55 changes: 55 additions & 0 deletions src/request.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#include "wave.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Request *parseRequest(const char *request)
{
Request *req = (Request *)malloc(sizeof(Request));

if (!req) {
perror("[WAVE] Failed to allocate memory for request");
return NULL;
}
char *requestLine = strtok(strdup(request), "\r\n");
if (requestLine) {
char *method = strtok(requestLine, " ");
char *path = strtok(NULL, " ");
char *version = strtok(NULL, " ");
if (method && path && version) {
req->method = strdup(method);
req->path = strdup(path);
req->version = strdup(version);
}
} else {
free(req);
return NULL;
}
char *headers = strstr(request, "\r\n");
if (headers) {
headers += 2;
char *end = strstr(headers, "\r\n\r\n");
if (end) {
size_t len = end - headers;
req->headers = (char *)malloc(len + 1);
if (req->headers) {
strncpy(req->headers, headers, len);
req->headers[len] = '\0';
}
}
}
if (req->headers && strlen(req->headers) == 0) {
free(req->headers);
req->headers = NULL;
}
char *body = strstr(request, "\r\n\r\n");
if (body) {
body += 4;
req->body = strdup(body);
}
if (req->body && strlen(req->body) == 0) {
free(req->body);
req->body = NULL;
}
return req;
}
79 changes: 79 additions & 0 deletions src/response.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "wave.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char *getContentType(const char *path)
{
if (strstr(path, ".css"))
return "text/css";
if (strstr(path, ".js"))
return "application/javascript";
if (strstr(path, ".png"))
return "image/png";
if (strstr(path, ".jpg") || strstr(path, ".jpeg"))
return "image/jpeg";
if (strstr(path, ".gif"))
return "image/gif";
if (strstr(path, ".mp4"))
return "video/mp4";
if (strstr(path, ".pdf"))
return "application/pdf";
if (strstr(path, ".html") || strstr(path, ".htm"))
return "text/html";
return "application/octet-stream";
}

void sendFileResponse(int clientFd, const char *path)
{
FILE *file;
char response[BUFFER_SIZE];
size_t bytesRead;
char buffer[BUFFER_SIZE];
char *contentType;

contentType = getContentType(path);
file = fopen(path, "rb");
if (!file) {
perror("[WAVE] Failed to open file");
return sendResponse(clientFd, "Not Found", NOT_FOUND);
}
snprintf(response, sizeof(response),
"HTTP/1.1 200 OK\r\n"
"Content-Type: %s\r\n"
"Connection: close\r\n"
"\r\n",
contentType);
write(clientFd, response, strlen(response));

while ((bytesRead = fread(buffer, 1, sizeof(buffer), file)) > 0) {
write(clientFd, buffer, bytesRead);
}
fclose(file);
}

void sendResponse(int clientFd, const char *body, int statusCode)
{
char response[BUFFER_SIZE];
ssize_t result;

if (statusCode < 100 || statusCode >= 600) {
fprintf(stderr, "[WAVE] Invalid status code: %d\n", statusCode);
return;
}
if (strlen(body) >= BUFFER_SIZE) {
fprintf(stderr, "[WAVE] Response body is too large\n");
return;
}
snprintf(response, sizeof(response),
"HTTP/1.1 %d OK\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %zu\r\n"
"\r\n"
"%s",
statusCode, strlen(body), body);
result = write(clientFd, response, strlen(response));
if (result == -1) {
perror("[WAVE] Failed to send response");
}
}
76 changes: 76 additions & 0 deletions src/wave.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#include "wave.h"
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

void addSocketsToSet(Server *server);
void checkNewConnections(Server *server);
void handleClientRequests(Server *server);

Server *initServer(int port)
{
Server *server = (Server *)malloc(sizeof(Server));
if (!server) {
perror("[WAVE] Failed to allocate memory for server");
exit(EXIT_FAILURE);
}

server->addrlen = sizeof(struct sockaddr_in);
if ((server->fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("[WAVE] Socket creation failed");
free(server);
exit(EXIT_FAILURE);
}
server->address.sin_family = AF_INET;
server->address.sin_addr.s_addr = INADDR_ANY;
server->address.sin_port = htons(port);

if (bind(server->fd, (struct sockaddr *)&server->address,
server->addrlen) < 0) {
perror("[WAVE] Bind failed");
close(server->fd);
free(server);
exit(EXIT_FAILURE);
}

if (listen(server->fd, 3) < 0) {
perror("[WAVE] Listen failed");
close(server->fd);
free(server);
exit(EXIT_FAILURE);
}

for (int i = 0; i < MAX_CLIENTS; i++) {
server->clients[i] = 0;
memset(server->buffers[i], 0, BUFFER_SIZE);
}
server->maxFd = server->fd;
server->endpointCount = 0;
return server;
}

void startWebServer(Server *server)
{
printf("🌊 Wave server started !\n");
printf("[WAVE] Server port: %d\n", ntohs(server->address.sin_port));
printf("[WAVE] Server host: %s\n", inet_ntoa(server->address.sin_addr));
while (1) {
addSocketsToSet(server);
int activity =
select(server->maxFd + 1, &server->readFdSet, NULL, NULL, NULL);
if (activity < 0) {
perror("[WAVE] Select failed");
break;
}
if (FD_ISSET(server->fd, &server->readFdSet)) {
checkNewConnections(server);
}
handleClientRequests(server);
}
printf("[WAVE] Server shutting down\n");
}
File renamed without changes.
Loading

0 comments on commit ffb47e6

Please sign in to comment.