diff --git a/Makefile b/Makefile index e2cedc7..f9fb2b2 100644 --- a/Makefile +++ b/Makefile @@ -6,8 +6,7 @@ # By: adjoly +#+ +:+ +#+ # # +#+#+#+#+#+ +#+ # # Created: 2024/10/25 16:09:27 by adjoly #+# #+# # -# Updated: 2025/04/10 11:52:13 by mmoussou ### ########.fr # -# Updated: 2025/03/25 18:13:53 by adjoly ### ########.fr # +# Updated: 2025/04/15 17:53:00 by adjoly ### ########.fr # # # # **************************************************************************** # diff --git a/exemples/test.toml b/exemples/test.toml index f4b6ece..a513196 100644 --- a/exemples/test.toml +++ b/exemples/test.toml @@ -1,8 +1,9 @@ +log_file = "test.log" + [server] server_names = { "localhost", "2B5.local" } host = "localhost" port = 8080 -log_file = "test.log" [server.error_pages] 404 = "not_found.html" diff --git a/includes/server/server.hpp b/includes/server/Server.hpp similarity index 63% rename from includes/server/server.hpp rename to includes/server/Server.hpp index f0f75fe..2744e75 100644 --- a/includes/server/server.hpp +++ b/includes/server/Server.hpp @@ -1,12 +1,12 @@ /* ************************************************************************** */ /* */ /* ::: :::::::: */ -/* server.hpp :+: :+: :+: */ +/* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/11 17:45:43 by adjoly #+# #+# */ -/* Updated: 2025/04/14 14:21:41 by adjoly ### ########.fr */ +/* Updated: 2025/04/17 11:48:36 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,11 +45,26 @@ class Server { */ void _handle_client(Client); + /** + * @brief Can be used to fill the vector passed as parameters with all the + * port and host in the config + * @param The vector of host + * @param The vector of port + */ + int _fillHostsPorts(std::vector &, std::vector &); + + /** + * @brief Can be used to open a socket with a specific port and host + * @param The host + * @param The port + */ + int _createSocket(std::string, int); + config::Config - *_conf; ///> Pointer to the configuration class (with all config in) - Logger *_log; ///> Pointer to the log class - int _fd_server; ///> The fd of the socket - std::vector _client_fds; ///> A vector of all the poll fd + *_conf; // Pointer to the configuration class (with all config in) + Logger *_log; // Pointer to the log class + std::vector _fds_server; // The fds of the sockets + std::vector _client_fds; // A vector of all the poll fd }; }; // namespace webserv diff --git a/includes/server/default.hpp b/includes/server/default.hpp index e2061d4..739752a 100644 --- a/includes/server/default.hpp +++ b/includes/server/default.hpp @@ -6,13 +6,14 @@ /* By: mmoussou +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/15 14:44:55 by adjoly #+# #+# */ +/* Updated: 2025/04/15 18:38:42 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include +#include + +Client::Client(int fd, sockaddr_in sockData, config::Config *conf) + : _fd(fd), _client_addr(sockData) { + +} diff --git a/src/config/Server.cpp b/src/config/Server.cpp index 278ebd2..dc33db3 100644 --- a/src/config/Server.cpp +++ b/src/config/Server.cpp @@ -6,7 +6,7 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/03/24 15:10:07 by adjoly #+# #+# */ -/* Updated: 2025/04/14 12:57:30 by adjoly ### ########.fr */ +/* Updated: 2025/04/17 11:22:20 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ @@ -29,7 +29,7 @@ Server::Server(toml::ANode *node, Logger *log) : _table(node), _log(log) { } // port parsing void *port = accessValue("port", toml::INT, _table, _log); - if (host != not_nullptr) { + if (port != not_nullptr) { _port = *static_cast(port); } else { delete _table; diff --git a/src/server.cpp b/src/server.cpp index 59d81df..ee7b4c0 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -6,100 +6,98 @@ /* By: adjoly +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2025/04/11 16:11:40 by adjoly #+# #+# */ -/* Updated: 2025/04/14 14:07:36 by adjoly ### ########.fr */ +/* Updated: 2025/04/17 12:37:45 by adjoly ### ########.fr */ /* */ /* ************************************************************************** */ #include #include #include +#include #include +#include #include #include #include -#include using namespace webserv; -std::string getMethod(std::string &data) -{ +std::string getMethod(std::string &data) { return (data.substr(0, data.substr(0, 4).find_last_not_of(" ") + 1)); } -void Server::_handle_client(int fd) -{ - (void) fd; - +void Server::_handle_client(int fd) { std::string received_data; - char buffer[BUFFER_SIZE]; - ssize_t bytes_received; - do - { + char buffer[BUFFER_SIZE]; + ssize_t bytes_received; + do { std::memset(buffer, 0, BUFFER_SIZE); bytes_received = recv(fd, buffer, BUFFER_SIZE - 1, 0); - if (bytes_received == -1) - { + if (bytes_received == -1) { _log->error("failed to receive request"); continue; } received_data += std::string(buffer, bytes_received); - } - while (buffer[bytes_received]); + } while (buffer[bytes_received]); - std::string response; + std::string response; - if (getMethod(received_data) == "GET") - { + if (getMethod(received_data) == "GET") { _log->info("get request received"); - http::Get request(received_data); + http::Get request(received_data); response = request.execute().str(); - } - else if (getMethod(received_data) == "DELETE") - { + } else if (getMethod(received_data) == "DELETE") { _log->info("delete request received"); - http::Delete request(received_data); + http::Delete request(received_data); response = request.execute().str(); - } - else if (getMethod(received_data) == "POST") - { + } else if (getMethod(received_data) == "POST") { _log->info("post request received"); - http::Post request(received_data); + http::Post request(received_data); response = request.execute().str(); - } - else - { - response = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\n\r\n

