135 lines
4 KiB
C++
135 lines
4 KiB
C++
#include <VWeb.h>
|
|
#include <cstring>
|
|
|
|
namespace VWeb {
|
|
Server::Server() {
|
|
m_Router = CreateRef<Router>();
|
|
m_ServerConfig = CreateRef<ServerConfig>();
|
|
m_ServerConfig->EPoll = CreateRef<EPollManager>();
|
|
m_ServerConfig->Socket = CreateRef<SocketManager>(m_ServerConfig);
|
|
m_RequestHandler = CreateRef<RequestHandler>(m_ServerConfig->Socket);
|
|
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<std::thread>(&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> &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>();
|
|
request->ID = meAccept.SockId;
|
|
request->Body = meAccept.Data.str();
|
|
m_RawRequest.Remove(sockID);
|
|
m_RequestHandler->AddRequest(request);
|
|
}
|
|
} // namespace VWeb
|