CSCommon: RealCPNet.h 소스 파일

MAIET

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