//
// Copyright (c) 2002
// Ronald Kevin Burton
//
// Z poniższym kodem nie jest związana żadna gwarancja poprawności działania.
// Program został dołączony do książki ".NET CLR. Księga eksperta" w celu
// ilustracji koncepcji i zasad przedstawionych w tej książce. Program może być 
// używany na własne ryzyko.
//
// Przyznaje się prawo do użycia lub kopiowania tego oprogramowania do dowolnego celu
// bez konieczności ponoszenia żadnych opłat pod warunkiem, że powyższe uwagi zostaną 
// zachowane we wszystkich kopiach. Przyznaje się także prawo do modyfikacji kodu
// i dystrybucji zmodyfikowanego kodu pod warunkiem zachowania powyższych uwag
// oraz dołączenia informacji mówiącej o modyfikacji kodu.
//
//
#include "stdafx.h"
#include "SynchUdpTest.h"

SynchronousUdpTest::SynchronousUdpTest(const std::string& _server, int _port, int _numberOfPackets, int _packetSize) :
        NetworkTest(_server, _port, _numberOfPackets, _packetSize)
{
   socket = WSASocket(AF_INET, SOCK_DGRAM, 0, NULL, 0, 0);
   if (socket == INVALID_SOCKET)
   {
      return;
   }

   sin.sin_family = AF_INET;
   sin.sin_addr.s_addr = inet_addr(server.c_str());
   if(sin.sin_addr.s_addr == INADDR_NONE)
   {
		LPHOSTENT lpHost = ::gethostbyname(server.c_str());
		if(lpHost != NULL)
		{
            // ::CopyMemory(&sin.sin_addr, lpHost->h_addr_list[0],
		    //             lpHost->h_length);
			sin.sin_addr.s_addr = 
				    ((LPIN_ADDR)lpHost->h_addr)->s_addr;
		}
		else
		{
	        std::string strError;
	        ReportSocketError("connect", strError);
	        ::closesocket(socket);
	        socket = INVALID_SOCKET;
			return;
		}
   }

   sin.sin_port = htons((u_short)port);
}

SynchronousUdpTest::~SynchronousUdpTest()
{
}

int SynchronousUdpTest::Start()
{
	int         nTotalReceived, nReceived, nBytes;
	LPBYTE      lpszBuffer;
	DWORD       dwStartTime, dwEndTime;
	int         i;
	DWORD       dwBytesTransmitted = 0;
	int         nNameLen;

	if(socket == INVALID_SOCKET)
		return 0;

	lpszBuffer = new BYTE[packetSize];

	// Wysłanie losowego pakietu
	nBytes = ::sendto(socket, (LPCSTR) lpszBuffer, 100, 0, (LPSOCKADDR) &sin, sizeof(SOCKADDR_IN));
	if(nBytes == SOCKET_ERROR)
		return 0;
	nNameLen = sizeof(SOCKADDR_IN);
	for (nTotalReceived = nReceived = 0;
		nBytes != SOCKET_ERROR &&
		nTotalReceived < nBytes;)
	{
		nReceived = ::recvfrom(socket, (LPSTR) lpszBuffer, nBytes, 0, (LPSOCKADDR) &sin, &nNameLen);
		if(nReceived == SOCKET_ERROR)
			return 0;
		nTotalReceived += nReceived;
	}

	transmitByteCount = 0;
	receivedByteCount = 0;
	for (i = 0, dwStartTime = ::GetCurrentTime();
		i < numberOfPackets; ++i)
	{
  	    nBytes = ::sendto(socket, (LPCSTR) lpszBuffer, packetSize, 0, (LPSOCKADDR) &sin, sizeof(SOCKADDR_IN));
		if (nBytes != SOCKET_ERROR)
		{
			transmitByteCount += nBytes;
			for (nReceived = 0, nTotalReceived = 0;
				 nTotalReceived < nBytes; )
			{
		        nReceived = ::recvfrom(socket, (LPSTR) lpszBuffer, nBytes, 0, (LPSOCKADDR) &sin, &nNameLen);
				if (nReceived == SOCKET_ERROR)
				{
					return 0;
				}
				nTotalReceived += nReceived;
			}
			receivedByteCount += nTotalReceived;
		}
	}

	dwEndTime = ::GetCurrentTime();

	elapsed = dwEndTime - dwStartTime;

	delete [] lpszBuffer;

	::closesocket(socket);
	socket = INVALID_SOCKET;

	return transmitByteCount + receivedByteCount;
}

UNMANAGEDNETWORKING_API void SynchUdpTest(LPCSTR server, int port, int count, int size)
{
	extern NetworkTest *pNetworkTest;

	if(pNetworkTest)
		delete pNetworkTest;

	pNetworkTest = new SynchronousUdpTest(server, port, count, size);

}
