#include #include namespace VWeb { Server::Server() { m_Router = CreateRef(); m_ServerConfig = CreateRef(); m_ServerConfig->EPoll = CreateRef(); m_ServerConfig->Socket = CreateRef(m_ServerConfig); m_RequestHandler = CreateRef(m_ServerConfig->Socket); auto& middleWare = m_RequestHandler->Middleware(); middleWare->Create(); middleWare->Create(); middleWare->Create(); m_RequestHandler->m_Server = this; }; void Server::LoadSharedLibs() { // @TODO: LOAD .so files inside sub-folder } void Server::Start() { m_ServerConfig->Socket->Init(); if (m_ServerConfig->Socket->IsErrored()) return; m_RequestHandler->SetRouter(m_Router); m_RequestHandler->InitThreads(m_ServerConfig->WorkerThreads); m_WorkerThread = CreateRef(&Server::Execute, this); fprintf(stdout, "[VWeb] Running Server On: 0.0.0.0:%d\n", m_ServerConfig->Port); } void Server::AddRoute(const std::string &path, const Ref &route) { m_Router->AddRoute(path, route); } void Server::RemoveRoute(const std::string &path) { m_Router->DeleteRoute(path); } void Server::Execute() { constexpr size_t MAX_EVENTS = 5000; struct epoll_event events[MAX_EVENTS]; int sockID = m_ServerConfig->Socket->ID(); for (;;) { if (m_IsExit) break; int eventCount = m_ServerConfig->EPoll->Wait(MAX_EVENTS, events); for (int i = 0; i < eventCount; ++i) { auto &event = events[i]; if ((event.events & EPOLLERR) || (event.events & EPOLLHUP)) { m_RawRequest.Remove(event.data.fd); SocketUtils::Close(event.data.fd); continue; } if (event.events & EPOLLOUT) { OutgoingExecute(events[i]); } if (event.data.fd == sockID) { IncomingExecute(event); } else if (event.events & EPOLLIN) { HandleRequestReading(event); } } } } void Server::OutgoingExecute(epoll_event &event) { if (!m_OutRequest.Has(event.data.fd)) { m_ServerConfig->Socket->SetReadListen(event.data.fd); return; } auto &sendData = m_OutRequest.Get(event.data.fd); auto returnVal = SocketUtils::Write(sendData); if (returnVal == WriteState::ERRORED || returnVal == WriteState::OK) { SocketUtils::WriteDone(sendData.SocketID); m_OutRequest.Remove(event.data.fd); } } void Server::IncomingExecute(epoll_event &event) { for (;;) { auto req = m_ServerConfig->Socket->Handle(); if (req.ReturnValue == EPollReturns::BREAK || req.ReturnValue == EPollReturns::FAILURE) break; else if (req.ReturnValue == EPollReturns::OK) { if (!m_RawRequest.Add(req.SockId, req)) SocketUtils::Close(req.SockId); } else continue; } } void Server::HandleRequestReading(epoll_event &event) { int fd = event.data.fd; if (!m_RawRequest.Has(fd)) { SocketUtils::Close(fd); return; } auto &data = m_RawRequest.Get(fd); char buf[m_ServerConfig->BufferSize]; bool isFinished = false; for (;;) { memset(buf, 0, sizeof(buf)); ssize_t nBytes = recv(fd, buf, m_ServerConfig->BufferSize, 0); if (nBytes < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { if (isFinished) CreateRequest(fd); break; } else { m_RawRequest.Remove(fd); SocketUtils::Close(fd); break; } } else if (nBytes == 0) { m_RawRequest.Remove(fd); SocketUtils::Close(fd); } else { if (m_ServerConfig->MaxBufferSize != -1 && data.CurrentBytes + nBytes > m_ServerConfig->MaxBufferSize) { data.Data.clear(); data.Data << "GET @431 HTTP/1.1"; CreateRequest(fd); break; } data.Data << buf; data.CurrentBytes += nBytes; if (nBytes < m_ServerConfig->BufferSize - 1) { isFinished = true; continue; } } } } void Server::CreateRequest(int sockID) { Accept &meAccept = m_RawRequest.Get(sockID); auto request = CreateRef(); request->ID = meAccept.SockId; request->Body = meAccept.Data.str(); m_RawRequest.Remove(sockID); m_RequestHandler->AddRequest(request); } Ref &Server::Middleware() { return m_RequestHandler->Middleware(); } } // namespace VWeb