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:
parent
747b3f7698
commit
3beeb31c9b
9 changed files with 297 additions and 2 deletions
|
|
@ -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
0
httpd/src/http/http.c
Normal file
47
httpd/src/http/http.h
Normal file
47
httpd/src/http/http.h
Normal 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
1
httpd/src/logger
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
utils/logs
|
||||||
|
|
@ -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
116
httpd/src/server/server.c
Normal 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
11
httpd/src/server/server.h
Normal 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
|
||||||
62
httpd/src/utils/logs/logs.c
Normal file
62
httpd/src/utils/logs/logs.c
Normal 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);
|
||||||
|
}
|
||||||
53
httpd/src/utils/logs/logs.h
Normal file
53
httpd/src/utils/logs/logs.h
Normal 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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue