Use epoll facilities
This commit is contained in:
@@ -1,32 +1,119 @@
|
||||
#include "../logger.hpp"
|
||||
#include "configuration.hpp"
|
||||
#include "server.hpp"
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <sys/epoll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void HttpServer::HandleEpollInEvent(int fd)
|
||||
{
|
||||
if (fd != listeningSocketFileDescriptor)
|
||||
{
|
||||
logger.Info("EPOLLIN Attempted to handle a non registered file descriptor");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned sockaddrSize = sizeof(sockaddr_in);
|
||||
int const connectionFileDescriptor = accept(
|
||||
listeningSocketFileDescriptor,
|
||||
reinterpret_cast<sockaddr *>(&socketAddress),
|
||||
&sockaddrSize);
|
||||
|
||||
socketWriteMap[connectionFileDescriptor] = connectionOperator.HandleNewConnection(connectionFileDescriptor);
|
||||
|
||||
epoll_event event;
|
||||
event.data.fd = connectionFileDescriptor;
|
||||
event.events = EPOLLOUT | EPOLLONESHOT;
|
||||
if (epoll_ctl(pollFileDescriptor, EPOLL_CTL_ADD, connectionFileDescriptor, &event) < 0)
|
||||
{
|
||||
logger.Error("Error registering file descriptor for EPOLLOUT");
|
||||
}
|
||||
}
|
||||
|
||||
void HttpServer::HandleEpollOutEvent(int fd)
|
||||
{
|
||||
auto result = socketWriteMap.find(fd);
|
||||
if (result == socketWriteMap.end())
|
||||
{
|
||||
logger.Error("EPOLLOUT Event for unexpected fd");
|
||||
return;
|
||||
}
|
||||
|
||||
Socket::WriteBytes(fd, result->second);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void HttpServer::Execute()
|
||||
{
|
||||
std::vector<epoll_event> epollEvents;
|
||||
epollEvents.resize(1000);
|
||||
|
||||
while(isOpen)
|
||||
{
|
||||
try
|
||||
int eventsHappened = epoll_wait(pollFileDescriptor, epollEvents.data(), static_cast<int>(epollEvents.size()), -1);
|
||||
for (int i = 0; i < eventsHappened; ++i)
|
||||
{
|
||||
ClientSocket newClient = listeningSocket.AcceptNextConnection();
|
||||
connectionOperator.HandleNewConnection(newClient);
|
||||
}
|
||||
catch (std::runtime_error & e)
|
||||
{
|
||||
logger.Info("ClientSocket dropped on accept");
|
||||
int const fd = epollEvents[i].data.fd;
|
||||
if (epollEvents[i].events & EPOLLIN)
|
||||
{
|
||||
HandleEpollInEvent(fd);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleEpollOutEvent(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpServer::HttpServer(Logger & _logger, ServerConfiguration const & serverConfiguration)
|
||||
: logger(_logger),
|
||||
listeningSocket(serverConfiguration.GetPort()),
|
||||
pollFileDescriptor(-1),
|
||||
listeningSocketFileDescriptor(-1),
|
||||
connectionOperator(_logger, serverConfiguration),
|
||||
isOpen(true)
|
||||
{
|
||||
pollFileDescriptor = epoll_create1(0);
|
||||
if (pollFileDescriptor < 0)
|
||||
{
|
||||
throw std::runtime_error("Error creating epoll file descriptor");
|
||||
}
|
||||
|
||||
socketAddress.sin_family = AF_INET;
|
||||
socketAddress.sin_addr.s_addr = INADDR_ANY;
|
||||
socketAddress.sin_port = htons(serverConfiguration.GetPort());
|
||||
|
||||
listeningSocketFileDescriptor = ListeningSocket::Create(socketAddress, 10000);
|
||||
if (listeningSocketFileDescriptor < 0)
|
||||
{
|
||||
throw std::runtime_error("Error creating listening socket");
|
||||
}
|
||||
|
||||
epoll_event event;
|
||||
event.data.fd = listeningSocketFileDescriptor;
|
||||
event.events = EPOLLIN;
|
||||
if (epoll_ctl(pollFileDescriptor, EPOLL_CTL_ADD, listeningSocketFileDescriptor, &event) < 0)
|
||||
{
|
||||
throw std::runtime_error("Error registering listening socket with epoll facilities");
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << "Listening on port " << serverConfiguration.GetPort();
|
||||
logger.Info(ss.str());
|
||||
}
|
||||
|
||||
HttpServer::~HttpServer()
|
||||
{
|
||||
if (listeningSocketFileDescriptor >= 0)
|
||||
{
|
||||
close(listeningSocketFileDescriptor);
|
||||
}
|
||||
|
||||
if (pollFileDescriptor >= 0)
|
||||
{
|
||||
close(pollFileDescriptor);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user