diff --git a/httpd/src/config/config.h b/httpd/src/config/config.h index aa4c318..acbc26c 100644 --- a/httpd/src/config/config.h +++ b/httpd/src/config/config.h @@ -48,7 +48,7 @@ struct config */ struct server_config { - struct string *server_name; + char *server_name; char *port; char *ip; char *root_dir; diff --git a/httpd/src/http/http.c b/httpd/src/http/http.c new file mode 100644 index 0000000..e69de29 diff --git a/httpd/src/http/http.h b/httpd/src/http/http.h new file mode 100644 index 0000000..8c6714f --- /dev/null +++ b/httpd/src/http/http.h @@ -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 diff --git a/httpd/src/logger b/httpd/src/logger new file mode 120000 index 0000000..c098a94 --- /dev/null +++ b/httpd/src/logger @@ -0,0 +1 @@ +utils/logs \ No newline at end of file diff --git a/httpd/src/main.c b/httpd/src/main.c index d86a4b8..6419b3b 100644 --- a/httpd/src/main.c +++ b/httpd/src/main.c @@ -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; } diff --git a/httpd/src/server/server.c b/httpd/src/server/server.c new file mode 100644 index 0000000..b55188a --- /dev/null +++ b/httpd/src/server/server.c @@ -0,0 +1,116 @@ +#include "server.h" + +#include +#include +#include +#include +#include + +// === 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); +} diff --git a/httpd/src/server/server.h b/httpd/src/server/server.h new file mode 100644 index 0000000..80ad392 --- /dev/null +++ b/httpd/src/server/server.h @@ -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 diff --git a/httpd/src/utils/logs/logs.c b/httpd/src/utils/logs/logs.c new file mode 100644 index 0000000..8114be6 --- /dev/null +++ b/httpd/src/utils/logs/logs.c @@ -0,0 +1,62 @@ +#include "logs.h" + +#include +#include +#include +#include +#include + +// === 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); +} diff --git a/httpd/src/utils/logs/logs.h b/httpd/src/utils/logs/logs.h new file mode 100644 index 0000000..e4ee209 --- /dev/null +++ b/httpd/src/utils/logs/logs.h @@ -0,0 +1,53 @@ +#ifndef LOGS_H +#define LOGS_H + +#include + +#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