#pragma warning (disable:4949)
#include "NetBridge_IOCP.h"

#pragma unmanaged

HANDLE	CNetBridge_IOCP::m_CompletionPort = NULL;
HANDLE	CNetBridge_IOCP::m_CompThreads[ DF_NB_MAX_COMPLETION_THREAD_COUNT ];


//-----------------------------------------------------------------
CNetBridge_IOCP::CNetBridge_IOCP(void)
{
}
//-----------------------------------------------------------------
CNetBridge_IOCP::~CNetBridge_IOCP(void)
{
}
//-----------------------------------------------------------------
int	CNetBridge_IOCP::Init ()
{
	int iReturn = NB_OK;
	if( ( iReturn = CNetBridge_Base::Init() ) != NB_OK )
	{
		return iReturn;
	}

	// 嘗試去 Create IOCP Port
	if( m_CompletionPort == NULL )
	{
		m_CompletionPort = CreateIoCompletionPort( INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)NULL, 0 );
		if( m_CompletionPort == NULL )
		{
			return NB_ERR_UNABLE_CREATE_IOCP;
		}

		SYSTEM_INFO      sysinfo;

		// Find out how many processors are on this system
		GetSystemInfo( &sysinfo );

		if (sysinfo.dwNumberOfProcessors > DF_NB_MAX_COMPLETION_THREAD_COUNT)
		{
			sysinfo.dwNumberOfProcessors = DF_NB_MAX_COMPLETION_THREAD_COUNT;
		}

		int i = 0;
		// Create the worker threads to service the completion notifications
		//for( int i=0; i < (int)sysinfo.dwNumberOfProcessors ; i++ )
		{
			m_CompThreads[i] = CreateThread( NULL, 0, Thread_Completion, (LPVOID)m_CompletionPort, 0, NULL );
			if ( m_CompThreads[i] == NULL )
			{
				return NB_ERR_UNABLE_CREATE_IOCPTHREAD;
			}
		}
	}
	return iReturn;
}
//-----------------------------------------------------------------
int	CNetBridge_IOCP::Host ( DWORD dwIP , WORD wPort, CEventObj* pEventObj, BOOL bCompress, BOOL bEncryption )
{
	// 有 MainThread 呼叫

	if( pEventObj == NULL )
		return NB_ERR;

	int		rc;

	// Create socket
		DWORD		dwNetID;
		CNetSocket* pSocket = CreateSocket( true, NULL, &dwNetID );

		pSocket->m_IsCompress	= bCompress;
		pSocket->m_IsEncryption	= bEncryption;

	// Link the event
		pSocket->m_pEvent = pEventObj;
		//m_mapEvent[ dwNetID ] = pEventObj;

	// Create the tcp socket
		pSocket->m_tcp_socket	= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

		printf( "\nNB: Create Accept TCP ( %d )", pSocket->m_tcp_socket );

		HANDLE		hrc			= CreateIoCompletionPort( (HANDLE)pSocket->m_tcp_socket, m_CompletionPort, (ULONG_PTR)pSocket, 0);

	// Bind the socket
		SOCKADDR_IN	sa;
		memset( &sa, 0, sizeof( SOCKADDR_IN ) );
		sa.sin_family		= AF_INET;

		if( dwIP != 0 )
			sa.sin_addr.s_addr	= dwIP;
		else
			sa.sin_addr.s_addr = INADDR_ANY;

		sa.sin_port 		= htons( wPort );

		bind( pSocket->m_tcp_socket, (SOCKADDR *) &sa, sizeof(SOCKADDR));

		// check if now it's iocp mode, then associate it to completion port
		// 並將 pSocket 當成 key 傳入
		// and make pSocket be key to turn in

		
		DWORD  hID			 = 0;

		// 測試 AcceptEx 的效率

#ifndef DF_TEST_ACCEPTEX

		listen( pSocket->m_tcp_socket , 1 );
		pSocket->m_thread_Accept = CreateThread( NULL, 0, Thread_Accept,	pSocket, 0, &hID );

#else

		//EM_ACCEPT
		GUID        guidAcceptEx				= WSAID_ACCEPTEX;
		GUID		guidGetAcceptExSockaddrs	= WSAID_GETACCEPTEXSOCKADDRS;
		DWORD       dwbytes						= 0;

		// 取出 AccectEx 的函式指標
		// Need to load the Winsock extension functions from each provider
		//    -- e.g. AF_INET and AF_INET6. 
			rc = WSAIoctl	(	
								pSocket->m_tcp_socket,
								SIO_GET_EXTENSION_FUNCTION_POINTER,
								&guidAcceptEx,
								sizeof( guidAcceptEx ),
								&pSocket->m_pfnAcceptEx,
								sizeof( pSocket->m_pfnAcceptEx ),
								&dwbytes,
								NULL,
								NULL
							);

			if (rc == SOCKET_ERROR)
			{
				On_Error( "NB:Host:WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER failed: %d\n", WSAGetLastError() );
				return NB_ERR;
			}

			rc = WSAIoctl	(
								pSocket->m_tcp_socket,
								SIO_GET_EXTENSION_FUNCTION_POINTER,
								&guidGetAcceptExSockaddrs,
								sizeof( guidGetAcceptExSockaddrs ),
								&pSocket->m_pfnGetAcceptExSockaddrs,
								sizeof( pSocket->m_pfnGetAcceptExSockaddrs ),
								&dwbytes,
								NULL,
								NULL
							);

			if (rc == SOCKET_ERROR)
			{
				On_Error( "NB:Host:WSAIoctl: SIO_GET_EXTENSION_FUNCTION_POINTER failed: %d\n", WSAGetLastError() );
				return NB_ERR;
			}

		// 令之成為 listen mode
			listen( pSocket->m_tcp_socket , 1 );

		// Post overlapped accept on a listening socket
		// 根據 DF_NB_OVERLAPPEDCOUNTER 作出多個 Socket 預備成為 Accept 來做為連線使用

			CBuffer* pBuffer = NULL;

			for( int i = 0; i < DF_NB_OVERLAPPEDCOUNTER; i++ )
			{
				pBuffer = CreateBuffer( DF_NB_PACKETBUFFERSIZE );
				pSocket->m_vecAccept.push_back( pBuffer );
				
				Post_Accept( pSocket, pBuffer );
			}

#endif

	return dwNetID;
}

