#include "../logger.hpp" #include "configuration.hpp" #include "server.hpp" #include #include #include #include #include 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(&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 epollEvents; epollEvents.resize(1000); while(isOpen) { int eventsHappened = epoll_wait(pollFileDescriptor, epollEvents.data(), static_cast(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); } }