Files
http-server/src/server/server.cpp

120 lines
3.0 KiB
C++
Executable File

#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);
socketWriteMap.erase(result);
}
void HttpServer::Execute()
{
std::vector<epoll_event> epollEvents;
epollEvents.resize(1000);
while(isOpen)
{
int eventsHappened = epoll_wait(pollFileDescriptor, epollEvents.data(), static_cast<int>(epollEvents.size()), -1);
for (int i = 0; i < eventsHappened; ++i)
{
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),
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);
}
}