//-----------------------------------------------------------------

DWORD WINAPI CNetBridge_IOCP::Thread_Completion	( PVOID pParam )
{
	HANDLE				CompletionPort;
	OVERLAPPED			*pOverlapped	=NULL;		// Pointer to overlapped structure for completed I/O
	//HANDLE			CompletionPort;				// Completion port handle
	DWORD				dwBytesTransfered = 0;			// Number of bytes transfered
	int					rc;
	CNetSocket*			pSocket			= NULL;
	CBuffer*			pBuffer			= NULL;
	CNetBridge_IOCP*	pNet			= NULL;
	int					iError			= 0;

	CompletionPort = (HANDLE)pParam;


	while (1)
	{
		//error = NO_ERROR;
		rc		= GetQueuedCompletionStatus(	CompletionPort,	&dwBytesTransfered, (PULONG_PTR)&pSocket,	&pOverlapped, 10000 );

		if( rc != ERROR_SUCCESS )
		{
			pBuffer	= CONTAINING_RECORD( pOverlapped, CBuffer, m_overlapped );
			pNet	= (CNetBridge_IOCP*)pSocket->m_pNetBridge;

			pSocket->m_cs_SocketIO.Enter();

			//if( pSocket->m_emStatus != EM_SOCKET_CLOSING && rc != ERROR_SUCCESS && dwBytesTransfered != 0 )
				// 反推回去原本的資料結構....從書上操來的作法, 真是可怕
				pBuffer	= CONTAINING_RECORD( pOverlapped, CBuffer, m_overlapped );
				pNet	= (CNetBridge_IOCP*)pSocket->m_pNetBridge;

				switch( pBuffer->m_emMode )
				{
				case EM_ACCEPT:
					{
						pNet->Handle_Accept	( pSocket, pBuffer, CompletionPort, dwBytesTransfered );
					} break;
				case EM_RECV:
					{
						pNet->Handle_Recv	( pSocket, pBuffer, CompletionPort, dwBytesTransfered );
					} break;
				case EM_SEND:
					{
						pNet->Handle_Send	( pSocket, pBuffer, CompletionPort, dwBytesTransfered );
					} break;
				case EM_COMPRESS:
					{
						pNet->Handle_Compress( pSocket, pBuffer, CompletionPort, dwBytesTransfered );
					} break;
				}

			pSocket->m_cs_SocketIO.Leave();
		}
		else
		{
			iError = WSAGetLastError();

			if( iError != WAIT_TIMEOUT )
			{
				// 錯誤及斷線處理

				pBuffer	= CONTAINING_RECORD( pOverlapped, CBuffer, m_overlapped );
				pNet	= (CNetBridge_IOCP*)pSocket->m_pNetBridge;

				// 表該 Socket Handle 關畢 or 錯誤發生
				if( pOverlapped != NULL && dwBytesTransfered == 0 )
				{
					// 表該 Socket Handle 關畢
					pNet->Handle_Disconnect	( pSocket, pBuffer, CompletionPort, dwBytesTransfered );				
				}
				else
				{
					// 真的發生了錯誤了
					pNet->On_Error( "NB:Thread_Completion: Thread_Completion GetQueuedCompletionStatus failed: %d", iError );

					// 將 Buff 回收後斷線
					// 關掉 Socket 會使 CompletionQueue 將 Buffer 倒回來給系統
					shutdown( pSocket->m_tcp_socket , SD_BOTH );
					//closesocket( pSocket->m_tcp_socket );
					pSocket->m_tcp_socket = INVALID_SOCKET;

					//shutdown( pSocket->m_tcp_socket, SD_SEND );
					pNet->Handle_Disconnect	( pSocket, pBuffer, CompletionPort, dwBytesTransfered );
				}

			}
		}
		
	}

	
	

	return 0;
}

