/************************************************************************/
/* BattlEye Server code                                                 */
/************************************************************************/

#include "../server/server.h"
#include "winquake.h"

extern qboolean	Sys_StringToSockaddr(char *s, struct sockaddr *sadr);

#ifdef BATTLEYE

static SOCKET mastersocket = INVALID_SOCKET;


qboolean SV_BE_ConnectToMaster(void)
{
	unsigned long _true = 1;
	struct sockaddr masteraddress;

	SV_BE_DisconnectFromMaster();

	// create a TCP socket
	if ((mastersocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
	{
		Com_Printf("ERROR: SV_BE_ConnectToMaster: socket: %s\n", NET_ErrorString());
		return qfalse;
	}

	// make it non-blocking
	if (ioctlsocket(mastersocket, FIONBIO, &_true) == SOCKET_ERROR)
	{
		Com_Printf("ERROR: SV_BE_ConnectToMaster: ioctlsocket FIONBIO: %s\n", NET_ErrorString());
		return qfalse;
	}

	// resolve BE Master DNS host name
	if (!Sys_StringToSockaddr(BATTLEYE_MASTERSERVER, &masteraddress))
	{
		Com_Printf("ERROR: SV_BE_ConnectToMaster: Sys_StringToSockaddr: %s\n", NET_ErrorString());
		return qfalse;
	}

	if (connect(mastersocket, &masteraddress, sizeof(masteraddress)) == SOCKET_ERROR
		&& WSAGetLastError() != WSAEWOULDBLOCK)
	{
		Com_Printf("ERROR: SV_BE_ConnectToMaster: connect: %s\n", NET_ErrorString());
		return qfalse;
	}

	return qtrue;
}

int SV_BE_CheckConnectAttempt(void)
{
	TIMEVAL timeout = { 0, 0 };
	fd_set success_set, failure_set;
	FD_ZERO(&success_set);
	FD_SET(mastersocket, &success_set);
	FD_ZERO(&failure_set);
	FD_SET(mastersocket, &failure_set);

	if (select(0, NULL, &success_set, &failure_set, &timeout) == SOCKET_ERROR)
	{
		Com_Printf("ERROR: SV_BE_CheckConnectAttempt: select: %s\n", NET_ErrorString());
		return -1;
	}
	if (FD_ISSET(mastersocket, &success_set))
		return 1;
	else if (FD_ISSET(mastersocket, &failure_set))
	{
		int error;
		int errlen = sizeof(error);
		getsockopt(mastersocket, SOL_SOCKET, SO_ERROR, (char *)&error, &errlen);
		WSASetLastError(error);
		return -1;
	}
	else
		return 0;
}

void SV_BE_SendToMaster(void* buf, int len)
{
	send(mastersocket, buf, len, 0);
}

int SV_BE_ReceiveFromMaster(void* buf, int len)
{
	int result = recv(mastersocket, buf, len, 0);

	if (result == SOCKET_ERROR && WSAGetLastError() == WSAEWOULDBLOCK)
		return 0;
	else if (result == SOCKET_ERROR || result == 0 || result != len)
		return -1;
	else
		return 1;
}

void SV_BE_DisconnectFromMaster(void)
{
	if (mastersocket != INVALID_SOCKET)
	{
		closesocket(mastersocket);
		mastersocket = INVALID_SOCKET;
	}
}

#endif // BATTLEYE
