120 lines
3.0 KiB
C++
Executable File
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);
|
|
}
|
|
} |