Files
42_INT_12_webserv/srcs/webserv/run_loop.cpp
lperrey 2c6bc096cc WIP CGI monitered by epoll
+ OK, but some errors case need to be lookup
2022-08-16 18:38:58 +02:00

178 lines
4.7 KiB
C++

#include "Webserv.hpp"
#define MAX_EVENTS 42 // arbitrary
#define TIMEOUT 3000
// TODO: temp to move in own file
bool operator==(const cgi_pipe_rfd& lhs, int fd)
{ return lhs.fd == fd; }
bool operator==(int fd, const cgi_pipe_rfd& rhs)
{ return fd == rhs.fd; }
#define BUFSIZE 8192 // (8Ko)
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
void Webserv::_read_cgi_output(cgi_pipe_rfd &cgi_fd)
{
char buf[BUFSIZE];
ssize_t ret;
pid_t wait_ret;
ret = ::read(cgi_fd.fd, buf, BUFSIZE);
std::cerr << "cgi read ret = " << ret << "\n";
if (ret == -1)
{
std::perror("err read(cgi_fd)");
cgi_fd.client->cgi_output = STATUS_500;
}
else if (ret == 0)
{
(void)0;
}
else
{
cgi_fd.client->cgi_output.append(buf, ret);
}
wait_ret = ::waitpid(cgi_fd.cgi_pid, NULL, WNOHANG);
std::cerr << "cgi waitpid ret = " << wait_ret << "\n";
if (wait_ret == 0 && ret == -1)
{
_epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(cgi_fd.fd);
// TODO: kill the child :)
}
else if (wait_ret == cgi_fd.cgi_pid)
{
_epoll_update(cgi_fd.client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(cgi_fd.fd);
}
return;
}
void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it)
{
(void)events;
std::cerr << "cgi EPOLLERR" << "\n";
pid_t wait_ret;
wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG);
std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
if (wait_ret == 0)
{
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(it->fd);
// TODO: kill the child :)
}
else if (wait_ret == it->cgi_pid)
{
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(it->fd);
}
}
void Webserv::_cgi_epollhup(uint32_t events, std::vector<cgi_pipe_rfd>::iterator it)
{
(void)events;
std::cerr << "cgi EPOLLHUP" << "\n";
pid_t wait_ret;
wait_ret = ::waitpid(it->cgi_pid, NULL, WNOHANG);
std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
if (wait_ret == 0)
{
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(it->fd);
// TODO: kill the child :)
}
else if (wait_ret == it->cgi_pid)
{
_epoll_update(it->client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
_close_cgi_pipe_rfd(it->fd);
}
}
void Webserv::run()
{
std::cerr << "Server started\n";
struct epoll_event events[MAX_EVENTS];
int nfds;
int i;
int count_loop = 0;
std::vector<listen_socket>::iterator it_lsocket;
std::vector<cgi_pipe_rfd>::iterator it_cgi_fd;
g_run = true;
while (g_run)
{
std::cerr << ++count_loop << "----loop epoll()\n";
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
if (nfds == -1)
{
int errno_copy = errno;
std::perror("err epoll_wait()");
if (errno_copy == EINTR)
g_run = false;
else
throw std::runtime_error("Epoll wait");
}
else if (nfds == 0 && !_clients.empty())
_timeout();
i = 0;
while (i < nfds)
{
try {
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
it_cgi_fd = std::find(_cgi_pipe_rfds.begin(), _cgi_pipe_rfds.end(), events[i].data.fd); // Could be moved in the loop to avoid useless find() call
if (it_lsocket != _listen_sockets.end())
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_lsocket(events[i].events, it_lsocket);
else if (events[i].events & EPOLLIN)
_accept_connection(*it_lsocket);
}
else if (it_cgi_fd != _cgi_pipe_rfds.end())
{
if (events[i].events & EPOLLERR)
_handle_epoll_error_cgi_fd(events[i].events, it_cgi_fd);
else if (events[i].events & EPOLLHUP)
_cgi_epollhup(events[i].events, it_cgi_fd);
else if (events[i].events & EPOLLIN)
_read_cgi_output(*it_cgi_fd);
}
else
{
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
_handle_epoll_error_client(events[i].events, events[i].data.fd);
else if (events[i].events & EPOLLIN)
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
else if (events[i].events & EPOLLOUT)
_response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
}
++i;
if (!g_run)
break;
}
catch (const std::bad_alloc& e) {
std::cerr << e.what() << '\n';
_close_all_clients();
/* Swap to free the memory
From : http://www.uml.org.cn/c%2B%2B/pdf/EffectiveSTL.pdf#page=66 */
std::vector<Client>().swap(_clients);
break;
}
catch (const Webserv::ExecFail& e)
{
std::cerr << e.what() << '\n';
throw;
}
catch (const std::exception& e) {
std::cerr << e.what() << '\n';
++i;
}
}
}
}