102 lines
3.4 KiB
C++
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
|