//-----------------------------------------------------------------
void CNetBridge_IOCP::Handle_Accept ( CNetSocket* pSocket, CBuffer* pBuffer, HANDLE CompletionPort, DWORD dwBytesTransfer )
{
	CNetSocket* pAcceptSocket	= pBuffer->m_pNetSocket;
	HANDLE		hrc				= CreateIoCompletionPort( (HANDLE)pAcceptSocket->m_tcp_socket, CompletionPort, (ULONG_PTR)pAcceptSocket, 0 );

	SOCKADDR_STORAGE	*LocalSockaddr		= NULL;
	SOCKADDR_STORAGE	*RemoteSockaddr		= NULL;
	int					LocalSockaddrLen,	RemoteSockaddrLen;

	if( hrc == NULL )
	{
		// ERROR
		On_Error( "NB: Thread_Completion: CreateIoCompletionPort failed: %d", GetLastError() );
	}

	//pAcceptSocket->m_cs_SocketIO.Enter();

		// Print the client's addresss
		pSocket->m_pfnGetAcceptExSockaddrs	(
												pBuffer->m_pData,
												//pBuffer->m_dwBufferSize - ((sizeof(SOCKADDR_STORAGE) + 16) * 2),
												0,
												sizeof(SOCKADDR_STORAGE) + 16,
												sizeof(SOCKADDR_STORAGE) + 16,
												(SOCKADDR **)&LocalSockaddr,
												&LocalSockaddrLen,
												(SOCKADDR **)&RemoteSockaddr,
												&RemoteSockaddrLen
											);


		SOCKADDR_IN* pAddr = (SOCKADDR_IN*)RemoteSockaddr;
		
		pAcceptSocket->m_dwIP		= pAddr->sin_addr.s_addr;
		pAcceptSocket->m_wPort		= ntohs( pAddr->sin_port );
		

		pAcceptSocket->m_emStatus		= EM_SOCKET_CONNECTED;
		pAcceptSocket->m_emAuthorize	= EM_AUTHORIZE_CHECK_AUTHORIZE;
		
		
		// 先將 Host 的 Socket Event 給予 Create 出來的 新 Socket, 等待認證結束後, 才通知 該 Evnet->OnAccept 產生新事件
		pAcceptSocket->m_pEvent		= pSocket->m_pEvent;

		// 將 Socket 推入管理機制中
		CreateSocket( true, pAcceptSocket );

		// 設定 KeepAlive
		SetKeepAlive( pAcceptSocket );

		// 做出 Recv Buffer, Post 到 overlapped IO request 上
		Post_Recv( pAcceptSocket );

#ifdef _DEBUG
		printf( "\nNB: Handle_Accept( %d )", pAcceptSocket->m_dwNetID );
#endif
		// 無論有無加密或壓縮, 則一率傳送 認證封包給連入端, 告知它我方 Socket 目前狀態( 有無加密或壓縮 )
		// 要求對方遵守我方協定, 並要求對方一定要回覆狀態, 若有加密, 則必需是加密過個封包
			
		Authorize( pSocket, pAcceptSocket );

			// 做出事件通知放入 Queue
			//pSocket->m_pNetBridge->MsgAccept( pSocket, pAcceptSocket );


		// 重新利用 Buffer 去等待連線
		Post_Accept( pSocket, pBuffer );

	//pAcceptSocket->m_cs_SocketIO.Leave();
}
//-----------------------------------------------------------------
void CNetBridge_IOCP::Handle_Compress		( CNetSocket* pSocket, CBuffer* pBuffer, HANDLE CompletionPort, DWORD dwBytesTransfer )
{
	// 對封包進行壓縮動作後將資料送出
	WSABUF	wBuf;
	DWORD	dwBytes = 0;
	int		iReturn;

	pBuffer->m_emMode		= EM_SEND;

	wBuf.buf = (char*)pBuffer->m_pData;
	wBuf.len = pBuffer->m_dwTotalSize;

	//pSocket->m_cs_SocketIO.Enter();

		if( ( iReturn	=	WSASend( pSocket->m_tcp_socket, &wBuf, 1, &dwBytes, 0, &pBuffer->m_overlapped, NULL ) ) == -1 )
		{
			iReturn =	WSAGetLastError();
			On_Error( "Handle_Compress:WSASend: Error %d\n", iReturn );
		}

	pSocket->m_dwSendBuf++;
	//pSocket->m_vecSend.push_back( pBuffer );

	//pSocket->m_cs_SocketIO.Leave();

}
//-----------------------------------------------------------------
void CNetBridge_IOCP::Handle_Recv			( CNetSocket* pSocket, CBuffer* pRecvBuffer, HANDLE CompletionPort, DWORD dwBytesRecvied )
{	
/*
#ifdef DF_DEBUG_RECVMSG
	printf( "\n Recv( %d )",dwBytesRecvied );
#endif
*/
	//pSocket->m_cs_SocketIO.Enter();

	//DWORD dwPacketSize = 0 , dwFlag = 0, dwBufferRemain = 0;



	if( dwBytesRecvied == 0 )
	{
		Handle_Disconnect( pSocket, pRecvBuffer, CompletionPort, dwBytesRecvied );
		return;
	}

	InterlockedExchangeAdd( &pSocket->m_pNetBridge->m_bytesRecv, dwBytesRecvied );

	// 檢查 Buffer 順序
	if( pRecvBuffer != pSocket->m_vecRecv.front() )
	{
		// 順序不對, 暫時將 Buffer 放入暫存區, 且先不處理
		pRecvBuffer->m_dwSize								= dwBytesRecvied;
		pSocket->m_arrayTemp[ pRecvBuffer->m_dwPriority ]	= pRecvBuffer;
		//pSocket->m_cs_SocketIO.Leave();
		return;
	}


	BYTE*	ptr						= pRecvBuffer->m_pData;	
	//BYTE*	pBuffer					= pSocket->m_pBuffer->m_pBuffer;
	//DWORD	dwbytesRemain			= pSocket->m_pBuffer->m_dwBufferSize - pSocket->m_pBuffer->m_dwBytesNeedProcess;
	//DWORD*	pdwBytesNeedProcess		= &pSocket->m_pBuffer->m_dwBytesNeedProcess;
	
	//BYTE*	ptr						= NULL;
	BYTE*	pBuffer					= NULL;
	DWORD	dwBytesNeedProcess		= dwBytesRecvied;
   
    static  CBuffer*  _last_Buffer;


	// 檢查是否有無法 處理仍無法判斷封包大小的不完整的資料
	
	if( pSocket->m_pBufferIncomplete->m_dwSize != 0 )
	{
		if( pSocket->m_pBufferIncomplete->m_dwTotalSize <= ( pSocket->m_pBufferIncomplete->m_dwSize + dwBytesRecvied ) )
		{
			// 理論上不可能會發生這樣的錯誤, 若發生表示收了兩倍 buffer 大小的資料, 確仍不能分析封包大小
			On_Error( "NB:Handle_Recv: pSocket->m_pBufferIncomplete 滿了卻仍不能處理成訊息資料,需要檢視程式碼或除錯. NetID(%d)", pSocket->m_dwNetID );
			// 錯誤處理 ? 強制斷線?
			return;
		}

		// 將這次收到的資料併入不完整資料緩衝區中

		BYTE* ptrIncomplete = pSocket->m_pBufferIncomplete->m_pData + pSocket->m_pBufferIncomplete->m_dwSize;
		memcpy( ptrIncomplete, ptr, dwBytesRecvied );

		pSocket->m_pBufferIncomplete->m_dwSize	+=	dwBytesRecvied;

		ptr										=	pSocket->m_pBufferIncomplete->m_pData;
		dwBytesNeedProcess						=	pSocket->m_pBufferIncomplete->m_dwSize;

	}

	DWORD dwFlag = 0, dwBufferRemain = 0;
	while( dwBytesNeedProcess != 0 )
	{
		DWORD dwPacketSize = 0;

		if( pSocket->m_pBuffer == NULL )
		{
			GetPacketInfo( ptr, dwBytesNeedProcess, &dwFlag, &dwPacketSize );

			// DEBUG
			//---------------------------------------------------------
				if( dwPacketSize != *( (DWORD*) ptr ) )
				{
					int a = 3;
					GetPacketInfo( ptr, dwBytesNeedProcess, &dwFlag, &dwPacketSize );
				}


				if( dwPacketSize > 90000 )
				{
					//MessageBox( NULL ,"封包 Size 過大!!", "Error" , MB_OK );
					Close( pSocket->m_dwNetID );
					MsgOutPut( "\nNB_DEBUG: 封包 Size 過大!! KICK()" );			
				}
			//---------------------------------------------------------

			//MsgOutPut( "\nNB_DEBUG: GetPacketInfo(): dwBytesNeedProcess = %d, dwFlag = %d, dwPacketSize = %d", dwBytesNeedProcess, dwFlag, dwPacketSize );

			if( dwPacketSize != 0 )
			{
				pSocket->m_pBuffer				= CreateBuffer( dwPacketSize );
				pSocket->m_pBuffer->m_dwFlag	= dwFlag;
				pBuffer							= pSocket->m_pBuffer->m_pData;

				//MsgOutPut( "\nNB_DEBUG: CreateBuffer(): dwPacketSize = %d, m_pBuffer->TotalSize = %d, m_pBuffer->dwSize = %d", dwPacketSize, pSocket->m_pBuffer->m_dwTotalSize, pSocket->m_pBuffer->m_dwSize );
			}
			else
				break; // 資料量, 不夠可以檢查封包大小的
		}
		else
		{
			pBuffer				= pSocket->m_pBuffer->m_pData + pSocket->m_pBuffer->m_dwSize;
			//MsgOutPut( "\nNB_DEBUG: pSocket->m_pBuffer != NULL : m_pBuffer->TotalSize = %d, m_pBuffer->dwSize = %d", pSocket->m_pBuffer->m_dwTotalSize, pSocket->m_pBuffer->m_dwSize );
		}

		dwBufferRemain = pSocket->m_pBuffer->GetRemain();

		//MsgOutPut( "\nNB_DEBUG: GetRemain() : %d, m_pBuffer->TotalSize = %d, m_pBuffer->dwSize = %d", dwBufferRemain, pSocket->m_pBuffer->m_dwTotalSize, pSocket->m_pBuffer->m_dwSize );

		if( dwBufferRemain > dwBytesNeedProcess )
		{
			// 資料量不夠一個完整封包
			memcpy( pBuffer, ptr, dwBytesNeedProcess );


			pSocket->m_pBuffer->m_dwSize		+= dwBytesNeedProcess;
			ptr									+= dwBytesNeedProcess;
			dwBytesNeedProcess					=  0;
		}
		else
		{
			// 剩下的量夠一個完整封包
			memcpy( pBuffer, ptr, dwBufferRemain );

			// 收到一個完整的封包了, 推入訊息佇列
			
			pSocket->m_pBuffer->m_dwSize		+= dwBufferRemain;
			//pNetBridge->MsgRecv( pSocket, pSocket->m_pBuffer );
            _last_Buffer = pSocket->m_pBuffer;
			ProcessBuffer( pSocket, pSocket->m_pBuffer );

			//MsgOutPut( "\nNB_DEBUG: ProcessBuffer() : 0x%x, m_pBuffer->TotalSize = %d, m_pBuffer->dwSize = %d\n", pSocket->m_pBuffer->m_pData, pSocket->m_pBuffer->m_dwTotalSize, pSocket->m_pBuffer->m_dwSize );

		
			pSocket->m_pBuffer					=  NULL;
			
			// 移動指標
			ptr									+= dwBufferRemain;
			dwBytesNeedProcess					-= dwBufferRemain;
		}
	}

	// 檢查是否還有剩餘資料還沒處理

	if( dwBytesNeedProcess != 0 )
	{
		// 還有剩餘資料, 就將剩下的資料搬道 IncompleteBuffer 上
		BYTE* pIncomplete = pSocket->m_pBufferIncomplete->m_pData + pSocket->m_pBufferIncomplete->m_dwSize;
		
		if( pSocket->m_pBufferIncomplete->m_dwSize != 0 )
		{
			int a = 3;
		}

		//MessageBox( NULL, "Error 叫小輝 Handle_Recv()", "Error" , MB_OK );
		//Close( pSocket->m_dwNetID );


		memmove( pSocket->m_pBufferIncomplete->m_pData, ptr, dwBytesNeedProcess );
		pSocket->m_pBufferIncomplete->m_dwSize	= dwBytesNeedProcess;
	}
	else
	{
		pSocket->m_pBufferIncomplete->m_dwSize = 0;
	}

	
	// 將 Recv Buffer 再推入 IO Queue, 並將之重新推入 RecvQueue

		pRecvBuffer->m_dwSize	= 0;

		pSocket->m_vecRecv.erase( pSocket->m_vecRecv.begin() );
		pSocket->m_vecRecv.push_back( pRecvBuffer );


	// 將重置好的 Buffer 再次推入 Recv CompleteionQueue 中
		WSABUF	wbuf;
		DWORD	dwBytes		= 0, dwflag		= 0;

		wbuf.buf				= (char*)pRecvBuffer->m_pData;
		wbuf.len				= pRecvBuffer->m_dwTotalSize;

		int rc	= WSARecv( pSocket->m_tcp_socket, &wbuf, 1, &dwBytes, &dwflag, &pRecvBuffer->m_overlapped, NULL );
		if( ( rc == SOCKET_ERROR ) && ( WSAGetLastError() != WSA_IO_PENDING ) )
		{
			// ERROR
			On_Error( "NB:Handle_Recv: WSARecv() failed: %d", WSAGetLastError() );
		}
		

	// 檢查下一個緩衝區是不是已經收到但擱至了, 是的話取出並執行
		
		
		CBuffer* pTempBuf = NULL;
		if( ( pTempBuf = pSocket->m_arrayTemp[ pRecvBuffer->m_dwNextPriority ] ) != NULL )
		{
			Handle_Recv( pSocket, pTempBuf, CompletionPort, pTempBuf->m_dwSize );
			pSocket->m_arrayTemp[ pRecvBuffer->m_dwNextPriority ] = NULL;			
		}

		//pSocket->m_cs_SocketIO.Leave();
}
//-----------------------------------------------------------------

