#include "StdAfx.h"
#include ".\network.h"


cNetwork::cNetwork(void)
{
}


cNetwork::~cNetwork(void)
{
	mpServiceMode = NULL;
	Destroy();
}


bool cNetwork::Init( cServiceMode* pServiceMode )
{
	WSADATA wsaData;

	SOCKET serverSock;
	SOCKADDR_IN serverAddr;

	if( WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) != 0)
		return false;

	/// SOCK_STREAM 연결형 서버(TCP)
	serverSock = socket( AF_INET, SOCK_STREAM, 0 );
	if( serverSock == INVALID_SOCKET )
		return false;

	serverAddr.sin_family = AF_INET;
	serverAddr.sin_addr.S_un.S_addr = htonl( INADDR_ANY );	/// 자신의 IP반환
	serverAddr.sin_port = htons( AGENT_PORT );

	if( bind( serverSock, (struct sockaddr*)&serverAddr, sizeof(serverAddr) ) == SOCKET_ERROR )
		return false;

	mhNewEvent = WSACreateEvent();
	if( WSAEventSelect( serverSock, mhNewEvent, FD_ACCEPT ) == SOCKET_ERROR )
		return false;

	if( listen( serverSock, 5 ) == SOCKET_ERROR )
		return false;

	mSockCnt = 0;
	mhSockAry[mSockCnt] = serverSock;

	mhEventAry[mSockCnt] = mhNewEvent;
	++mSockCnt;

	mpServiceMode = pServiceMode;

	return true;
}


void cNetwork::Process()
{
	int idx = 0;

	SOCKET clientSock;
	SOCKADDR_IN clientAddr;
	int clientLen;
	WSANETWORKEVENTS netEvents;

	while(1)
	{
		idx = WSAWaitForMultipleEvents( mSockCnt, mhEventAry, FALSE, WSA_INFINITE, FALSE );
		idx = idx - WSA_WAIT_EVENT_0;

		for( int i = idx ; i < mSockCnt ; ++i )
		{
			idx = WSAWaitForMultipleEvents( 1, &mhEventAry[i], TRUE, 0, FALSE );
			if( ( idx == WSA_WAIT_FAILED || idx == WSA_WAIT_TIMEOUT ) )
				continue;

			idx = i;
			WSAEnumNetworkEvents( mhSockAry[idx], mhEventAry[idx], &netEvents );

			switch( netEvents.lNetworkEvents )
			{
			case FD_ACCEPT:
				{
					if( netEvents.iErrorCode[FD_ACCEPT_BIT] != 0 )
					{
						puts("FD_ACCEPT ERROR!");
						break;
					}

					clientLen = sizeof( clientAddr );
					clientSock = accept( mhSockAry[idx], (SOCKADDR *)&clientAddr, &clientLen );
					mhNewEvent = WSACreateEvent();
					WSAEventSelect( clientSock, mhNewEvent, FD_READ | FD_CLOSE );

					mhEventAry[mSockCnt] = mhNewEvent;
					mhSockAry[mSockCnt] = clientSock;
					++mSockCnt;
					printf( "New Connect Socket[%d] \n", clientSock );
				}
				break;
			case FD_READ:
				{
					if( netEvents.iErrorCode[FD_READ_BIT] != 0 )
					{
						printf( "FD_READ ERROR \n" );
						break;
					}

					NetworkMsgParser( mhSockAry[idx-WSA_WAIT_EVENT_0] );
				}
				break;
			case FD_CLOSE:
				{
					printf("Socket Close[%d] \n", mhSockAry[idx] );

					WSACloseEvent( mhEventAry[idx] );
					closesocket( mhSockAry[idx] );					
					--mSockCnt;

					for( int j = idx ; j < mSockCnt ; ++j )
						mhSockAry[j] = mhSockAry[j+1];
					for( int j = idx ; j < mSockCnt ; ++j )
						mhEventAry[j] = mhEventAry[j+1];
				}
			}
		}
	}

	WSACleanup();	
}


void cNetwork::Destroy()
{
	for( int i = 0 ; i < mSockCnt ; ++i )
	{
		WSACloseEvent( mhEventAry[i] );
		closesocket( mhSockAry[i] );					
	}
	mSockCnt = 0;
}


void cNetwork::NetworkMsgParser( SOCKET socket )
{

	char tempMsg[MSGSIZE];
	char msg[MSGSIZE];

	int size = 0;
	memset( tempMsg, 0, sizeof(tempMsg) );
	size = recv( socket, tempMsg, sizeof(tempMsg), 0);

	if( size <= sizeof(Packet) ) 
		return;

	Packet* pPacket = (Packet*)tempMsg;
	if( pPacket->ver != 1 || pPacket->tos != TOS_SERVERTOOL )
		return;

	memset( msg, 0, sizeof(msg) );
	memcpy( msg, tempMsg + sizeof(Packet), sizeof(tempMsg) - sizeof(Packet) );

	MSGROOT* pRecvRoot = (MSGROOT*)msg;

	switch( pRecvRoot->Category )
	{
	case NM_SERVERTOOL:
		{
			switch( pRecvRoot->Protocol )
			{
			case NM_SERVERTOOL_CHANNEL_ON_REQ:
				{
					mpServiceMode->SetszSvcName( _T("GameServer") );
					mpServiceMode->DoStartSvc();
				}
				break;
			case NM_SERVERTOOL_CHANNEL_OFF_REQ:
				{
					mpServiceMode->SetszSvcName( _T("GameServer") );
					mpServiceMode->DoStopSvc();
				}
				break;
			case NM_SERVERTOOL_LOGIN_ON_REQ:
				{
					mpServiceMode->SetszSvcName( _T("LoginServer") );
					mpServiceMode->DoStartSvc();
				}
				break;
			case NM_SERVERTOOL_LOGIN_OFF_REQ:
				{
					mpServiceMode->SetszSvcName( _T("LoginServer") );
					mpServiceMode->DoStopSvc();
				}
				break;
			}
		}
		break;
	}
}