www.pudn.com > NetScan.rar > Ping.cpp


// Ping.cpp: implementation of the CPing class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "Ping.h" 
#include "NetScanView.h" 
#include  
 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
//----------线程------------------- 
 
CCriticalSection global_criticalsection;//临界区变量 
UINT PingThreadProc(LPVOID pParam);		//线程函数的声明 
 
struct _PINGTHREADPARAM				//Ping线程参数 
{ 
	unsigned int addr_begin;	//线程扫描的起始IP地址 
	unsigned int addr_end;	//线程扫描的结束IP地址 
	CPing *const pPing; 
	_PINGTHREADPARAM(CPing *d):pPing(d)//构造函数 
	{ 
	} 
}; 
 
volatile BOOL g_threadContral;//线程停止的标准,true为运行,false为停止; 
_PINGTHREADPARAM *param=NULL;//全局的线程参数对象 
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
CPing::CPing(CView *pParent /*NULL*/) 
{ 
	m_pView=(CNetScanView *)pParent; 
	//初始化ICMP包 
	icmp_data=NULL; 
	seq_no=0; 
	recvbuf=NULL; 
	m_bRecordRout=FALSE; 
	lpdest=NULL; 
	datasize=DEF_PACKET_SIZE; 
	m_pingNumber=1; 
 
	//初始化socket 
	WSADATA wsaData; 
	if(WSAStartup(MAKEWORD(2,2),&wsaData)!=0) 
	{ 
		AfxMessageBox("Sorry,you cannot load socket dll!"); 
		return; 
	} 
	m_hSocket=INVALID_SOCKET; 
 
} 
 
CPing::~CPing() 
{ 
 
 
} 
 
void CPing::SetConfigure(unsigned int begin, unsigned int end,int pingNumber,int timeout,BOOL recordrout, int size) 
{//设置Ping参数 
	m_bRecordRout = recordrout; 
    datasize = size; 
    m_addrBegin=begin; 
	m_addrEnd=end; 
	//lpdest=host; 
	m_pingNumber=pingNumber; 
	m_timeout=timeout; 
}	 
 
void CPing::DecodeIPOptions(char *buf,int bytes) 
{//解析IP可选参数 
    IpOptionHeader *ipopt = NULL; 
    IN_ADDR         inaddr; 
    int             i; 
    HOSTENT        *host = NULL; 
 
    ipopt = (IpOptionHeader *)(buf + 20); 
 
	TRACE("Ping 结果:   \r\n"); 
  //  m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
    for(i = 0; i < (ipopt->ptr / 4) - 1; i++) 
    { 
        inaddr.S_un.S_addr = ipopt->addr[i]; 
        if (i != 0) 
		{ 
		//	m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
		} 
        host = gethostbyaddr((char *)&inaddr.S_un.S_addr, 
                    sizeof(inaddr.S_un.S_addr), AF_INET); 
 
		CString temp; 
        if (host) 
		{ 
			temp.Format("(%-15s) %s \r\n", inet_ntoa(inaddr), host->h_name); 
		//	m_dlg->m_result+=temp; 
		//	m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
		} 
        else 
		{ 
			temp.Format("(%-15s)\r\n", inet_ntoa(inaddr)); 
		//	m_dlg->m_result+=temp; 
		//	m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
		} 
    } 
    return; 
 
} 
	 
void CPing::Cleanup() 
{//清除ICMP包 
	if (m_hSocket != INVALID_SOCKET)  
        closesocket(m_hSocket); 
    HeapFree(GetProcessHeap(), 0, recvbuf); 
    HeapFree(GetProcessHeap(), 0, icmp_data); 
 
//    WSACleanup(); 
    return ; 
} 
	 
void CPing::ping() 
{//使用多线程的ping函数 
	 
//	g_threadContral=false; 
	param = new _PINGTHREADPARAM(this); 
	param->addr_begin=m_addrBegin; 
	param->addr_end=m_addrEnd; 
	AfxBeginThread(PingThreadProc,param); 
} 
 