int CNetBridge_IOCP::Connect ( DWORD dwIP, WORD wPort, CEventObj* pEventObj ) 
{
	int iNetID = 0;

	//----------------------------------------------------------------------
	/*
	if( ( iNetID = CNetBridge_Base::Connect( dwIP, wPort, pEventObj ) ) == -1 )
	{
		return NB_ERR;
	}
	*/

		if( pEventObj == NULL )
			return NB_ERR;

		// Create Socket
			CNetSocket* pSocket		= CreateSocket( true, NULL );
			pSocket->m_tcp_socket	= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
			pSocket->m_emAuthorize	= EM_AUTHORIZE_WAIT_AUTHORIZE;

		// 連結 Socket 與 CompletionPort
			HANDLE hrc			= CreateIoCompletionPort( (HANDLE)pSocket->m_tcp_socket, m_CompletionPort, (ULONG_PTR)pSocket, 0);

		// Prepre Socket Address
			SOCKADDR_IN	sa;
			memset( &sa, 0, sizeof( SOCKADDR_IN ) );
			sa.sin_family		= AF_INET;
			sa.sin_addr.s_addr	= dwIP;
			sa.sin_port 		= htons( (WORD)wPort );

		// Tring to connect
			int iReturn			= WSAConnect( pSocket->m_tcp_socket, (SOCKADDR *)&sa, sizeof( SOCKADDR ), NULL, NULL, NULL, NULL );

			if( iReturn == SOCKET_ERROR )
			{
				// 連線失敗
				iReturn = WSAGetLastError();
				pEventObj->OnConnectFailed( iReturn );
				DeleteSocket( pSocket->m_dwNetID );
				return -1;
			}

		// Set Keep alive
			SetKeepAlive( pSocket );

			pSocket->m_emStatus	= EM_SOCKET_CONNECTED;
			// Connected!! Create event and msg
			pSocket->m_pEvent = pEventObj;

		// 暫時不發訊息通知 Client, 而等到 Server 發回認證訊息回來後, 才通知 Client 

	//----------------------------------------------------------------------
	//CNetSocket* pSocket = GetSocket( iNetID );


	// 做出 PostRecv Buffer 等待資料
	Post_Recv( pSocket );
	
	return iNetID;
}

