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 string *server_name;
|
||||
char *server_name;
|
||||
char *port;
|
||||
char *ip;
|
||||
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"
|
||||
|
||||
#define ERR_ARG 2
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
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