tidy up code a bit

This commit is contained in:
ari melody 2026-04-27 23:13:06 +01:00
parent 365b48c403
commit e173033c33
Signed by: ari
GPG key ID: 60B5F0386E3DDB7E
7 changed files with 216 additions and 164 deletions

139
src/client.c Normal file
View file

@ -0,0 +1,139 @@
#include "consts.h"
#include "state.h"
#include "strings.h"
#include "client.h"
#include <asm-generic/socket.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <pthread.h>
struct client *clients;
int accept_connection(struct app_state *app) {
struct sockaddr_in addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
struct epoll_event ev;
int sock = accept(app->sock, (struct sockaddr*)&addr, &addrlen);
if (sock < 0) {
perror("Failed to accept connection");
return -1;
}
// add client to epoll instance
ev.events = EPOLLIN;
ev.data.fd = sock;
pthread_mutex_lock(&app->epoll_lock);
if (epoll_ctl(app->epoll, EPOLL_CTL_ADD, sock, &ev) == -1) {
perror("Failed to add client to epoll");
pthread_mutex_unlock(&app->epoll_lock);
return -1;
}
pthread_mutex_unlock(&app->epoll_lock);
struct client *client = &clients[sock % MAX_CLIENTS];
pthread_mutex_lock(&client->lock);
memset(client, 0, sizeof(struct client));
client->active = 1;
client->sock = sock;
client->req_buffer = malloc(sizeof(char) * BUFFER_SIZE);
client->req_buffer_len = 0;
client->req_buffer_sz = BUFFER_SIZE;
client->res_buffer = malloc(sizeof(char) * BUFFER_SIZE);
client->res_buffer_len = 0;
client->res_buffer_sz = BUFFER_SIZE;
char *addr_str = inet_ntoa(addr.sin_addr);
size_t addr_strlen = snprintf(NULL, 0, "%s:%d", addr_str, addr.sin_port) + 1;
client->addr_str = malloc(addr_strlen * sizeof(char));
snprintf(client->addr_str, addr_strlen, "%s:%d", addr_str, addr.sin_port);
pthread_mutex_unlock(&client->lock);
// printf("Connected: %s\n", client->addr_str);
return 0;
}
void close_client(struct app_state *app, struct client *client, int read) {
if (read == -1) {
fprintf(stderr, "Failed to read [%s]: %s\n",
client->addr_str, strerror(errno));
}
if (client->req_buffer_len > 300)
printf("%s\n", client->req_buffer);
// printf("Disonnected: %s\n", client->addr_str);
pthread_mutex_lock(&app->epoll_lock);
if (epoll_ctl(app->epoll, EPOLL_CTL_DEL, client->sock, NULL) == -1)
fprintf(stderr, "Failed to remove [%s] from epoll: %s\n",
client->addr_str, strerror(errno));
pthread_mutex_unlock(&app->epoll_lock);
if (shutdown(client->sock, SHUT_RDWR) == -1)
fprintf(stderr, "Failed to shutdown socket [%s]: %s\n",
client->addr_str, strerror(errno));
if (close(client->sock) == -1)
fprintf(stderr, "Failed to close socket [%s]: %s\n",
client->addr_str, strerror(errno));
client->active = 0;
}
void handle_client(struct app_state *app, struct client *client) {
pthread_mutex_lock(&client->lock);
if (!client->active) {
pthread_mutex_unlock(&client->lock);
return;
}
char buffer[BUFFER_SIZE + 1]; // ensure space for \0
memset(buffer, 0, BUFFER_SIZE);
int read = recv(client->sock, buffer, BUFFER_SIZE, 0);
if (read > 0 && client->req_buffer_len + read < MAX_BUFFER_SIZE) {
// increase buffer size if running out of space
if (client->req_buffer_len + read > client->req_buffer_sz) {
char *new_buffer = malloc(client->req_buffer_sz + BUFFER_SIZE);
memset(new_buffer, 0, client->req_buffer_sz + BUFFER_SIZE);
strncpy(new_buffer, client->req_buffer, client->req_buffer_sz);
client->req_buffer_sz += BUFFER_SIZE;
client->req_buffer = new_buffer;
}
// copy buffer to client state
strncpy(client->req_buffer + client->req_buffer_len, buffer, read);
client->req_buffer_len += read;
// printf("Read %d bytes from %s (%ld total)\n",
// read, client->addr_str, client->req_buffer_len);
if (str_has_suffix(client->req_buffer, "\r\n\r\n")) {
if (send(client->sock, HTTP_RESPONSE, strlen(HTTP_RESPONSE), 0) == -1)
fprintf(stderr, "Failed to send [%s]: %s\n",
client->addr_str, strerror(errno));
close_client(app, client, 0);
}
} else {
close_client(app, client, read);
}
pthread_mutex_unlock(&client->lock);
return;
}

