#ifndef ___SOCKET_SERVER_H_INCLUDED___ #define ___SOCKET_SERVER_H_INCLUDED___ #include <winsock2.h> #include "mem_manager.h" #include "socket_client.h" /////////////////////////////////////////////////////////////////////////////////////////////// //---------------------------- CLASS ---------------------------------------------------------- // A class for handling basic server socket operations. template<class T> class ServerSocket { private: // Server socket. SOCKET m_ServSock; // Pool of client sockets. QueuedBlocks<ClientSocket<T> > m_SockPool; protected: public: // Set the size of the socket pool to the maximum number of accepted // client connections. ServerSocket(unsigned int nPort, unsigned int nMaxClients, bool blnCreateAsync = false, bool blnBindLocal = true): m_SockPool(nMaxClients) { int nRet; unsigned long lngMode = 1; struct sockaddr_in sAddrIn; // Create the server socket, set the necessary // parameters for making it IOCP compatible. this->m_ServSock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); if (this->m_ServSock <= 0) { throw "server socket creation failed."; } // Make server socket Synchronous (blocking) // or Asynchronous (non-blocking) if (blnCreateAsync) { nRet = ioctlsocket(this->m_ServSock, FIONBIO, (u_long FAR*) &lngMode); if (nRet < 0) { closesocket(this->m_ServSock); throw "server socket creation failed."; } } // Fill the structure for binding operation sAddrIn.sin_family = AF_INET; sAddrIn.sin_port = htons(nPort); // Bind to the localhost ("127.0.0.1") to accept connections only from // localhost or // "0.0.0.0" (INADDR_ANY) to accept connections from any IP address. if (blnBindLocal) sAddrIn.sin_addr.s_addr = inet_addr("127.0.0.1"); else sAddrIn.sin_addr.s_addr = htonl(INADDR_ANY); // Bind the structure to the created server socket. nRet = bind(this->m_ServSock, (struct sockaddr *) &sAddrIn, sizeof(sAddrIn)); if (nRet < 0) { closesocket(this->m_ServSock); throw "server socket failed to bind on given port."; } // Set server socket in listen mode and set the listen queue to 20. nRet = listen(this->m_ServSock, 20); if (nRet < 0) { closesocket(this->m_ServSock); throw "server scket failed to listen."; } }; // Returns a pointer to the ClientSocket instance, bind // to the accepted client socket (incoming connection). ClientSocket<T>* Accept() { SOCKET sAccept; struct sockaddr_in sForeignAddIn; int nLength = sizeof(struct sockaddr_in); ClientSocket<T> *ret = NULL; // Check if there is something in the listen queue. sAccept = WSAAccept(this->m_ServSock, (struct sockaddr *) &sForeignAddIn, &nLength, NULL, NULL); // Check for errors. if (sAccept != INVALID_SOCKET) { // Get a pointer to the free ClientSocket // instance from the pool. ret = m_SockPool.GetFromQueue(); if (ret == NULL) { // There are no free instances in the pool, maximum // number of accepted client connections is reached. ::shutdown(sAccept,2); ::closesocket(sAccept); } else { // Everything is fine, so associate the instance // with the client socket. ret->Lock(); ret->Associate(sAccept, &sForeignAddIn); ret->UnLock(); } } return ret; }; // Release the client socket, will try closing connection and // will place it back to the pool. void Release(ClientSocket<T> *sock) { if (sock != NULL) { // check if client socket object is // assigned a socket handler. If yes, // close it. if (sock->IsBusy()) sock->CloseSocket(); // Place it back to the pool. m_SockPool.Release(sock); } }; vector<ClientSocket<T> *> *GetPool() { return m_SockPool.GetBlocks(); }; ~ServerSocket() { shutdown(this->m_ServSock, 2); closesocket(this->m_ServSock); }; }; #endif