From 72d9709ca7c6c70867e1e02ccf97bf5f6281c61e Mon Sep 17 00:00:00 2001 From: LuckyLaszlo Date: Sat, 23 Jul 2022 07:01:41 +0200 Subject: [PATCH] poll() replaced by epoll() --- srcs/Webserv.cpp | 227 ++++++++++++++++++++++++++--------------------- srcs/Webserv.hpp | 24 +++-- srcs/main.cpp | 3 +- 3 files changed, 147 insertions(+), 107 deletions(-) diff --git a/srcs/Webserv.cpp b/srcs/Webserv.cpp index 8bd7259..92a85c0 100644 --- a/srcs/Webserv.cpp +++ b/srcs/Webserv.cpp @@ -4,12 +4,12 @@ Webserv::Webserv() { std::cout << "Server init\n"; - _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); - //_socket_fd = ::socket(AF_INET, SOCK_STREAM, 0); - if (_socket_fd == -1) + + _epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ? + if (_epfd == -1) { - std::perror("err socket(): "); - throw std::runtime_error("Socket init"); + std::perror("err epoll_create1(): "); + throw std::runtime_error("Epoll init"); } } @@ -20,6 +20,8 @@ Webserv::Webserv() Webserv::~Webserv() { + close(_socket_fd); + close(_epfd); std::cout << "Server destroyed\n"; } @@ -31,7 +33,71 @@ Webserv::~Webserv() /////////////// // Functions // -void Webserv::bind(in_port_t port) +void Webserv::init_virtual_servers() // ADD config param +{ + _socket_fd = ::socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); // (SOCK_CLOEXEC) for CGI fork ? + if (_socket_fd == -1) + { + std::perror("err socket(): "); + throw std::runtime_error("Socket init"); + } + + _bind(_socket_fd, 80); + _listen(_socket_fd, 512); // 512 arbitrary + + struct epoll_event ev; + std::memset(&ev, 0, sizeof ev); + ev.events = EPOLLIN; + ev.data.fd = _socket_fd; + if (::epoll_ctl(_epfd, EPOLL_CTL_ADD, _socket_fd, &ev) == -1) + { + std::perror("err epoll_ctl(): "); + throw std::runtime_error("Socket init"); + } +} + +void Webserv::start() +{ + std::cout << "Server started\n"; + struct epoll_event events[MAX_EVENTS]; + int nfds; + int i; + int count_loop = 0; + std::cout << ++count_loop << "----loop epoll()\n"; + + while ( (nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT)) != -1) + { + if (nfds == 0) + { + (void)0; + // TODO : parcourir les "Clients" encore ouvert et les close() tous + } + i = 0; + while (i < nfds) + { + if ((events[i].data.fd == _socket_fd) && (events[i].events & EPOLLIN)) + _accept_connection(events[i].data.fd); + else if (events[i].events & EPOLLIN) + _read_request(events[i].data.fd); + else if (events[i].events & EPOLLOUT) + _send_response(events[i].data.fd); + ++i; + } + std::cout << ++count_loop << "----loop epoll()\n"; + } + + if (nfds == -1) + { + std::perror("err epoll_wait(): "); + throw std::runtime_error("Epoll wait"); + } +} + + + /////////////////////// + // Private Functions // + +void Webserv::_bind(int socket_fd, in_port_t port) { // cast invalid ? how to ? // const struct sockaddr* cast_test = static_cast(addr); @@ -42,118 +108,79 @@ void Webserv::bind(in_port_t port) addr.sin_port = ::htons(port); addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ? - if (::bind(_socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) + if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1) { std::perror("err bind(): "); throw std::runtime_error("Socket bind"); } } -void Webserv::listen(unsigned int max_connections) +void Webserv::_listen(int socket_fd, unsigned int max_connections) { - if (::listen(_socket_fd, max_connections) == -1) + if (::listen(socket_fd, max_connections) == -1) { std::perror("err listen(): "); throw std::runtime_error("Socket listen"); } } -#define BUFSIZE 8192 -#define MSG_TEST "Le Webserv / 20 =D\n" -#define MSG_BOUNCE "bounced properly ;)\n" // placeholder - -void Webserv::start() +void Webserv::_accept_connection(int fd) { struct sockaddr_in addr; socklen_t addr_len; int accepted_fd; - char buf[BUFSIZE+1]; // WIP buffer. need to try with std::vector or std::string. - int ret; - int timeout = 3000; - int i = 1; - int nfds = 1; - int ret_nfds; - - _poll_s[0].fd = _socket_fd; - _poll_s[0].events = POLLIN; - - std::cout << "Server started\n"; - int i_loop = 0; - ++i_loop; - std::cout << i_loop << "----------\n"; - std::cout << "loop poll()\n"; - while ( (ret_nfds = ::poll(_poll_s, nfds, timeout)) != -1) + std::cout << "accept()\n"; + addr_len = sizeof addr; + accepted_fd = ::accept(fd, (sockaddr*)&addr, &addr_len); + if (accepted_fd == -1) { - i = 1; - while (i < nfds) - { - if (ret_nfds == 0) - { - std::cout << "timeout\n"; - ::close(_poll_s[i].fd); - _poll_s[i].fd = -1; - --nfds; - } - - else if (_poll_s[i].revents & POLLIN) // READ - { - std::cout << "recv()\n"; - ret = ::recv(_poll_s[i].fd, buf, BUFSIZE, 0); - if (ret == -1) - { - std::perror("err recv(): "); - if (::send(_poll_s[i].fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1) - std::perror("err send(): "); - - ::close(_poll_s[i].fd); - _poll_s[i].fd = -1; - --nfds; - continue; - } - /* - if (ret == BUFSIZE) - // send error like "request too long" to client - */ - buf[ret] = '\0'; - _poll_s[i].events = POLLOUT; - } - - else if (_poll_s[i].revents & POLLOUT) // WRITE - { - std::cout << "send()\n"; - if (::send(_poll_s[i].fd, buf, ret, 0) == -1) // echo the read - std::perror("err send(): "); - if (::send(_poll_s[i].fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1) - std::perror("err send(): "); - - ::close(_poll_s[i].fd); - _poll_s[i].fd = -1; - --nfds; - } - - ++i; - } - - - if ((_poll_s[0].fd == _socket_fd) && (_poll_s[0].revents & POLLIN)) // ACCEPT - { - std::cout << "accept()\n"; - addr_len = sizeof addr; - accepted_fd = ::accept(_socket_fd, (sockaddr*)&addr, &addr_len); - if (accepted_fd == -1) - { - std::perror("err accept(): "); - continue; - } - ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); - _poll_s[nfds].fd = accepted_fd; - _poll_s[nfds].events = POLLIN; - ++nfds; - } - - ++i_loop; - std::cout << i_loop << "----------\n"; - std::cout << "loop poll()\n"; + std::perror("err accept(): "); + return; } + ::fcntl(accepted_fd, F_SETFL, O_NONBLOCK); + + struct epoll_event ev; + std::memset(&ev, 0, sizeof ev); + ev.events = EPOLLIN; + ev.data.fd = accepted_fd; + if (::epoll_ctl(_epfd, EPOLL_CTL_ADD, accepted_fd, &ev) == -1) + std::perror("err accept() epoll_ctl(): "); +} + +void Webserv::_read_request(int fd) +{ + std::cout << "recv()\n"; + _read_ret = ::recv(fd, _buf, BUFSIZE, 0); + if (_read_ret == -1) + { + std::perror("err recv(): "); + if (::send(fd, MSG_BOUNCE, sizeof MSG_BOUNCE - 1, 0) == -1) + std::perror("err send(): "); + + ::close(fd); + return; + } + /* + if (_read_ret == BUFSIZE) + // send error like "request too long" to client + */ + _buf[_read_ret] = '\0'; + + struct epoll_event ev; + std::memset(&ev, 0, sizeof ev); + ev.events = EPOLLOUT; + ev.data.fd = fd; + if (::epoll_ctl(_epfd, EPOLL_CTL_MOD, fd, &ev) == -1) + std::perror("err accept() epoll_ctl(): "); +} + +void Webserv::_send_response(int fd) +{ + std::cout << "send()\n"; + if (::send(fd, _buf, _read_ret, 0) == -1) + std::perror("err send(): "); + if (::send(fd, MSG_TEST, sizeof MSG_TEST - 1, 0) == -1) + std::perror("err send(): "); + ::close(fd); } diff --git a/srcs/Webserv.hpp b/srcs/Webserv.hpp index 7c3fd4f..c9acb5f 100644 --- a/srcs/Webserv.hpp +++ b/srcs/Webserv.hpp @@ -17,9 +17,15 @@ // # include // usefull for what ? # include // htonl, htons, ntohl, ntohs, inet_addr -# include // poll +# include // epoll # include // fcntl +#define BUFSIZE 8192 +#define TIMEOUT 3000 +#define MAX_EVENTS 42 // arbitrary +#define MSG_TEST "Le Webserv / 20 =D\n" +#define MSG_BOUNCE "bounced properly ;)\n" // placeholder + class Webserv { public: @@ -28,16 +34,24 @@ class Webserv ~Webserv(); // Webserv &operator=(Webserv const &rhs); - void bind(in_port_t port); - void listen(unsigned int max_connections); + void init_virtual_servers(); // ADD config param void start(); private: - int _socket_fd; - struct pollfd _poll_s[42]; // 42 PLACEHOLDER + int _socket_fd; // TODO: replace with vector of "Server" struct + int _epfd; + + // WIP global buffer. Need one variable set per "Client" + char _buf[BUFSIZE+1]; + ssize_t _read_ret; std::map _request; std::map _response; + void _bind(int socket_fd, in_port_t port); + void _listen(int socket_fd, unsigned int max_connections); + void _accept_connection(int fd); + void _read_request(int fd); + void _send_response(int fd); }; #endif diff --git a/srcs/main.cpp b/srcs/main.cpp index 7fe8d61..5121ac7 100644 --- a/srcs/main.cpp +++ b/srcs/main.cpp @@ -10,8 +10,7 @@ int main(void) { Webserv serv; - serv.bind(80); - serv.listen(512); // 512 max connections arbitrary + serv.init_virtual_servers(); serv.start(); } catch (std::exception& e)