//-----------------------------------------------------------------

void CNetBridge_IOCP::_Send( DWORD dwNetID, DWORD dwSize, PVOID pData, DWORD dwPriority, DWORD dwFlag )
{	
	CNetSocket*	pSocket = GetSocket( dwNetID );
	if( pSocket == NULL || pSocket->m_emStatus != EM_SOCKET_CONNECTED ) return;

	DWORD		dwBytes = 0;
	CBuffer*	pBuffer	= NULL;

	pBuffer		= CreatePacketBuffer( dwSize, pData, NULL );

	if( dwFlag != 0 )
	{
		*((DWORD*)pBuffer->m_pData) |= dwFlag;
	}

	pBuffer->m_emMode		= EM_SEND;

	// 傳送成功, 紀錄傳送中的 Buffer 計數
	pSocket->m_dwSendBuf++;

	m_vecWaitSendSocket.push_back( pSocket->m_dwNetID );
	pSocket->m_vecWaitToSend.push_back( pBuffer );

	// 通知主執行續有事件
	SetEvent( m_hMsgEvent );
}

//-----------------------------------------------------------------

void CNetBridge_IOCP::Handle_Send ( CNetSocket* pSocket, CBuffer* pBuffer, HANDLE CompletionPort, DWORD dwBytesTransfer )
{
#ifdef DF_DEBUG_SENDMSG
	printf("\nSend(%d): %d",pSocket->m_dwNetID, dwBytesTransfer );
#endif
	
	if( dwBytesTransfer == 0 )
	{
		int a = 3;
	}


	InterlockedExchangeAdd( &pSocket->m_pNetBridge->m_bytesSend, dwBytesTransfer );
	
	//pSocket->m_cs_SocketIO.Enter();

		/*
		vector< CBuffer* >::iterator it;
		for( it = pSocket->m_vecSend.begin(); it != pSocket->m_vecSend.end(); it++ )
		{
			if( *it == pBuffer )
			{
			
				pSocket->m_vecSend.erase( it );
				break;
			}
		}
		*/
		pSocket->m_dwSendBuf--;
		
		
		
		// 收到這表示資料已送完
		DeleteBuffer( pBuffer );

	//pSocket->m_cs_SocketIO.Leave();
	
}

