#include 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 &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