178 lines
4.9 KiB
C++
178 lines
4.9 KiB
C++
|
|
#include "Webserv.hpp"
|
|
|
|
#define MAX_EVENTS 42 // arbitrary
|
|
#define TIMEOUT 3000
|
|
|
|
|
|
#define BUFSIZE 8192 // (8Ko)
|
|
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
|
|
void Webserv::_read_cgi_output(Client *client)
|
|
{
|
|
char buf[BUFSIZE];
|
|
ssize_t ret;
|
|
std::cerr << "_read_cgi_output()" << "\n";
|
|
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n";
|
|
|
|
ret = ::read(client->cgi_pipe_rfd, buf, BUFSIZE);
|
|
std::cerr << "cgi read ret = " << ret << "\n";
|
|
if (ret == -1)
|
|
{
|
|
std::perror("err read(cgi_fd)");
|
|
client->cgi_output = STATUS_500;
|
|
}
|
|
else if (ret == 0)
|
|
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n";
|
|
else
|
|
client->cgi_output.append(buf, ret);
|
|
}
|
|
|
|
void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client)
|
|
{
|
|
(void)events;
|
|
std::cerr << "cgi EPOLLERR" << "\n";
|
|
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n";
|
|
|
|
client->cgi_output = STATUS_500;
|
|
|
|
pid_t wait_ret;
|
|
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
|
std::cerr << "cgi EPOLLERR waitpid ret = " << wait_ret << "\n";
|
|
if (wait_ret == client->cgi_pid)
|
|
{
|
|
if (client->cgi_pipe_rfd)
|
|
{
|
|
if (::close(client->cgi_pipe_rfd) == -1)
|
|
std::perror("err close()");
|
|
}
|
|
client->cgi_pipe_rfd = 0;
|
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
|
}
|
|
|
|
}
|
|
|
|
void Webserv::_cgi_epollhup(uint32_t events, Client *client)
|
|
{
|
|
(void)events;
|
|
(void)client;
|
|
|
|
/* std::cerr << "cgi EPOLLHUP" << "\n";
|
|
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; */
|
|
|
|
pid_t wait_ret;
|
|
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
|
// std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
|
|
if (wait_ret == client->cgi_pid)
|
|
{
|
|
if (client->cgi_pipe_rfd)
|
|
{
|
|
if (::close(client->cgi_pipe_rfd) == -1)
|
|
std::perror("err close()");
|
|
}
|
|
client->cgi_pipe_rfd = 0;
|
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
|
}
|
|
}
|
|
|
|
Client *Webserv::_find_cgi_fd(int cgi_fd)
|
|
{
|
|
std::vector<Client>::iterator it = _clients.begin();
|
|
std::vector<Client>::iterator it_end = _clients.end();
|
|
while (it != it_end)
|
|
{
|
|
if (it->cgi_pipe_rfd == cgi_fd)
|
|
return (&(*it));
|
|
++it;
|
|
}
|
|
return (NULL);
|
|
}
|
|
|
|
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;
|
|
Client *client_cgi = NULL;
|
|
|
|
g_run = true;
|
|
while (g_run)
|
|
{
|
|
std::cerr << ++count_loop << "----loop epoll() ";
|
|
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
|
|
std::cerr << "(nfds=" << nfds << ")\n";
|
|
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);
|
|
client_cgi = _find_cgi_fd(events[i].data.fd);
|
|
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 (client_cgi)
|
|
{
|
|
if (events[i].events & EPOLLERR)
|
|
_handle_epoll_error_cgi_fd(events[i].events, client_cgi);
|
|
else if (events[i].events & EPOLLIN)
|
|
_read_cgi_output(client_cgi);
|
|
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
|
|
_cgi_epollhup(events[i].events, client_cgi);
|
|
}
|
|
else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find()
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|