#include "StdAfx.h"
#include ".\myping.h"

CMyPing::CMyPing(void)
{
}

CMyPing::~CMyPing(void)
{
}

int CMyPing::SendEchoRequest(SOCKET s,LPSOCKADDR_IN lpstToAddr)
{
	static ECHOREQUEST echoReq;
	static int nId = 1;
	static int nSeq = 1;
	int nRet;

	// Fill in echo request
	echoReq.icmpHdr.Type		= ICMP_ECHOREQ;
	echoReq.icmpHdr.Code		= 0;
	echoReq.icmpHdr.Checksum	= 0;
	echoReq.icmpHdr.ID			= nId++;
	echoReq.icmpHdr.Seq			= nSeq++;

	// Fill in some data to send
	for (nRet = 0; nRet < REQ_DATASIZE; nRet++)
		echoReq.cData[nRet] = ' '+nRet;

	// Save tick count when sent
	echoReq.dwTime				= GetTickCount();

	// Put data in packet and compute checksum
	echoReq.icmpHdr.Checksum = in_cksum((u_short *)&echoReq, sizeof(ECHOREQUEST));

	// Send the echo request  								  
	nRet = sendto(s,						/* socket */
				 (LPSTR)&echoReq,			/* buffer */
				 sizeof(ECHOREQUEST),
				 0,							/* flags */
				 (LPSOCKADDR)lpstToAddr, /* destination */
				 sizeof(SOCKADDR_IN));   /* address length */

	if (nRet == SOCKET_ERROR) 
		WSAError("sendto()");
	return (nRet);
}

DWORD CMyPing::RecvEchoReply(SOCKET s, LPSOCKADDR_IN lpsaFrom, u_char *pTTL)
{
	ECHOREPLY echoReply;
	int nRet;
	int nAddrLen = sizeof(struct sockaddr_in);

	// Receive the echo reply	
	nRet = recvfrom(s,					// socket
					(LPSTR)&echoReply,	// buffer
					sizeof(ECHOREPLY),	// size of buffer
					0,					// flags
					(LPSOCKADDR)lpsaFrom,	// From address
					&nAddrLen);			// pointer to address len

	// Check return value
	if (nRet == SOCKET_ERROR) 
		WSAError("recvfrom()");

	// return time sent and IP TTL
	*pTTL = echoReply.ipHdr.TTL;

	return(echoReply.echoRequest.dwTime);   		
}

int CMyPing::WaitForEchoReply(SOCKET s)
{
	struct timeval Timeout;
	fd_set readfds;

	readfds.fd_count = 1;
	readfds.fd_array[0] = s;
	Timeout.tv_sec = 1;
    Timeout.tv_usec = 0;

	return(select(1, &readfds, NULL, NULL, &Timeout));
}

void CMyPing::WSAError(LPCSTR lpMsg)
{
	CString strMsg;
	strMsg.Format("%s - WSAError: %ld",lpMsg,WSAGetLastError());	
	MessageBox(NULL,strMsg,"ERROR",MB_OK);
}

u_short CMyPing::in_cksum(u_short *addr, int len)
{
	register int nleft = len;
	register u_short *w = addr;
	register u_short answer;
	register int sum = 0;

	/*
	 *  Our algorithm is simple, using a 32 bit accumulator (sum),
	 *  we add sequential 16 bit words to it, and at the end, fold
	 *  back all the carry bits from the top 16 bits into the lower
	 *  16 bits.
	 */
	while( nleft > 1 )  {
		sum += *w++;
		nleft -= 2;
	}

	/* mop up an odd byte, if necessary */
	if( nleft == 1 ) {
		u_short	u = 0;

		*(u_char *)(&u) = *(u_char *)w ;
		sum += u;
	}

	/*
	 * add back carry outs from top 16 bits to low 16 bits
	 */
	sum = (sum >> 16) + (sum & 0xffff);	/* add hi 16 to low 16 */
	sum += (sum >> 16);			/* add carry */
	answer = ~sum;				/* truncate to 16 bits */
	return (answer);
}

