VWeb/Source/SocketManager.cpp

102 lines
3.4 KiB
C++

#include <VWeb.h>
namespace VWeb {
#pragma region VWebSocketUtils
bool SocketUtils::MakeAsync(int socketId) {
int flags = fcntl(socketId, F_GETFL, 0);
if (flags == -1)
return false;
if (fcntl(socketId, F_SETFL, flags | O_NONBLOCK) == -1)
return false;
return true;
}
bool SocketUtils::Add(int socketId) { return MakeAsync(socketId); }
bool SocketUtils::Close(int socketId) { return close(socketId) >= 0; }
bool SocketUtils::WriteDone(int socketId) {
return shutdown(socketId, SHUT_WR) != -1;
}
WriteState SocketUtils::Write(VWeb::SendData &sendData) {
const char *buf = sendData.Content.c_str();
ssize_t n;
while (sendData.Size > 0) {
n = send(sendData.SocketID, buf + sendData.Offset, sendData.Size, 0);
if (n < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
return WriteState::EPOLL;
fprintf(stderr, "[SocketUtils::Write] >> Im Errored\n");
return WriteState::ERRORED;
}
sendData.Offset += n;
sendData.Size -= n;
}
return WriteState::OK;
}
#pragma endregion VWebSocketUtils
#pragma region VWebSocketManager
SocketManager::SocketManager(const Ref<VWeb::ServerConfig> &serverConfig)
: m_ServerConfig(serverConfig) {}
SocketManager::~SocketManager() { close(m_SocketID); }
Accept SocketManager::Handle() {
Accept requestReturn{};
int client =
accept(m_SocketID, (sockaddr *)&m_Address, (socklen_t *)&m_AddressLength);
if (client < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
requestReturn.ReturnValue = EPollReturns::BREAK;
else
requestReturn.ReturnValue = EPollReturns::FAILURE;
} else {
requestReturn.SockId = client;
requestReturn.ReturnValue = EPollReturns::FAILURE;
if (SocketUtils::Add(client) &&
m_ServerConfig->EPoll->Dispatch(client, EPOLLIN | EPOLLET)) {
requestReturn.ReturnValue = EPollReturns::OK;
} else {
SocketUtils::Close(client);
}
}
return requestReturn;
}
bool SocketManager::SetSendListen(int socketID) {
return m_ServerConfig->EPoll->UpdateEvents(socketID, EPOLLOUT | EPOLLET);
}
bool SocketManager::SetReadListen(int socketID) {
return m_ServerConfig->EPoll->UpdateEvents(socketID, EPOLLIN | EPOLLET);
}
void SocketManager::Init() {
if ((m_SocketID = socket(AF_INET, SOCK_STREAM, 0)) == 0)
return Errored("Cannot Create Socket");
auto trues = 1;
struct timeval tv {
1, 0
};
setsockopt(m_SocketID, SOL_SOCKET, SO_REUSEADDR, &trues, sizeof(int));
setsockopt(m_SocketID, SOL_SOCKET, SO_REUSEPORT, &trues, sizeof(int));
setsockopt(m_SocketID, SOL_SOCKET, SOCK_CLOEXEC, &trues, sizeof(int));
setsockopt(m_SocketID, SOL_SOCKET, SOCK_NONBLOCK, &trues, sizeof(int));
setsockopt(m_SocketID, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);
m_Address.sin_family = AF_INET;
m_Address.sin_addr.s_addr = htonl(INADDR_ANY);
m_Address.sin_port = htons(m_ServerConfig->Port);
if (bind(m_SocketID, (struct sockaddr *)&m_Address, m_AddressLength) < 0)
return Errored("Cannot Bind Socket");
SocketUtils::MakeAsync(m_SocketID);
if (listen(m_SocketID, SOMAXCONN) < 0)
return Errored("Socket Failed to Listen");
if (!m_ServerConfig->EPoll->Dispatch(m_SocketID,EPOLLIN | EPOLLET | EPOLLOUT))
return Errored("Cannot Add Event");
}
void SocketManager::Errored(const std::string &data) {
if (m_SocketID > 0)
close(m_SocketID);
fprintf(stderr, "%s\n", data.c_str());
m_IsErrored = true;
}
#pragma endregion VWebSocketManager
} // namespace VWeb