BOOL CPing::runPing(unsigned int addr) 
{ 
	CString result; 
	m_hSocket = WSASocket (AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0,WSA_FLAG_OVERLAPPED); 
//创建Socket		 
	if (m_hSocket == INVALID_SOCKET)  
		{ 
			((CEdit *)m_pView->GetDlgItem(1020))->SetWindowText("创建Socket失败\n"); 
			return false; 
		} 
//设置接收超时选项 
		int bread = setsockopt(m_hSocket, SOL_SOCKET, SO_RCVTIMEO,  
			(char*)&m_timeout, sizeof(m_timeout)); 
		if(bread == SOCKET_ERROR)  
		{ 
			((CEdit *)m_pView->GetDlgItem(1020))->SetWindowText("设置socket接收超时选项错误!"); 
			return false; 
		} 
//设置发送超时选项 
		bread = setsockopt(m_hSocket, SOL_SOCKET, SO_SNDTIMEO,  
			(char*)&m_timeout, sizeof(m_timeout)); 
		if (bread == SOCKET_ERROR)  
		{ 
			((CEdit *)m_pView->GetDlgItem(1020))->SetWindowText("设置socket发送超时选项错误!"); 
			return false; 
		} 
//转换地址的格式 
		memset(&m_addrDest, 0, sizeof(m_addrDest)); 
		m_addrDest.sin_family = AF_INET; 
		unsigned char *a; 
		a=(unsigned char*)&addr; 
		m_addrDest.sin_addr.S_un.S_un_b.s_b1=a[3]; 
		m_addrDest.sin_addr.S_un.S_un_b.s_b2=a[2]; 
		m_addrDest.sin_addr.S_un.S_un_b.s_b3=a[1]; 
		m_addrDest.sin_addr.S_un.S_un_b.s_b4=a[0]; 
		result.Format("%s",inet_ntoa(m_addrDest.sin_addr)); 
		result="正在ping  "+result+"  "; 
		((CEdit *)m_pView->GetDlgItem(1020))->SetWindowText(result);//inet_ntoa(m_addrDest.sin_addr)); 
		TRACE("m_addrDest.sin_addr = %s\n", inet_ntoa(m_addrDest.sin_addr)); 
// 创建ICMP包 
		datasize += sizeof(IcmpHeader);   
		icmp_data =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET); 
		recvbuf =(char*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,MAX_PACKET); 
		if (!icmp_data)  
		{ 
			TRACE(result+"堆分配错误!"); 
			return false; 
		} 
		memset(icmp_data,0,MAX_PACKET); 
//向ICMP包中填充数据 
		FillICMPData(icmp_data,datasize); 
//发送/接收ICMP包的循环,共进行m_pingNumber遍 
		int nCount=0; 
		while(1)  
		{ 
			int bwrote; 
			TRACE("%d\n",nCount);      
			if (nCount++ == m_pingNumber)  
				break; 
//发送ICMP包        
			((IcmpHeader*)icmp_data)->i_cksum = 0; 
			((IcmpHeader*)icmp_data)->timestamp = GetTickCount(); 
			((IcmpHeader*)icmp_data)->i_seq = seq_no++; 
			((IcmpHeader*)icmp_data)->i_cksum =checksum((USHORT*)icmp_data, datasize); 
			bwrote = sendto(m_hSocket, icmp_data, datasize, 0,  
				(struct sockaddr*)&m_addrDest, sizeof(m_addrDest)); 
			if (bwrote == SOCKET_ERROR) 
			{ 
				if (WSAGetLastError() == WSAETIMEDOUT)  
				{ 
					TRACE(result+"发送数据超时! "); 
					continue; 
				} 
				TRACE(result+"发送数据函数调用错误!"); 
				return false; 
			} 
//接收ICMP包 
			int fromlen = sizeof(m_addrFrom); 
			bread = recvfrom(m_hSocket,recvbuf, MAX_PACKET, 0,  
				(struct sockaddr*)&m_addrFrom, &fromlen); 
			if (bread == SOCKET_ERROR) 
			{ 
				if (WSAGetLastError() == WSAETIMEDOUT)  
				{ 
					TRACE(result+"接收数据超时!"); 
					continue; 
				} 
				TRACE(result+"接收数据函数调用错误!"); 
				return 0; 
			} 
			 
//解析ICMP头,显示ping结果 
			if(DecodeICMPHeader(recvbuf, bread, &m_addrFrom)) 
			{ 
				TRACE("\n正确解析ICMP头!!!\n"); 
				return true; 
			} 
			else TRACE(result+"解析ICMP头出错"); 
		}//end while(1) 
	return false; 
} 
 