BOOL CMyPing::Ping(UINT nRetries,LPCSTR pstrHost)
{
	SOCKET	  rawSocket;
	LPHOSTENT lpHost;
//	UINT	  nLoop;
	int       nRet;
	struct    sockaddr_in saDest;
//	struct    sockaddr_in saSrc;
//	DWORD	  dwTimeSent;
//	DWORD	  dwElapsed;
//	u_char    cTTL;

//	CString str;

	WSADATA wsa;
	if (WSAStartup(MAKEWORD(1, 1), &wsa) != 0)
		return FALSE;

	// Create a Raw socket
	rawSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (rawSocket == SOCKET_ERROR) 
	{
		WSAError("socket()");
		WSACleanup();
		return FALSE;
	}
	
	// Lookup host
	lpHost = gethostbyname(pstrHost);
	if (lpHost == NULL)
	{
//		str.Format("Host not found: %s", pstrHost);
		WSACleanup();
		return FALSE;
	}
	
	// Setup destination socket address
	saDest.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));
	saDest.sin_family = AF_INET;
	saDest.sin_port = htons(80);

	if (connect(rawSocket, (SOCKADDR*)&saDest, sizeof(saDest)) == SOCKET_ERROR)
	{
		DWORD error = WSAGetLastError();
		closesocket(rawSocket);
		WSACleanup();
		return FALSE;
	}
/*
	// Tell the user what we're doing
	str.Format("Pinging %s [%s] with %d bytes of data:",
				pstrHost,
				inet_ntoa(saDest.sin_addr),
				REQ_DATASIZE);

	// Ping multiple times
	for (nLoop = 0; nLoop < nRetries; nLoop++)
	{
		// Send ICMP echo request
		SendEchoRequest(rawSocket, &saDest);

		Sleep(1000);
		nRet = WaitForEchoReply(rawSocket);
		if (nRet == SOCKET_ERROR)
		{
			WSAError("select()");
			break;
		}

		if (!nRet)
		{
			str.Format("Request Timed Out");
			WSACleanup();
			return FALSE;
		}
		else
		{
			// Receive reply
			dwTimeSent = RecvEchoReply(rawSocket, &saSrc, &cTTL);

			// Calculate elapsed time
			dwElapsed = GetTickCount() - dwTimeSent;
			str.Format("Reply[%d] from: %s: bytes=%d time=%ldms TTL=%d", 
				nLoop+1,
				   inet_ntoa(saSrc.sin_addr), 
				   REQ_DATASIZE,
				   dwElapsed/100,
				   cTTL);
			WSACleanup();
			return TRUE;
		}
	}
*/	
	nRet = closesocket(rawSocket);
	if (nRet == SOCKET_ERROR)
		WSAError("closesocket()");
	
	WSACleanup();
	return TRUE;
}



unsigned long conv_addr(const char *name)
{
	struct hostent *he;
	int max;
	unsigned long retval;

	if ((retval = inet_addr(name)) != INADDR_NONE)
		return retval;

	he = gethostbyname(name);
	if (he == NULL)
		return INADDR_NONE;

	for (max = 0; he->h_addr_list[max]; max++) ;
	if (max == 1) return *((unsigned long *)(he->h_addr_list[0]));
	else return *((unsigned long *)(he->h_addr_list[rand() % max]));
}

BOOL CMyPing::Ping2(UINT nRetries,LPCSTR pstrHost)
{
	return TRUE;

	
LPHOSTENT lpHost;

	SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (sock == INVALID_SOCKET) {
		return FALSE;
	}

	bool bRet = false;
	DWORD dwWritten;
	char s[1024];

	lpHost = gethostbyname(pstrHost);

	sockaddr_in sa; 
	sa.sin_family      = AF_INET;
	sa.sin_addr.s_addr = *((u_long FAR *) (lpHost->h_addr));

	sa.sin_port        = htons(80);
	int nNonBlocking = 1;
	ioctlsocket(sock, FIONBIO, (u_long FAR*)&nNonBlocking);

	if (connect(sock, (SOCKADDR*)&sa, sizeof(sa)) ) 
	{
		return TRUE;
	}
	else
	{
		return FALSE;
	}

	if (sock != INVALID_SOCKET)
		closesocket(sock);

}

