RealCPNet.h
00001 #ifndef REALCPNET_H 00002 #define REALCPNET_H 00003 00005 // Class: MRealCPNet class (2001/10/25) 00006 // File: RealCPNet.cpp 00007 // Author: Kim young ho ([email protected]) 00008 // 00009 // Implements Scalable Network Module with I/O Competion Port. 00010 // Code based on MS iocpserver/iocpclient example 00012 00013 #pragma warning(disable:4786) 00014 #include <list> 00015 #include <algorithm> 00016 using namespace std; 00017 00018 #include <Winsock2.h> 00019 #include <mswsock.h> 00020 00021 #include "MPacket.h" 00022 00023 00024 // Constants 00025 #define DEFAULT_PORT 5000 00026 #define MAX_BUFF_SIZE 8192 00027 #define MAX_WORKER_THREAD 16 00028 00029 00030 typedef list<MPacketHeader*> MPacketList; 00031 typedef MPacketList::iterator MPacketListItor; 00032 class MRealCPNet; 00033 00034 00035 typedef enum RCP_IO_OPERATION { 00036 RCP_IO_NONE, 00037 RCP_IO_ACCEPT, 00038 RCP_IO_CONNECT, 00039 RCP_IO_DISCONNECT, 00040 RCP_IO_READ, 00041 RCP_IO_WRITE, 00042 }; 00043 00044 class RCPOverlapped : public WSAOVERLAPPED { 00045 protected: 00046 RCP_IO_OPERATION m_IOOperation; 00047 public: 00048 RCPOverlapped(RCP_IO_OPERATION nIO) { 00049 ZeroMemory(this, sizeof(RCPOverlapped)); 00050 m_IOOperation = nIO; 00051 } 00052 RCP_IO_OPERATION GetIOOperation() { return m_IOOperation; } 00053 }; 00054 00055 class RCPOverlappedSend : public RCPOverlapped { 00056 protected: 00057 int m_nTotalBytes; 00058 int m_nTransBytes; 00059 char* m_pData; 00060 public: 00061 RCPOverlappedSend() : RCPOverlapped(RCP_IO_WRITE) { 00062 m_nTotalBytes = 0; 00063 m_nTransBytes = 0; 00064 m_pData = NULL; 00065 } 00066 virtual ~RCPOverlappedSend() { 00067 free(m_pData); m_pData = NULL; 00068 } 00069 void SetData(char* pData, int nDataLen) { 00070 m_pData = pData; 00071 m_nTotalBytes = nDataLen; 00072 } 00073 int GetTotalBytes() { return m_nTotalBytes; } 00074 int GetTransBytes() { return m_nTransBytes; } 00075 void AddTransBytes(int nBytes) { m_nTransBytes += nBytes; } 00076 char* GetData() { return m_pData; } 00077 }; 00078 00079 class RCPOverlappedRecv : public RCPOverlapped { 00080 protected: 00081 char* m_pBuffer; 00082 int m_nBufferSize; 00083 public: 00084 RCPOverlappedRecv() : RCPOverlapped(RCP_IO_READ) { 00085 m_pBuffer = 0; 00086 m_nBufferSize = 0; 00087 } 00088 void SetBuffer(char* pBuffer, int nBufferSize) { 00089 m_pBuffer = pBuffer; 00090 m_nBufferSize = nBufferSize; 00091 } 00092 char* GetBuffer() { return m_pBuffer; } 00093 int GetBufferSize() { return m_nBufferSize; } 00094 }; 00095 00096 class RCPOverlappedAccept : public RCPOverlapped { 00097 protected: 00098 SOCKET m_Socket; 00099 char* m_pBuffer; 00100 int m_nBufferSize; 00101 public: 00102 RCPOverlappedAccept() : RCPOverlapped(RCP_IO_ACCEPT) { 00103 m_Socket = INVALID_SOCKET; 00104 m_pBuffer = 0; 00105 m_nBufferSize = 0; 00106 } 00107 void SetSocket(SOCKET sd) { m_Socket = sd; } 00108 SOCKET GetSocket() { return m_Socket; } 00109 void SetBuffer(char* pBuffer, int nBufferSize) { 00110 m_pBuffer = pBuffer; 00111 m_nBufferSize = nBufferSize; 00112 } 00113 char* GetBuffer() { return m_pBuffer; } 00114 int GetBufferSize() { return m_nBufferSize; } 00115 }; 00116 00117 // For AcceptEx, the IOCP key is the MRealSession for the listening socket, 00118 // so we need to another field SocketAccept in PER_IO_CONTEXT. When the outstanding 00119 // AcceptEx completes, this field is our connection socket handle. 00120 class MRealSession { 00121 public: 00122 enum SESSIONSTATE { SESSIONSTATE_IDLE, SESSIONSTATE_ACTIVE, SESSIONSTATE_DEAD }; 00123 00124 private: 00125 SOCKET m_sdSocket; 00126 SOCKADDR_IN m_SockAddr; 00127 SESSIONSTATE m_nSessionState; 00128 void* m_pUserContext; 00129 00130 public: 00131 CHAR m_RecvBuffer[MAX_BUFF_SIZE]; // RCPOverlappedRecv 용도 00132 00133 public: 00134 MRealSession() { 00135 m_sdSocket = INVALID_SOCKET; 00136 ZeroMemory(&m_SockAddr, sizeof(SOCKADDR_IN)); 00137 SetSessionState(SESSIONSTATE_IDLE); 00138 SetUserContext(NULL); 00139 00140 ZeroMemory(m_RecvBuffer, sizeof(CHAR)*MAX_BUFF_SIZE); 00141 } 00142 00143 virtual ~MRealSession() { 00144 } 00145 00146 void SetSocket(SOCKET sd) { m_sdSocket = sd; } 00147 SOCKET GetSocket() { return m_sdSocket; } 00148 00149 void SetSockAddr(SOCKADDR_IN* pAddr, int nAddrLen) { CopyMemory(&m_SockAddr, pAddr, min(sizeof(SOCKADDR_IN), nAddrLen)); } 00150 SOCKADDR_IN* GetSockAddr() { return &m_SockAddr; } 00151 char* GetIPString() { return inet_ntoa(m_SockAddr.sin_addr); } 00152 DWORD GetIP() { return m_SockAddr.sin_addr.S_un.S_addr; } 00153 int GetPort() { return ntohs(m_SockAddr.sin_port); } 00154 WORD GetRawPort() { return m_SockAddr.sin_port; } 00155 00156 void SetSessionState(SESSIONSTATE nState) { m_nSessionState = nState; } 00157 SESSIONSTATE GetSessionState() { return m_nSessionState; } 00158 void SetUserContext(void* pContext) { m_pUserContext = pContext; } 00159 void* GetUserContext() { return m_pUserContext; } 00160 }; 00161 00162 00163 class MSessionMap : protected map<SOCKET, MRealSession*> { 00164 protected: 00165 CRITICAL_SECTION m_csLock; 00166 00167 public: 00168 MSessionMap() { InitializeCriticalSection(&m_csLock); } 00169 virtual ~MSessionMap() { DeleteCriticalSection(&m_csLock); } 00170 00171 // Safe Methods //////////////////////////////////////////////////////// 00172 void Add(MRealSession* pSession) { 00173 Lock(); 00174 _ASSERT(pSession->GetSocket() != INVALID_SOCKET); 00175 insert(MSessionMap::value_type(pSession->GetSocket(), pSession)); 00176 Unlock(); 00177 } 00178 bool Remove(SOCKET sd, MSessionMap::iterator* pNextItor=NULL) { 00179 bool bResult = false; 00180 Lock(); 00181 MSessionMap::iterator i = find(sd); 00182 if (i!=end()) { 00183 MRealSession* pSession = (*i).second; 00184 delete pSession; 00185 MSessionMap::iterator itorTmp = erase(i); 00186 if (pNextItor) 00187 *pNextItor = itorTmp; 00188 bResult = true; 00189 } 00190 Unlock(); 00191 return bResult; 00192 } 00193 void RemoveAll() { 00194 OutputDebugString("MSessionMap::RemoveAll() Proceeding \n"); 00195 Lock(); 00196 MSessionMap::iterator itor = begin(); 00197 while( itor != end()) { 00198 MRealSession* pSession = (*itor).second; 00199 delete pSession; 00200 itor = erase(itor); 00201 } 00202 Unlock(); 00203 OutputDebugString("MSessionMap::RemoveAll() Finished \n"); 00204 } 00205 bool IsExist(SOCKET sd) { 00206 bool bResult = false; 00207 Lock(); 00208 MSessionMap::iterator i = find(sd); 00209 if(i!=end()) bResult = true; 00210 Unlock(); 00211 return bResult; 00212 } 00213 MRealSession* GetSession(SOCKET sd) { 00214 MRealSession* pSession = NULL; 00215 Lock(); 00216 MSessionMap::iterator i = find(sd); 00217 if(i!=end()) 00218 pSession = (*i).second; 00219 Unlock(); 00220 return pSession; 00221 } 00222 00223 // Unsafe Methods ///////////////////////////////////////////////////////////////////// 00224 // ~Unsafe() 용도 이외엔 사용금지 00225 void Lock() { EnterCriticalSection(&m_csLock); } 00226 void Unlock() { LeaveCriticalSection(&m_csLock); } 00227 00228 MSessionMap::iterator GetBeginItorUnsafe() { return begin(); } 00229 MSessionMap::iterator GetEndItorUnsafe() { return end(); } 00230 MRealSession* GetSessionUnsafe(SOCKET sd) { // 반드시 Lock과 Unlock을 동반해서 사용 00231 MSessionMap::iterator i = find(sd); 00232 if(i==end()) 00233 return NULL; 00234 else 00235 return (*i).second; 00236 } 00237 bool IsExistUnsafe(MRealSession* pSession) { 00238 for (MSessionMap::iterator i=begin(); i!=end(); i++) { 00239 MRealSession* pItorSession = (*i).second; 00240 if (pItorSession == pSession) 00241 return true; 00242 } 00243 return false; 00244 } 00245 bool RemoveUnsafe(SOCKET sd, MSessionMap::iterator* pNextItor=NULL) { 00246 bool bResult = false; 00247 MSessionMap::iterator i = find(sd); 00248 if (i!=end()) { 00249 MRealSession* pSession = (*i).second; 00250 delete pSession; 00251 MSessionMap::iterator itorTmp = erase(i); 00252 if (pNextItor) 00253 *pNextItor = itorTmp; 00254 bResult = true; 00255 } 00256 return bResult; 00257 } 00258 friend MRealCPNet; 00259 }; 00260 00261 00262 typedef void(RCPCALLBACK)(void* pCallbackContext, RCP_IO_OPERATION nIO, DWORD dwKey, MPacketHeader* pPacket, DWORD dwPacketLen); 00263 00264 00265 class MRealCPNet { 00266 private: 00267 unsigned short m_nPort; 00268 BOOL m_bEndServer; 00269 BOOL m_bRestart; 00270 BOOL m_bVerbose; 00271 HANDLE m_hIOCP; 00272 SOCKET m_sdListen; 00273 DWORD m_dwThreadCount; 00274 HANDLE m_ThreadHandles[MAX_WORKER_THREAD]; 00275 HANDLE m_hCleanupEvent; 00276 00277 MRealSession* m_pListenSession; 00278 MSessionMap m_SessionMap; 00279 00280 CRITICAL_SECTION m_csCrashDump; 00281 00282 RCPCALLBACK* m_fnCallback; 00283 void* m_pCallbackContext; 00284 00285 private: 00286 DWORD CrashDump(PEXCEPTION_POINTERS ExceptionInfo); 00287 00288 protected: 00289 SOCKET CreateSocket(void); 00290 BOOL CreateListenSocket(void); 00291 BOOL CreateAcceptSocket(BOOL fUpdateIOCP); 00292 00293 MRealSession* UpdateCompletionPort(SOCKET sd, RCP_IO_OPERATION nOperation, BOOL bAddToList); 00294 // bAddToList is FALSE for listening socket, and TRUE for connection sockets. 00295 // As we maintain the context for listening socket in a global structure, we 00296 // don't need to add it to the list. 00297 00298 bool PostIOSend(SOCKET sd, char* pBuf, DWORD nBufLen); 00299 void PostIORecv(SOCKET sd); 00300 00301 static bool MakeSockAddr(char* pszIP, int nPort, sockaddr_in* pSockAddr); 00302 bool CheckIPFloodAttack(sockaddr_in* pRemoteAddr, int* poutIPCount); 00303 00304 MRealSession* CreateSession(SOCKET sd, RCP_IO_OPERATION ClientIO); 00305 void DeleteAllSession(); 00306 00307 static DWORD WINAPI WorkerThread(LPVOID WorkContext); 00308 00309 public: 00310 MRealCPNet(); 00311 ~MRealCPNet(); 00312 bool Create(int nPort); 00313 void Destroy(); 00314 00315 void SetLogLevel(int nLevel) { if (nLevel > 0) m_bVerbose = TRUE; else m_bVerbose = FALSE; } 00316 void SetCallback(RCPCALLBACK* pCallback, void* pCallbackContext) { m_fnCallback = pCallback; m_pCallbackContext = pCallbackContext; } 00317 00318 bool Connect(SOCKET* pSocket, char* pszAddress, int nPort); 00319 void Disconnect(SOCKET sd); 00320 VOID CloseSession(MRealSession* pSession, BOOL bGraceful); 00321 00322 bool GetAddress(SOCKET sd, char* pszAddress, int* pPort); 00323 void* GetUserContext(SOCKET sd); 00324 void SetUserContext(SOCKET sd, void* pContext); 00325 00326 bool Send(SOCKET sd, MPacketHeader* pPacket); 00327 00328 friend RCPCALLBACK; 00329 }; 00330 00331 00332 typedef void(RCPLOGFUNC)(const char *pFormat,...); 00333 void SetupRCPLog(RCPLOGFUNC* pFunc); 00334 00335 #ifdef REALCPNET_LINK_SOCKET_LIBS 00336 #pragma comment(lib, "ws2_32.lib") 00337 #pragma comment(lib, "mswsock.lib") 00338 #endif 00339 00340 00341 #endif
MAIET entertainment