feat: Implemented TCP server, base structures for http parsing, made some fixes for the logs and config modules. Also created a symlink to comply with school's architecture

This commit is contained in:
Gu://em_ 2025-11-21 16:09:48 +01:00
parent 747b3f7698
commit 3beeb31c9b
9 changed files with 297 additions and 2 deletions

View file

@ -48,7 +48,7 @@ struct config
*/ */
struct server_config struct server_config
{ {
struct string *server_name; char *server_name;
char *port; char *port;
char *ip; char *ip;
char *root_dir; char *root_dir;

0
httpd/src/http/http.c Normal file
View file

47
httpd/src/http/http.h Normal file
View file

@ -0,0 +1,47 @@
#ifndef HTTP_H
#define HTTP_H
// === Enums
enum http_method
{
GET,
POST,
PUT,
DELETE,
// patch,
// head,
// options,
// connect,
// trace
};
// === Structures
struct http_header
{
char *field;
char *value;
struct http_header *next;
};
struct http_request
{
enum http_method method;
char *path;
char *protocol;
char *protocol_version;
struct http_header *headers; // Headers linked list
};
struct http_response
{
char *protocol;
char *protocol_version;
int status_code;
char *status_msg;
struct http_header *headers; // Headers linked list
};
#endif // ! HTTP_H

1
httpd/src/logger Symbolic link
View file

@ -0,0 +1 @@
utils/logs

View file

@ -3,8 +3,13 @@
#include "config/config.h" #include "config/config.h"
#define ERR_ARG 2
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
parse_configuration(argc, argv); struct config *config = parse_configuration(argc, argv);
if (config == NULL)
return ERR_ARG;
return 0; return 0;
} }

116
httpd/src/server/server.c Normal file
View file

@ -0,0 +1,116 @@
#include "server.h"
#include <netdb.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/socket.h>
#include <unistd.h>
// === Definitions
#define BUFFER_SIZE 1024
// === Static functions
// TODO
// See getaddrinfo(3) at RETURN VALUE
static void print_getaddr_error(int err_code)
{}
// Creates and bind the server communication socket
static int get_socket(const char *hostname, const char *port)
{
// set lower-level protocols infos
struct addrinfo hints = { 0 };
hints.ai_family = AF_INET; // IPv4
hints.ai_socktype = SOCK_STREAM; // Socket type (necessary for TCP)
hints.ai_protocol = IPPROTO_TCP; // TCP
// Retrieve node informations
struct addrinfo *client_addr = NULL; // Client addresses list
int err = getaddrinfo(hostname, port, &hints, &client_addr);
if (err != 0)
{
print_getaddr_error(err);
return -1;
}
// Try each address
int sock_fd;
bool socket_bound = false;
struct addrinfo *cur_addr = client_addr;
while (cur_addr != NULL && socket_bound)
{
// Create socket
sock_fd = socket(cur_addr->ai_family, cur_addr->ai_socktype,
cur_addr->ai_protocol);
if (sock_fd == -1)
continue;
// ... Has something to do with not changing port
int sock_opt = -1;
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &sock_opt,
sizeof(sock_opt));
// Assign name to socket (bind)
err = bind(sock_fd, cur_addr->ai_addr, cur_addr->ai_addrlen);
if (err != -1)
socket_bound = true;
else
close(sock_fd);
cur_addr = cur_addr->ai_next;
}
freeaddrinfo(client_addr);
return sock_fd;
}
// Reads and sends back received data to client
static void send_back(int client_fd)
{
ssize_t nread = 0;
char buffer[BUFFER_SIZE];
while ((nread = recv(client_fd, buffer, BUFFER_SIZE, 0)) > 0)
{
ssize_t sent;
while (nread > 0)
{
sent = send(client_fd, buffer, nread, 0);
if (sent == -1) // Send failed
break;
nread -= sent;
}
}
}
// === Functions
void start_server(const char *hostname, const char *port)
{
int server_socket = get_socket(hostname, port);
if (server_socket == -1)
// TODO log that
return;
int err = listen(server_socket, SOMAXCONN);
if (err == -1)
return;
// Main loop
while (1)
{
int client_fd = accept(server_socket, NULL, NULL);
if (client_fd == -1)
continue;
// TODO handle signals to stop
send_back(client_fd);
close(client_fd);
}
close(server_socket);
}

11
httpd/src/server/server.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef SERVER_H
#define SERVER_H
/* @brief
*
* @param hpstname
* @param port
*/
void start_server(const char* hostname, const char* port);
#endif // ! SERVER_H

View file

@ -0,0 +1,62 @@
#include "logs.h"
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
// === Static variable
static struct logs_config config;
// === Static functions
// Returns a string containing the formatted GMT time
static char *get_time(void)
{
time_t local_ts = time(NULL);
struct tm *gmt_time = gmtime(&local_ts);
return asctime(gmt_time);
}
// === Functions
int log_init(struct config *global_config)
{
config.enabled = global_config->log;
config.logfile_stream = fopen(global_config->log_file, "w");
if (config.logfile_stream == NULL)
return 1;
return 0;
}
void print_log(char *format, ...)
{
// Log prefix (time and server name)
fprintf(config.logfile_stream, "%s [%s] ", get_time(),
config.server_cfg->server_name);
// Print actual log
va_list args;
va_start(args, format);
vfprintf(config.logfile_stream, format, args);
va_end(args);
// New line
fprintf(config.logfile_stream, "\n");
}
void log_request(char *request_type, char *target, char *client_ip)
{
print_log("received %s, on '%s' from %s", get_time(),
config.server_cfg->server_name, request_type, target, client_ip);
}
void log_response(int status_code, char *request_type, char *target,
char *client_ip)
{
print_log("responding with %d to %s for %s on '%s'", get_time(),
config.server_cfg->server_name, status_code, client_ip,
request_type, target);
}

View file

@ -0,0 +1,53 @@
#ifndef LOGS_H
#define LOGS_H
#include <stdio.h>
#include "../../config/config.h"
struct logs_config
{
bool enabled;
FILE* logfile_stream;
struct server_config* server_cfg;
};
/* @brief Initializes the logging module
*
* @param config
*
* @return 0 on success, an error code otherwise
*/
int log_init(struct config* config);
/* @brief Prints logs (or not) conformly to the config given by the user.
* Works like printf (because it uses it under the hood) with a
* formatted string and variadic arguments.
*
* @param format
* @param ...
*/
void print_log(char* format, ...);
/* @brief Prints request logs with the adequate format in the logfile
*
* @param request_type
* @param target
* @param client_ip
*/
void log_request(char* request_type, char* target, char* client_ip);
/* @brief Prints response logs with the adequate format in the logfile
*
* @param status_code
* @param request_type
* @param target
* @param client_ip
*/
void log_response(int status_code, char* request_type, char* target, char* client_ip);
#endif // ! LOGS_H