//-----------------------------------------------------------------
void CNetBridge_IOCP::Handle_Disconnect	( CNetSocket* pSocket, CBuffer* pBuffer, HANDLE CompletionPort, DWORD dwBytesTransfer )
{
	//queue< CBuffer* >::iterator it;
	vector< CBuffer* >::iterator it;

	pSocket->m_cs_SocketIO.Enter();

	bool bDeleteSocket = false;
	

	if( pSocket->m_emStatus != EM_SOCKET_CLOSING )
	{
#ifdef _DEBUG
		printf( "\nNB: Handle_Disconnect( %d )", pSocket->m_dwNetID );
#endif
		// 將 Socket 推入待斷線佇列中, 若時間超過但系統仍未將所有 Buffer 歸還, 則強制斷線
		pSocket->m_emStatus			= EM_SOCKET_CLOSING;

		// 發出訊息告訴 Client 斷線
		MsgDisconnect( pSocket );
		
		if( pSocket->m_tcp_socket != INVALID_SOCKET )
		{
			closesocket( pSocket->m_tcp_socket );
			pSocket->m_tcp_socket = INVALID_SOCKET;
		}
	}

	switch( pBuffer->m_emMode )
	{
	case EM_ACCEPT:
		{
			for( it = pSocket->m_vecAccept.begin(); it != pSocket->m_vecAccept.end(); it++ )
			{
				if( pBuffer == *it )
				{
					pSocket->m_vecAccept.erase( it );
					break;
				}
			}
		} break;

	case EM_RECV:
		{
			for( it = pSocket->m_vecRecv.begin(); it != pSocket->m_vecRecv.end(); it++ )
			{
				if( pBuffer == *it )
				{
					pSocket->m_vecRecv.erase( it );
					break;
				}
			}
		} break;
	case EM_SEND:
		{
			/*
			for( it = pSocket->m_vecSend.begin(); it != pSocket->m_vecSend.end(); it++ )
			{
				if( pBuffer == *it )
				{
					pSocket->m_vecSend.erase( it );
					break;
				}
			}
			*/
			pSocket->m_dwSendBuf--;
		} break;
	}

	DeleteBuffer( pBuffer );

	//pSocket->m_queueRecv.

	if( pSocket->m_vecAccept.empty() && pSocket->m_vecRecv.empty() && pSocket->m_dwSendBuf == 0 )
	{
		// 發出訊息, 告知介面端已斷線, 且所有 Buffer 已經回收
		//MsgDisconnect( pSocket );
		//bDeleteSocket = true;		
		//pSocket->m_emStatus = EM_SOCKET_UNCONNECT;
		//m_vecWaitCloseSocket.push_back( pSocket );
		pSocket->m_dwTimer	= GetTickCount() + DF_TIME_RECYCLEDELAY;
		m_cs_Socket.Enter();
			m_vecWaitDeleteSocket.push_back( pSocket );
		m_cs_Socket.Leave();
	}
	pSocket->m_cs_SocketIO.Leave();
	

	//if( bDeleteSocket
	//DeleteSocket( pSocket->m_dwNetID );
}
//-----------------------------------------------------------------
void	CNetBridge_IOCP::Post_Accept			( CNetSocket* pSocket , CBuffer* pBuffer )
{
	int		rc		= 0;
	DWORD	dwBytes = 0;

	pBuffer->m_emMode					= EM_ACCEPT;	
	pBuffer->m_pNetSocket				= CreateSocket( false, NULL, false );
	pBuffer->m_pNetSocket->m_tcp_socket	= socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
	printf( "\nNB: Create Accept TCP ( %d )", pSocket->m_tcp_socket );

	if( pBuffer->m_pNetSocket->m_tcp_socket	 == INVALID_SOCKET )
	{
		// ERROR?
	}

	/*
	rc = pSocket->m_pfnAcceptEx(
	pSocket->m_tcp_socket,
	pBuffer->m_pNetSocket->m_tcp_socket,
	pBuffer->m_pBuffer,
	( pBuffer->m_dwBufferSize - ((sizeof(SOCKADDR_STORAGE) + 16) * 2) ),
	( sizeof(SOCKADDR_STORAGE) + 16 ),
	( sizeof(SOCKADDR_STORAGE) + 16 ),
	&bytes,
	&pBuffer->m_overlapped
	);
	*/

	// 令之成為 Accept 狀態, AcceptEx 可以在一開始的時候接收一個封包, 但暫時用不到,故接收 Buffer 填 0
	rc = pSocket->m_pfnAcceptEx	(
									pSocket->m_tcp_socket,
									pBuffer->m_pNetSocket->m_tcp_socket,
									pBuffer->m_pData,
									0,//((sizeof(SOCKADDR_STORAGE) + 16) * 2),
									( sizeof(SOCKADDR_STORAGE) + 16 ),
									( sizeof(SOCKADDR_STORAGE) + 16 ),
									&dwBytes,
									&pBuffer->m_overlapped
								);

	if( rc == FALSE )
	{
		if( WSAGetLastError() != WSA_IO_PENDING )
		{
			On_Error( "NB:Host:m_pfnAcceptEx: %d\n", WSAGetLastError() );
		}
	}
}
	