501 Not Implemented

"; + } else { + response = "HTTP/1.1 501 Not Implemented\r\nContent-Type: " + "text/html\r\n\r\n

501 Not " + "Implemented

"; } - send(fd, response.c_str(), response.length(), 0); + send(fd, response.c_str(), response.length(), 0); +} + +int Server::_fillHostsPorts(std::vector &hosts, + std::vector &ports) { + std::vector *config = _conf->getServers(); + + for (std::vector::iterator it = config->begin(); + it != config->end(); it++) { + hosts.push_back((*it)->getHost()); + ports.push_back((*it)->getPort()); + } + return config->size(); } void Server::_setup(void) { - _fd_server = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - if (_fd_server == -1) - throw std::runtime_error("error at socket setup"); + std::vector hosts; + std::vector ports; - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_port = htons(_conf->getPort()); + int size = _fillHostsPorts(hosts, ports); + if (size < 1) + throw std::runtime_error("no server present in the config file"); - if (bind(_fd_server, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - close(_fd_server); - throw std::runtime_error("error when binding address"); - } - - if (listen(_fd_server, SOMAXCONN) < 0) { - close(_fd_server); - throw std::runtime_error("error when listening"); + std::vector::iterator itH = hosts.begin(); + for (std::vector::iterator itP = ports.begin(); itP != ports.end(); itP++, itH++) { + try { + int fd = _createSocket(*itH, *itP); + _fds_server.push_back(fd); + } catch (std::exception &e) { + throw e; + } } } -void Server::_run(void) -{ +void Server::_run(void) { struct pollfd fd; fd.fd = _fd_server; @@ -109,22 +107,19 @@ void Server::_run(void) int nbr_client = 0; - while (727) - { + while (727) { int ret = poll(_client_fds.data(), nbr_client + 1, -1); - if (ret < 0) - { + if (ret < 0) { close(_fd_server); throw std::runtime_error("poll failed :("); } - if (_client_fds[0].revents & POLLIN) - { + if (_client_fds[0].revents & POLLIN) { struct sockaddr_in client_addr; socklen_t addrlen = sizeof(client_addr); - int client_fd = accept(_fd_server, (struct sockaddr *)&client_addr, &addrlen); - if (client_fd < 0) - { + int client_fd = + accept(_fd_server, (struct sockaddr *)&client_addr, &addrlen); + if (client_fd < 0) { _log->error("accept failed"); continue; } @@ -136,16 +131,13 @@ void Server::_run(void) // if (nbr_client) TODO do we need a max client probably not :D } - for (int i = 1; i <= nbr_client; ) - { - if (_client_fds[i].revents & POLLIN) - { + for (int i = 1; i <= nbr_client;) { + if (_client_fds[i].revents & POLLIN) { _handle_client(_client_fds[i].fd); close(_client_fds[i].fd); _client_fds[i] = _client_fds[nbr_client--]; - _client_fds.pop_back(); - } - else + _client_fds.pop_back(); + } else ++i; } } diff --git a/src/socket.cpp b/src/socket.cpp new file mode 100644 index 0000000..2aac70e --- /dev/null +++ b/src/socket.cpp @@ -0,0 +1,71 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* socket.cpp :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: adjoly +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2025/04/17 11:58:42 by adjoly #+# #+# */ +/* Updated: 2025/04/17 12:35:31 by adjoly ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include +#include + +using namespace webserv; + +bool convertStringToIP(const char *ip_str, struct in_addr *addr) { + // Split the IP string into four octets + unsigned int a, b, c, d; + if (sscanf(ip_str, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) { + return false; + } + + // Check if each octet is within the valid range + if (a > 255 || b > 255 || c > 255 || d > 255) { + return false; + } + + // Combine the octets into a single 32-bit address + addr->s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d); + return true; +} + +int Server::_createSocket(std::string host, int port) { + int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (fd == -1) { + std::ostringstream str; + str << port; + throw std::runtime_error("socket binding failed for : " + host + ":" + + str.str()); + } + return -1; + + int opt = 1; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { + close(fd); + throw std::runtime_error("setsockopt failed"); + } + + struct sockaddr_in addr; + addr.sin_family = AF_INET; + convertStringToIP(host.c_str(), &addr.sin_addr); + addr.sin_port = htons(port); + + if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + close(fd); + std::ostringstream str; + str << port; + throw std::runtime_error("bind failed for : " + host + ":" + str.str()); + } + + if (listen(fd, SOMAXCONN) < 0) { + close(fd); + std::ostringstream str; + str << port; + throw std::runtime_error("listen failed for : " + host + ":" + str.str()); + } + + return (fd); +}