23
src/client.h Normal file
View file

@ -0,0 +1,23 @@
#ifndef _CLIENTS_H
#define _CLIENTS_H
#include "state.h"
#include <pthread.h>
struct client {
char active;
int sock;
char *addr_str;
pthread_mutex_t lock;
char *req_buffer;
size_t req_buffer_sz;
size_t req_buffer_len;
char *res_buffer;
size_t res_buffer_sz;
size_t res_buffer_len;
};
int accept_connection(struct app_state *app);
void handle_client(struct app_state *app, struct client *client);
#endif // _CLIENTS_H

15
src/consts.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _CONSTS_H
#define _CONSTS_H
#define MAX_CLIENTS 1000
#define BUFFER_SIZE 1000
#define MAX_BUFFER_SIZE 1000000
#define HTTP_RESPONSE \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/plain; charset=utf-8\r\n" \
"Content-Length: 14\r\n" \
"\r\n" \
"bunny -> 🐇\n" \
#endif // _CONSTS_H

View file

@ -1,5 +1,7 @@
#include "client.h"
#include "consts.h"
#include "state.h"
#include <asm-generic/socket.h> #include <asm-generic/socket.h>
#include <errno.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -11,174 +13,11 @@
#include <sys/epoll.h> #include <sys/epoll.h>
#include <pthread.h> #include <pthread.h>
#define MAX_CLIENTS 1000
#define BUFFER_SIZE 1000
#define MAX_BUFFER_SIZE 1000000
#define WORKER_THREADS 8 #define WORKER_THREADS 8
#define DEFAULT_HOST "0.0.0.0" #define DEFAULT_HOST "0.0.0.0"
#define HTTP_RESPONSE \
"HTTP/1.1 200 OK\r\n" \
"Content-Type: text/plain; charset=utf-8\r\n" \
"Content-Length: 14\r\n" \
"\r\n" \
"bunny -> 🐇\n" \
struct app_state {
struct sockaddr_in addr;
int sock;
int epoll;
pthread_mutex_t epoll_lock;
char *page_buffer;
};
struct client {
char active;
int sock;
char *addr_str;
pthread_mutex_t lock;
char *req_buffer;
size_t req_buffer_sz;
size_t req_buffer_len;
char *res_buffer;
size_t res_buffer_sz;
size_t res_buffer_len;
};
struct client clients[MAX_CLIENTS]; struct client clients[MAX_CLIENTS];
int accept_connection(struct app_state *app) {
struct sockaddr_in addr;
socklen_t addrlen = sizeof(struct sockaddr_in);
struct epoll_event ev;
int sock = accept(app->sock, (struct sockaddr*)&addr, &addrlen);
if (sock < 0) {
perror("Failed to accept connection");
return -1;
}
// add client to epoll instance
ev.events = EPOLLIN;
ev.data.fd = sock;
pthread_mutex_lock(&app->epoll_lock);
if (epoll_ctl(app->epoll, EPOLL_CTL_ADD, sock, &ev) == -1) {
perror("Failed to add client to epoll");
pthread_mutex_unlock(&app->epoll_lock);
return -1;
}
pthread_mutex_unlock(&app->epoll_lock);
struct client *client = &clients[sock % MAX_CLIENTS];
pthread_mutex_lock(&client->lock);
memset(client, 0, sizeof(struct client));
client->active = 1;
client->sock = sock;
client->req_buffer = malloc(sizeof(char) * BUFFER_SIZE);
client->req_buffer_len = 0;
client->req_buffer_sz = BUFFER_SIZE;
client->res_buffer = malloc(sizeof(char) * BUFFER_SIZE);
client->res_buffer_len = 0;
client->res_buffer_sz = BUFFER_SIZE;
char *addr_str = inet_ntoa(addr.sin_addr);
size_t addr_strlen = snprintf(NULL, 0, "%s:%d", addr_str, addr.sin_port) + 1;
client->addr_str = malloc(addr_strlen * sizeof(char));
snprintf(client->addr_str, addr_strlen, "%s:%d", addr_str, addr.sin_port);
pthread_mutex_unlock(&client->lock);
// printf("Connected: %s\n", client->addr_str);
return 0;
}
void close_client(struct app_state *app, struct client *client, int read) {
if (read == -1) {
fprintf(stderr, "Failed to read [%s]: %s\n",
client->addr_str, strerror(errno));
}
if (client->req_buffer_len > 300)
printf("%s\n", client->req_buffer);
// printf("Disonnected: %s\n", client->addr_str);
pthread_mutex_lock(&app->epoll_lock);
if (epoll_ctl(app->epoll, EPOLL_CTL_DEL, client->sock, NULL) == -1)
fprintf(stderr, "Failed to remove [%s] from epoll: %s\n",
client->addr_str, strerror(errno));
pthread_mutex_unlock(&app->epoll_lock);
if (shutdown(client->sock, SHUT_RDWR) == -1)
fprintf(stderr, "Failed to shutdown socket [%s]: %s\n",
client->addr_str, strerror(errno));
if (close(client->sock) == -1)
fprintf(stderr, "Failed to close socket [%s]: %s\n",
client->addr_str, strerror(errno));
client->active = 0;
}
int str_has_suffix(char *str, const char *suffix) {
if (str == NULL || suffix == NULL)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}
void handle_client(struct app_state *app, struct client *client) {
pthread_mutex_lock(&client->lock);
if (!client->active) {
pthread_mutex_unlock(&client->lock);
return;
}
char buffer[BUFFER_SIZE + 1]; // ensure space for \0
memset(buffer, 0, BUFFER_SIZE);
int read = recv(client->sock, buffer, BUFFER_SIZE, 0);
if (read > 0 && client->req_buffer_len + read < MAX_BUFFER_SIZE) {
// increase buffer size if running out of space
if (client->req_buffer_len + read > client->req_buffer_sz) {
char *new_buffer = malloc(client->req_buffer_sz + BUFFER_SIZE);
memset(new_buffer, 0, client->req_buffer_sz + BUFFER_SIZE);
strncpy(new_buffer, client->req_buffer, client->req_buffer_sz);
client->req_buffer_sz += BUFFER_SIZE;
client->req_buffer = new_buffer;
}
// copy buffer to client state
strncpy(client->req_buffer + client->req_buffer_len, buffer, read);
client->req_buffer_len += read;
// printf("Read %d bytes from %s (%ld total)\n",
// read, client->addr_str, client->req_buffer_len);
if (str_has_suffix(client->req_buffer, "\r\n\r\n")) {
if (send(client->sock, HTTP_RESPONSE, strlen(HTTP_RESPONSE), 0) == -1)
fprintf(stderr, "Failed to send [%s]: %s\n",
client->addr_str, strerror(errno));
close_client(app, client, 0);
}
} else {
close_client(app, client, read);
}
pthread_mutex_unlock(&client->lock);
return;
}
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
struct app_state app; struct app_state app;
memset(&app, 0, sizeof(struct app_state)); memset(&app, 0, sizeof(struct app_state));

15
src/state.h Normal file
View file

@ -0,0 +1,15 @@
#ifndef _STATE_H
#define _STATE_H
#include <netinet/in.h>
#include <sys/socket.h>
struct app_state {
struct sockaddr_in addr;
int sock;
int epoll;
pthread_mutex_t epoll_lock;
char *page_buffer;
};
#endif // _STATE_H

15
src/strings.c Normal file
View file

@ -0,0 +1,15 @@
#include "strings.h"
#include <string.h>
#include <unistd.h>
int str_has_suffix(char *str, const char *suffix) {
if (str == NULL || suffix == NULL)
return 0;
size_t lenstr = strlen(str);
size_t lensuffix = strlen(suffix);
if (lensuffix > lenstr)
return 0;
return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
}

6
src/strings.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _STRINGS_H
#define _STRINGS_H
int str_has_suffix(char *str, const char *suffix);
#endif // _STRINGS_H