//-----------------------------------------------------------------
void	CNetBridge_IOCP::Post_Recv		( CNetSocket* pSocket )
{
	WSABUF		wbuf;
	DWORD		dwBytes		= 0, dwflag		= 0;
	int			rc;

	// 做出 Recv Buffer, Post 到 overlapped IO request 上
	CBuffer* pRecvBuffer = NULL;
	for( int i=0; i < DF_NB_OVERLAPPEDCOUNTER ;i++ )
	{
		pRecvBuffer = CreateBuffer( DF_NB_PACKETBUFFERSIZE );

		pRecvBuffer->m_emMode			= EM_RECV;
		pRecvBuffer->m_dwPriority		= i;

		pRecvBuffer->m_dwNextPriority	= i+1;

		if( i == ( DF_NB_OVERLAPPEDCOUNTER -1 ) )
		{
			pRecvBuffer->m_dwNextPriority	= pSocket->m_vecRecv.front()->m_dwPriority;
		}

		pSocket->m_vecRecv.push_back( pRecvBuffer );

		wbuf.buf				= (char*)pRecvBuffer->m_pData;
		wbuf.len				= pRecvBuffer->m_dwTotalSize;

		rc	= WSARecv( pSocket->m_tcp_socket, &wbuf, 1, &dwBytes, &dwflag, &pRecvBuffer->m_overlapped, NULL );
		if( ( rc == SOCKET_ERROR ) && ( WSAGetLastError() != WSA_IO_PENDING ) )
		{
			// ERROR
			pSocket->m_pNetBridge->On_Error( "NB:Handle_Accept: WSARecv failed: %d", WSAGetLastError() );
		}
	}


}
//-----------------------------------------------------------------
void CNetBridge_IOCP::Post_Compress		( CNetSocket* pSocket , CBuffer* pBuffer )
{
	pBuffer->m_emMode				=  EM_COMPRESS;
	*((DWORD*)pBuffer->m_pData)		|= DF_PTAG_COMORESS;
	

	pSocket->m_cs_SocketIO.Enter();
		BOOL b = PostQueuedCompletionStatus( (HANDLE)m_CompletionPort, pBuffer->m_dwTotalSize, (ULONG_PTR)pSocket, &pBuffer->m_overlapped );
	pSocket->m_cs_SocketIO.Leave();
}
//-----------------------------------------------------------------
void CNetBridge_IOCP::Post_Send			( CNetSocket* pSocket , CBuffer* pBuffer )
{
	WSABUF	wBuf;
	DWORD	dwBytes = 0;
	int		iReturn;

	pBuffer->m_emMode		= EM_SEND;

	wBuf.buf = (char*)pBuffer->m_pData;
	wBuf.len = pBuffer->m_dwTotalSize;

	if( wBuf.len > 100000 )
	{
		//MessageBox( NULL , "封包Size過大","錯誤", MB_OK );
	}



	pSocket->m_cs_SocketIO.Enter();	
		if( pSocket->m_tcp_socket != INVALID_SOCKET )
		{
			iReturn	= WSASend( pSocket->m_tcp_socket, &wBuf, 1, &dwBytes, 0, &pBuffer->m_overlapped, NULL );
			if( iReturn == -1 )
			{
				iReturn =	WSAGetLastError();
				if( iReturn != WSA_IO_PENDING )
				{
					On_Error( "Post_Send: Error %d\n", iReturn );
					shutdown( pSocket->m_tcp_socket , SD_SEND );
					pSocket->m_tcp_socket = INVALID_SOCKET;
				}
			}

		}

		if( pSocket->m_tcp_socket == INVALID_SOCKET )
		{
			DeleteBuffer( pBuffer );
			pSocket->m_dwSendBuf--;
		}
	pSocket->m_cs_SocketIO.Leave();
}
//-----------------------------------------------------------------
void CNetBridge_IOCP::SendToAll ( DWORD dwSize, PVOID pPacket, DWORD dwPriority )
{
	map< DWORD, CNetSocket* >::iterator it;
	CNetSocket*	pSocket = NULL;
	m_cs_Socket.Enter();
		for( it = m_mapSocket.begin(); it != m_mapSocket.end(); it++ )
		{
			pSocket = it->second;
			if( pSocket->m_emStatus == EM_SOCKET_CONNECTED )
			{
				Send( pSocket->m_dwNetID, dwSize, pPacket, 0 , 0 );
			}
		}
	m_cs_Socket.Leave();
}
//-----------------------------------------------------------------
void CNetBridge_IOCP::Close ( DWORD dwNetID )
{
	map< DWORD, CNetSocket* >::iterator it;
	CNetSocket*	pSocket = NULL;
	m_cs_Socket.Enter();
		if( ( it = m_mapSocket.find( dwNetID ) ) != m_mapSocket.end() )
			pSocket = it->second;
		else
		{
			m_cs_Socket.Leave();
			return;
		}
	m_cs_Socket.Leave();

	if( pSocket )
	{
		pSocket->m_cs_SocketIO.Enter();			
			pSocket->m_emStatus		= EM_SOCKET_WAIT_CLOSE;
			pSocket->m_dwTimer		= GetTickCount() + 5000;
			m_vecWaitCloseSocket.push_back( pSocket );
		pSocket->m_cs_SocketIO.Leave();
	}
}
//-----------------------------------------------------------------
bool CNetBridge_IOCP::CheckNetID ( DWORD dwNetID )
{
	bool bReturn = false;
	map< DWORD, CNetSocket* >::iterator it;
	CNetSocket*	pSocket = NULL;
	m_cs_Socket.Enter();
	for( it = m_mapSocket.begin(); it != m_mapSocket.end(); it++ )
	{
		pSocket = it->second;
		if( pSocket->m_emStatus == EM_SOCKET_CONNECTED )
		{
			//Send( pSocket->m_dwNetID, dwSize, pPacket, 0 , 0 );
			if( pSocket->m_dwNetID == dwNetID )
				bReturn = true;
		}
	}
	m_cs_Socket.Leave();

	return bReturn;
}
//-----------------------------------------------------------------
DWORD CNetBridge_IOCP::GetNumOfConnections ()
{
	DWORD dwCount = 0;
	map< DWORD, CNetSocket* >::iterator it;
	CNetSocket*	pSocket = NULL;
	m_cs_Socket.Enter();
	for( it = m_mapSocket.begin(); it != m_mapSocket.end(); it++ )
	{
		pSocket = it->second;
		if( pSocket->m_emStatus == EM_SOCKET_CONNECTED )
		{
			dwCount++;
		}
	}
	m_cs_Socket.Leave();

	return dwCount;
}
//-----------------------------------------------------------------
int CNetBridge_IOCP::GetSendQueueSize ()
{
	return 0;
}

