Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef __NETWORK_SERVER_TCP__H__
- #define __NETWORK_SERVER_TCP__H__
- #include "../Network.h"
- namespace Engine
- {
- class ServerTcp
- {
- private:
- Network* mNetwork;
- int mPort;
- Network::Socket mListenSocket;
- #ifdef _WIN32
- struct Context
- {
- WSAOVERLAPPED mOverlapped;
- Network::Socket mClientSocket;
- char mBuffer[1024];
- WSABUF mWsaBuffer;
- int mOperationType;
- };
- HANDLE mCompletionPort;
- std::thread mWorkerThread;
- std::atomic<bool> mWorkerRunning;
- #else
- size_t mMaxEvents;
- epoll_event* mEvents;
- int mEpollFd;
- #endif
- bool Setup()
- {
- #ifdef _WIN32
- // Create IO completion port
- mCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
- #endif
- // Setup listening socket
- mListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (!IS_VALID_SOCKET(mListenSocket))
- {
- mNetwork->GetLog()->Print("Network.Server.TCP",
- std::string("Error: Could not create TCP socket: ") + mNetwork->GetLastError());
- return false;
- }
- #ifndef _WIN32
- fcntl(mListenSocket, F_SETFL, fcntl(mListenSocket, F_GETFL, 0) | O_NONBLOCK);
- int opt = 1;
- setsockopt(mListenSocket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- #endif
- sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
- addr.sin_port = htons((unsigned short)(mPort));
- int result = bind(mListenSocket, (sockaddr*)&addr, sizeof(addr));
- if (result == SOCKET_ERROR)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP",
- std::string("Error: Could not bind TCP socket to port ") + std::to_string(mPort) + ": " + mNetwork->GetLastError());
- CLOSE_SOCKET(mListenSocket);
- return false;
- }
- result = listen(mListenSocket, SOMAXCONN);
- if (result == SOCKET_ERROR)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP",
- std::string("Error: Could not listen on TCP socket: ") + mNetwork->GetLastError());
- CLOSE_SOCKET(mListenSocket);
- return false;
- }
- return true;
- }
- void HandleNewConnection()
- {
- #ifdef _WIN32
- Network::Socket clientSocket = accept(mListenSocket, NULL, NULL);
- if (IS_VALID_SOCKET(clientSocket))
- {
- mNetwork->GetLog()->Print("Network.Server.TCP", "Info: New client connected");
- CreateIoCompletionPort((HANDLE)clientSocket, mCompletionPort, 0, 0);
- PostRead(clientSocket);
- }
- #else
- sockaddr_in clientAddr;
- socklen_t clientAddrLen = sizeof(clientAddr);
- Network::Socket clientSocket = accept(mListenSocket, (sockaddr*)&clientAddr, &clientAddrLen);
- if (IS_VALID_SOCKET(clientSocket))
- {
- mNetwork->GetLog()->Print("Network.Server.TCP", "Info: New client connected");
- // Set non-blocking
- fcntl(clientSocket, F_SETFL, fcntl(clientSocket, F_GETFL, 0) | O_NONBLOCK);
- // Add client to epoll list
- epoll_event event;
- event.events = EPOLLIN | EPOLLET;
- event.data.fd = clientSocket;
- epoll_ctl(epoll_fd, EPOLL_CTL_ADD, clientSocket, &event);
- }
- #endif
- }
- void HandleClientData(Network::Socket fd, void* contextPtr, size_t bufferSize)
- {
- #ifdef _WIN32
- Context* context = (Context*)contextPtr;
- send(fd, context->mBuffer, bufferSize, 0);
- #else
- char buffer[1024];
- size_t bytes = recv(fd, buffer, sizeof(buffer), 0);
- if (bytes <= 0)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP.Worker", "Info: Client Disconnected");
- eopll_ctl(mEpollFd, EPOLL_CTL_DEL, fd, NULL);
- close(fd);
- }
- else
- {
- send(fd, buffer, bytes, 0);
- }
- #endif
- }
- #ifdef _WIN32
- void PostRead(Network::Socket client)
- {
- Context* context = new Context();
- ZeroMemory(&context->mOverlapped, sizeof(WSAOVERLAPPED));
- context->mClientSocket = client;
- context->mWsaBuffer.buf = context->mBuffer;
- context->mWsaBuffer.len = sizeof(context->mBuffer);
- context->mOperationType = 0;
- DWORD flags = 0;
- DWORD bytesRead = 0;
- WSARecv(client,
- &context->mWsaBuffer,
- 1,
- &bytesRead,
- &flags,
- &context->mOverlapped,
- NULL);
- }
- void WorkerThreadProc()
- {
- DWORD bytesTransferred;
- ULONG_PTR completionKey;
- LPOVERLAPPED overlapped;
- while (mWorkerRunning)
- {
- BOOL result = GetQueuedCompletionStatus(
- mCompletionPort,
- &bytesTransferred,
- &completionKey,
- &overlapped,
- INFINITE);
- Context* context = (Context*)overlapped;
- if (!result || bytesTransferred == 0)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP.Worker", "Info: Client Disconnected");
- delete context;
- continue;
- }
- HandleClientData(context->mClientSocket, context, bytesTransferred);
- // Re-post the read request to keep listening
- PostRead(context->mClientSocket);
- // TODO: Use memory pool instead of allocating/deallocating every time
- delete context;
- }
- }
- #endif
- public:
- ServerTcp(Network* network, int port, size_t poolSize) :
- mNetwork(network),
- mPort(port),
- mListenSocket(INVALID_SOCKET)
- {
- #ifdef _WIN32
- mCompletionPort = NULL;
- mWorkerRunning = false;
- #else
- mMaxSize = poolSize;
- mEvents = new epoll_event[mMaxSize];
- mEpollFd = NULL;
- #endif
- }
- ~ServerTcp()
- {
- if (IS_VALID_SOCKET(mListenSocket))
- {
- CLOSE_SOCKET(mListenSocket);
- }
- #ifndef _WIN32
- if (mEvents)
- {
- delete[] mEvents;
- }
- #endif
- }
- void Start()
- {
- if (!Setup())
- {
- return;
- }
- #ifdef _WIN32
- mWorkerRunning = true;
- mWorkerThread = std::thread(&ServerTcp::WorkerThreadProc, this);
- #else
- mEpollFd = epoll_create1(0);
- if (mEpollFd == -1)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP",
- std::string("Error: Could not create epoll instance: ") + mNetwork->GetLastError());
- return;
- }
- epoll_event event;
- event.events = EPOLLIN;
- event.data.fd = mListenSocket;
- if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mListenSocket, &event) == -1)
- {
- mNetwork->GetLog()->Print("Network.Server.TCP",
- std::string("Error: Could not add listening socket to epoll instance: ") + mNetwork->GetLastError());
- return;
- }
- #endif
- }
- void Stop()
- {
- #ifdef _WIN32
- mWorkerRunning = false;
- if (mWorkerThread.joinable())
- {
- mWorkerThread.join();
- }
- #else
- if (mEpollFd)
- {
- CLOSE_SOCKET(mEpollFd);
- }
- #endif
- }
- void Process()
- {
- #ifdef _WIN32
- HandleNewConnection();
- #else
- int noFDs = epoll_wait(mEpollFd, mEvents, (int)mMaxSize, -1);
- for (int i = 0; i < noFDs; i++)
- {
- if (mEvents[i].data.fd == mListenSocket)
- {
- HandleNewConnection()
- }
- else
- {
- HandleClientData(mEvents[i].data.fd, NULL, 0);
- }
- }
- #endif
- }
- };
- }
- #endif
Advertisement
Add Comment
Please, Sign In to add comment