bool CPing::DecodeICMPHeader(char *buf, int bytes, SOCKADDR_IN* from) 
{//解析ICMP包头结构信息 
	IpHeader       *iphdr = NULL; 
    IcmpHeader     *icmphdr = NULL; 
    unsigned short  iphdrlen; 
    DWORD           tick; 
    static   int    icmpcount = 0; 
 
    iphdr = (IpHeader *)buf; 
	// Number of 32-bit words * 4 = bytes 
    iphdrlen = iphdr->h_len * 4; 
	//得到以毫秒为单位的当前时间 
    tick = GetTickCount(); 
	//第一次解析ICMP头信息时需要解析IP头选项 
    if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount)) 
        DecodeIPOptions(buf, bytes);//解析IP包头可选项信息 
 
	CString temp; 
    if (bytes  < iphdrlen + ICMP_MIN)  
    { 
		temp.Format("Too few bytes from %s \r\n",inet_ntoa(from->sin_addr)); 
		//m_dlg->m_result+=temp; 
		//m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
    } 
    icmphdr = (IcmpHeader*)(buf + iphdrlen); 
 
    if (icmphdr->i_type != ICMP_ECHOREPLY)  
    { 
		temp.Format("nonecho type %d recvd \r\n", icmphdr->i_type); 
		//m_dlg->m_result+=temp; 
		//m_dlg->SetDlgItemText(IDC_EDIT2,m_dlg->m_result); 
        return false; 
    } 
 
    // 确保当前的ICMP回应是所发送的ICMP包的回应,有可能其它程序也发送了ICMP包 
    if (icmphdr->i_id != (USHORT)GetCurrentProcessId())  
    { 
		temp.Format("someone else's packet! \r\n"); 
        return false; 
    } 
	//设置Ping结果信息 
/* 
	temp.Format("%d bytes from %s: \r\n", bytes, inet_ntoa(from->sin_addr)); 
	m_dlg->m_result+=temp; 
	temp.Format(" icmp_seq = %d. \r\n", icmphdr->i_seq); 
	m_dlg->m_result+=temp; 
	temp.Format(" time: %d ms \r\n", tick - icmphdr->timestamp); 
	m_dlg->m_result+=temp; 
	temp.Format("校验和 = %d \r\n",icmphdr->i_cksum); 
	m_dlg->m_result+=temp; 
	temp.Format("标识符 = %d \r\n",icmphdr->i_id); 
	m_dlg->m_result+=temp; 
	*/ 
	 
//将IP信息加入list中 
	_hostInfo  hi; 
	hi.destIP=from->sin_addr.S_un.S_addr; 
	hi.time=tick - icmphdr->timestamp; 
	m_pView->m_listHost.AddTail(hi); 
 
//将这条信息写入ListContral 
	int iPos=m_pView->m_ctrlList.GetItemCount(); 
	char buffer[10]; 
	_itoa(hi.time,buffer,10); 
	LV_ITEM lvitem1; 
	 
	lvitem1.mask=LVIF_TEXT; 
	lvitem1.iItem=iPos; 
	lvitem1.iSubItem=0; 
	lvitem1.pszText=inet_ntoa(m_addrDest.sin_addr); 
	iPos=m_pView->m_ctrlList.InsertItem(&lvitem1);//返回表项插入后的索引号 
 
	lvitem1.iItem=iPos; 
	lvitem1.iSubItem=1; 
	lvitem1.pszText=buffer; 
	m_pView->m_ctrlList.SetItem(&lvitem1); 
 
    icmpcount++; 
    return true; 
} 
 
USHORT CPing::checksum(USHORT *buffer, int size) 
{//校验数据 
   unsigned long cksum=0; 
 
    while (size > 1)  
    { 
        cksum += *buffer++; 
        size -= sizeof(USHORT); 
    } 
    if (size)  
    { 
        cksum += *(UCHAR*)buffer; 
    } 
    cksum = (cksum >> 16) + (cksum & 0xffff); 
    cksum += (cksum >>16); 
    return (USHORT)(~cksum); 
} 
 
void CPing::FillICMPData(char *icmp_data, int datasize) 
{//填充ICMP数据 
	IcmpHeader *icmp_hdr = NULL; 
    char       *datapart = NULL; 
 
    icmp_hdr = (IcmpHeader*)icmp_data; 
    icmp_hdr->i_type = ICMP_ECHO;        // 请求一个ICMP回显 
    icmp_hdr->i_code = 0; 
    icmp_hdr->i_id = (USHORT)GetCurrentProcessId(); 
    icmp_hdr->i_cksum = 0; 
    icmp_hdr->i_seq = 0; 
   
    datapart = icmp_data + sizeof(IcmpHeader); 
} 
 
UINT PingThreadProc(LPVOID pParam) 
{ 
	_PINGTHREADPARAM* param=(_PINGTHREADPARAM*)pParam; 
	ASSERT(param); 
	CPing *pPing=param->pPing; 
	unsigned int ip; 
	 
	for(ip=param->addr_begin;ip<=param->addr_end;ip++)	 
	{	 
		if(g_threadContral) 
		{	global_criticalsection.Lock(); 
			if(pPing->runPing(ip)==false) 
				continue; 
			pPing->Cleanup(); 
			global_criticalsection.Unlock(); 
		}else break; 
	} 
	((CEdit *)pPing->m_pView->GetDlgItem(1020))->SetWindowText("ping 结束"); 
	((CEdit *)pPing->m_pView->GetDlgItem(1017))->SetWindowText("开始ping"); 
	g_threadContral=false; 
	return 0; 
}