//-----------------------------------------------------------------
void CNetBridge_IOCP::ProcessBuffer		( CNetSocket* pSocket, CBuffer* pBuffer )
{
	CBuffer *pDeCompressBuffer = NULL;
	
	// 檢查是有是壓縮後的封包	
	DWORD dwFlag = pBuffer->m_dwFlag;

	CBuffer *pAfterUnCompressBuffer = NULL;

	bool bProcessed = false;

	// 處理壓縮
	if( dwFlag & DF_PTAG_COMORESS )
	{
		bProcessed			= false;
		pDeCompressBuffer	= pBuffer;
		// 現在還沒有壓縮
		// 解開壓縮後放到新的 Buffer
	}

	// 處理封裝
	if( dwFlag & DF_PTAG_COLLECT )
	{
		bProcessed = true;
		CBuffer* pDeCollectBuffer = NULL;
		if( pDeCompressBuffer != NULL )
			pDeCollectBuffer = pDeCompressBuffer; // 表該封包已經解壓
		else
			pDeCollectBuffer = pBuffer;

		// 開始處理解封裝
		int iTotalSize = pBuffer->m_dwTotalSize - sizeof( DWORD );
		
		BYTE*		ptr			= NULL;
		CBuffer*	pPartBuffer = NULL;

		ptr = ( pDeCollectBuffer->m_pData + sizeof( DWORD ) );

		// 手動發處 MsgRecv
		m_cs_MessageAndEvent.Enter();
		pSocket->m_cs_SocketIO.Enter();

			CEventMsg* pMsg  = NULL;

			while( iTotalSize > 0 )
			{
				DWORD dwFlag, dwPartSize;
				
				GetPacketInfo( ptr, iTotalSize, &dwFlag, &dwPartSize );

				pPartBuffer	= CreateBuffer( dwPartSize );
				
				pPartBuffer->m_dwFlag	= dwFlag;

				memcpy( pPartBuffer->m_pData, ptr, dwPartSize );
				
				pPartBuffer->m_dwSize		= dwPartSize;


				pPartBuffer->m_dwTotalSize		= dwPartSize;
				
				pSocket->m_MsgRecvCount++;

				pMsg = CreateMsg( MSG_RECV, pSocket );
				pMsg->MsgRecv.pBuffer			= pPartBuffer;
				

				pSocket->m_pvecMsg->push_back( pMsg );
		
				iTotalSize	-= dwPartSize;
				ptr			+= dwPartSize;
			}

			SetEvent( m_hMsgEvent );

		pSocket->m_cs_SocketIO.Leave();
		m_cs_MessageAndEvent.Leave();
	}

	if( bProcessed )
		DeleteBuffer( pBuffer );
	else
	{
		pBuffer->m_dwSize		= pBuffer->m_dwTotalSize;
		MsgRecv( pSocket, pBuffer );
	}
}

#pragma managed