#include "Server.h"

VOID _AcceptConnection(LPSERVER lpSrv)
{	
	SOCKET			sdSocket;
	SOCKADDR_IN		sinRemote;
	INT				iAddrLen = sizeof(SOCKADDR_IN);		
	USHORT			uPort;
	DWORD			dwAddr;
	LPCONNECTION	lpCon;

	ZeroMemory(&sinRemote, iAddrLen);

	sdSocket = accept(lpSrv->sdListener, (struct sockaddr*)&sinRemote, &iAddrLen);
	if(sdSocket != INVALID_SOCKET)
	{
		dwAddr	= 0;
		uPort	= 0;
		WSANtohs(sdSocket, sinRemote.sin_port, &uPort);
		WSANtohl(sdSocket, sinRemote.sin_addr.S_un.S_addr, &dwAddr);
		lpCon = AddConnection(lpSrv->lpIoci, sdSocket, ServerSideProc, sizeof(SERVERDATA), dwAddr, uPort);
		if(lpCon != NULL)
		{			
			AddItem(lpSrv->liClients, lpCon, TRUE);
			((LPSERVERDATA)GetProtocolDataPtr(lpCon))->lpServer = lpSrv;	
			SendCreateMessage(lpCon);
		}
		else
			closesocket(sdSocket);
	}
}

DWORD WINAPI _AcceptorThread(LPVOID lpParameter)
{
	LPSERVER lpSrv = (LPSERVER)lpParameter;
	WSANETWORKEVENTS WSAEvents;

	while(WaitForSingleObject(lpSrv->hEvents[0], 0) != WAIT_OBJECT_0)
	{
		WSAWaitForMultipleEvents(2, lpSrv->hEvents, FALSE, INFINITE, FALSE);

		if(WaitForSingleObject(lpSrv->hEvents[0], 0) != WAIT_OBJECT_0)
		{
			WSAEnumNetworkEvents(lpSrv->sdListener, lpSrv->hEvents[1], &WSAEvents);
			if ((WSAEvents.lNetworkEvents & FD_ACCEPT) && 
				(0 == WSAEvents.iErrorCode[FD_ACCEPT_BIT]))			
				_AcceptConnection(lpSrv);			
		}
		else
			break;
	}	
	ExitThread(0);	
}


LPSERVER CreateServer(LPIOCPINFO lpIoci, LPFGSTRUCT lpFgs)
{
	LPSERVER	lpSrv = (LPSERVER)DefAlloc(sizeof(SERVER));
	SOCKADDR_IN	sinLocal;

	lpSrv->lpIoci	= lpIoci;
	lpSrv->lpFgs	= lpFgs;

	
	if(FGStart(lpSrv->lpFgs, g_sSettings.iVIDeviceID, g_sSettings.iVideoW, g_sSettings.iVideoH) != TRUE)
		goto CreateServerErrLvl1;

	lpSrv->sdListener = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, 
		NULL, 0, WSA_FLAG_OVERLAPPED);
	if(lpSrv->sdListener == INVALID_SOCKET)
		goto CreateServerErrLvl1;
	
	ZeroMemory(&sinLocal, sizeof(SOCKADDR_IN));

	sinLocal.sin_family				= AF_INET;
	sinLocal.sin_addr.S_un.S_addr	= INADDR_ANY;
	sinLocal.sin_port				= htons(g_sSettings.iPort);
	
	if(bind(lpSrv->sdListener, (struct sockaddr*)&sinLocal, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
		goto CreateServerErrLvl2;

	if(listen(lpSrv->sdListener, SOMAXCONN) == SOCKET_ERROR)
		goto CreateServerErrLvl2;

	lpSrv->hEvents[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
	if(lpSrv->hEvents[0] == NULL)
		goto CreateServerErrLvl2;

	lpSrv->hEvents[1] = WSACreateEvent();
	if(lpSrv->hEvents[1] == WSA_INVALID_EVENT)
		goto CreateServerErrLvl3;

	if(WSAEventSelect(lpSrv->sdListener, lpSrv->hEvents[1], FD_ACCEPT) == SOCKET_ERROR)
		goto CreateServerErrLvl4;

	lpSrv->liClients = CreateList(NULL);

	lpSrv->hAcceptorThread = CreateThread(NULL, 0, _AcceptorThread, lpSrv, 0, NULL);
	if(lpSrv->hAcceptorThread == NULL)
		goto CreateServerErrLvl5;

	return lpSrv;
	
CreateServerErrLvl5:	DestroyList(lpSrv->liClients);
CreateServerErrLvl4:	WSACloseEvent(lpSrv->hEvents[1]);
CreateServerErrLvl3:	CloseHandle(lpSrv->hEvents[0]);
CreateServerErrLvl2:	closesocket(lpSrv->sdListener);
CreateServerErrLvl1:	DefFree(lpSrv);
						return NULL;
}
VOID DestroyServer(LPSERVER lpSrv)
{	
	LPLISTENUM lpLe;
	LPCONNECTION lpCon;

	SetEvent(lpSrv->hEvents[0]);
	WaitForSingleObject(lpSrv->hAcceptorThread, INFINITE);
	lpLe = BeginListEnum(lpSrv->liClients);

	while(NextListItem(lpLe, (LPVOID *)&lpCon))
		BeginDisconnect(lpCon);	
	

	ResetEnum(lpLe);

	while(NextListItem(lpLe, (LPVOID *)&lpCon))
	{
		WaitForDisconnect(lpCon);
		DestroyConnection(lpCon);
	}

	EndListEnum(lpLe);

	DestroyList(lpSrv->liClients);
	WSACloseEvent(lpSrv->hEvents[1]);
	CloseHandle(lpSrv->hEvents[0]);
	closesocket(lpSrv->sdListener);
	SendFGMessage(lpSrv->lpFgs, FG_STOP, 0, 0);
	DefFree(lpSrv);	
}
