//---------------------------------------------------------------------------
#include <vcl.h>
#include "Unit1.h"
#include <stdio.h>
#pragma hdrstop

//---------------------------------------------------------------------------
#pragma argsused
#pragma comment(lib,"ws2_32.lib")
USHORT checksum(USHORT* buff,int size)
{
    ULONG chksum=0;
    while(size>1) //以双字为单位
    {
        chksum+=*buff++;
        size-=2;
    }
    if(size==1)//为奇数
    {
        chksum+=*(UCHAR*)buff;
    }
    chksum=(chksum>>16)+(chksum&0xffff);//高16位+低16位
    chksum+=(chksum>>16);
    return (USHORT)(~chksum);
}
bool SetTimeOut(SOCKET s,int nRetime,bool bSetRecv)
{
  int ret=setsockopt(s,SOL_SOCKET,bSetRecv?SO_RCVTIMEO:SO_SNDTIMEO,(char*)&nRetime,sizeof(nRetime));
  return ret!=SOCKET_ERROR;
}
int main(int argc, char* argv[])
{
       WSADATA wsaData;
       if(WSAStartup(MAKEWORD(2,2),&wsaData)==SOCKET_ERROR)
       {
         WSACleanup();
         return -1;
       }
       SOCKET s;
       if(argc==2)
       {
           char destaddr[32]="";
           if(argv[1][0]>='0'&&argv[1][0]<='9')
           strncpy(destaddr,argv[1],32);
           else  //域名解析
           {
            hostent *hostaddr=gethostbyname(argv[1]);
            in_addr addr;
            if(!hostaddr)
            return -1;
            memmove(&addr,hostaddr->h_addr_list[0],4);
            strncpy(destaddr,inet_ntoa(addr),32);
           }
           s=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
           SetTimeOut(s,1000,True);
           sockaddr_in dest;
           dest.sin_family=AF_INET;
           dest.sin_addr.S_un.S_addr=inet_addr(destaddr);
           char buff[sizeof(ICMPHeader)+32]="";
           ICMPHeader *pICMP=(ICMPHeader*)buff;
           pICMP->icmp_type=8;
           pICMP->icmp_code=0;
           pICMP->icmp_id=(USHORT)::GetCurrentProcessId();
           pICMP->icmp_sequence=0;
           USHORT nSeq=0;
           CHAR recvBuf[1024]="";
           sockaddr_in from;
           int nLen=sizeof(from);
           printf("/nICMP Package test.../n");
           Sleep(1000);
           while(True)
           {
               static int nCount=0;
               int nRet;
               if(nCount++==4)
               break;
               pICMP->icmp_checksum=0;
               pICMP->icmp_timestamp=::GetTickCount();
               pICMP->icmp_sequence=nSeq++;
               pICMP->icmp_checksum=checksum((USHORT*)buff,sizeof(ICMPHeader)+32);
               nRet=::sendto(s,buff,sizeof(ICMPHeader)+32,0,(SOCKADDR*)&dest,sizeof(dest));
               if(nRet==SOCKET_ERROR)
               {
                   printf("sendto() failed:%d/n",WSAGetLastError());
                   return -1;
               }
               nRet=::recvfrom(s,recvBuf,1024,0,(SOCKADDR*)&from,&nLen);
               if(nRet==SOCKET_ERROR)
               {
                   if(WSAGetLastError()==WSAETIMEDOUT)//超时
                   {
                      printf("timed out/n");
                      continue;
                   }
                   printf("recvfrom() failed:%d/n",WSAGetLastError());
                   return -1;
               }
               int nTick=::GetTickCount();
               if(nRet<sizeof(IPHeader)+sizeof(ICMPHeader))
               {
                   printf("Too few bytes from %s /n",inet_ntoa(from.sin_addr));
               }
               IPHeader *pRecvIP=(IPHeader*)(recvBuf);
               ICMPHeader *pRecvICMP=(ICMPHeader*)(recvBuf+sizeof(IPHeader));
               if(pRecvICMP->icmp_type!=0) //返回不是回显
               {
                   printf("nonecho type %d recvd /n",pRecvICMP->icmp_type);
                   return -1;
               }
               if(pRecvICMP->icmp_id!=::GetCurrentProcessId())
               {
                   printf(" someone else's packet!/n");
                   return -1;
               }
               printf("%d byte from %s:",nRet,inet_ntoa(from.sin_addr));
               printf(" icmp_seq=%d,",pRecvICMP->icmp_sequence);
               printf(" time=%dms,",nTick-pRecvICMP->icmp_timestamp);
               printf(" TTL=%d. /n",pRecvIP->ipTTL);
               Sleep(1000);
           }
       }
       closesocket(s);
       WSACleanup();
       return 0;
}
//---------------------------------------------------------------------------