home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / ping / ping.c < prev    next >
C/C++ Source or Header  |  1997-10-08  |  7KB  |  282 lines

  1. /******************************************************************************\
  2. * ping.c - Simple ping utility using SOCK_RAW
  3. *       This is a part of the Microsoft Source Code Samples.
  4. *       Copyright 1996-1997 Microsoft Corporation.
  5. *       All rights reserved.
  6. *       This source code is only intended as a supplement to
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. #pragma pack(4)
  13.  
  14. #define WIN32_LEAN_AND_MEAN
  15. #include <winsock2.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18.  
  19. #define ICMP_ECHO 8
  20. #define ICMP_ECHOREPLY 0
  21.  
  22. #define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
  23.  
  24. /* The IP header */
  25. typedef struct iphdr {
  26.     unsigned int h_len:4;          // length of the header
  27.     unsigned int version:4;        // Version of IP
  28.     unsigned char tos;             // Type of service
  29.     unsigned short total_len;      // total length of the packet
  30.     unsigned short ident;          // unique identifier
  31.     unsigned short frag_and_flags; // flags
  32.     unsigned char  ttl; 
  33.     unsigned char proto;           // protocol (TCP, UDP etc)
  34.     unsigned short checksum;       // IP checksum
  35.  
  36.     unsigned int sourceIP;
  37.     unsigned int destIP;
  38.  
  39. }IpHeader;
  40.  
  41. //
  42. // ICMP header
  43. //
  44. typedef struct _ihdr {
  45.   BYTE i_type;
  46.   BYTE i_code; /* type sub code */
  47.   USHORT i_cksum;
  48.   USHORT i_id;
  49.   USHORT i_seq;
  50.   /* This is not the std header, but we reserve space for time */
  51.   ULONG timestamp;
  52. }IcmpHeader;
  53.  
  54. #define STATUS_FAILED 0xFFFF
  55. #define DEF_PACKET_SIZE 32
  56. #define MAX_PACKET 1024
  57.  
  58. #define xmalloc(s) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(s))
  59. #define xfree(p)   HeapFree (GetProcessHeap(),0,(p))
  60.  
  61. void fill_icmp_data(char *, int);
  62. USHORT checksum(USHORT *, int);
  63. void decode_resp(char *,int ,struct sockaddr_in *);
  64.  
  65. void Usage(char *progname){
  66.   
  67.   fprintf(stderr,"Usage:\n");
  68.   fprintf(stderr,"%s <host> [data_size]\n",progname);
  69.   fprintf(stderr,"datasize can be up to 1Kb\n");
  70.   ExitProcess(STATUS_FAILED);
  71.  
  72. }
  73. int main(int argc, char **argv){
  74.  
  75.   WSADATA wsaData;
  76.   SOCKET sockRaw;
  77.   struct sockaddr_in dest,from;
  78.   struct hostent * hp;
  79.   int bread,datasize;
  80.   int fromlen = sizeof(from);
  81.   int timeout = 1000;
  82.   char *dest_ip;
  83.   char *icmp_data;
  84.   char *recvbuf;
  85.   unsigned int addr=0;
  86.   USHORT seq_no = 0;
  87.  
  88.   if (WSAStartup(MAKEWORD(2,1),&wsaData) != 0){
  89.     fprintf(stderr,"WSAStartup failed: %d\n",GetLastError());
  90.     ExitProcess(STATUS_FAILED);
  91.   }
  92.  
  93.   if (argc <2 ) {
  94.     Usage(argv[0]);
  95.   }
  96.   sockRaw = WSASocket (AF_INET,
  97.                        SOCK_RAW,
  98.                        IPPROTO_ICMP,
  99.                        NULL, 0,0);
  100.   
  101.   if (sockRaw == INVALID_SOCKET) {
  102.     fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
  103.     ExitProcess(STATUS_FAILED);
  104.   }
  105.   bread = setsockopt(sockRaw,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,
  106.                       sizeof(timeout));
  107.   if(bread == SOCKET_ERROR) {
  108.       fprintf(stderr,"failed to set recv timeout: %d\n",WSAGetLastError());
  109.     ExitProcess(STATUS_FAILED);
  110.   }
  111.   timeout = 1000;
  112.   bread = setsockopt(sockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,
  113.                       sizeof(timeout));
  114.   if(bread == SOCKET_ERROR) {
  115.       fprintf(stderr,"failed to set send timeout: %d\n",WSAGetLastError());
  116.     ExitProcess(STATUS_FAILED);
  117.   }
  118.   memset(&dest,0,sizeof(dest));
  119.  
  120.   hp = gethostbyname(argv[1]);
  121.  
  122.   if (!hp){
  123.     addr = inet_addr(argv[1]);
  124.   }
  125.   if ((!hp)  && (addr == INADDR_NONE) ) {
  126.     fprintf(stderr,"Unable to resolve %s\n",argv[1]);
  127.     ExitProcess(STATUS_FAILED);
  128.   }
  129.  
  130.   if (hp != NULL)
  131.       memcpy(&(dest.sin_addr),hp->h_addr,hp->h_length);
  132.   else
  133.       dest.sin_addr.s_addr = addr;
  134.  
  135.   if (hp)
  136.       dest.sin_family = hp->h_addrtype;
  137.   else
  138.       dest.sin_family = AF_INET;
  139.  
  140.   dest_ip = inet_ntoa(dest.sin_addr);
  141.  
  142.   if (argc >2) {
  143.     datasize = atoi(argv[2]);
  144.     if (datasize == 0)
  145.       datasize = DEF_PACKET_SIZE;
  146.  
  147.   }
  148.   else
  149.       datasize = DEF_PACKET_SIZE;
  150.     
  151.   datasize += sizeof(IcmpHeader);  
  152.  
  153.   icmp_data = xmalloc(MAX_PACKET);
  154.   recvbuf = xmalloc(MAX_PACKET);
  155.  
  156.   if (!icmp_data) {
  157.     fprintf(stderr,"HeapAlloc failed %d\n",GetLastError());
  158.     ExitProcess(STATUS_FAILED);
  159.   }
  160.   
  161.  
  162.   memset(icmp_data,0,MAX_PACKET);
  163.   fill_icmp_data(icmp_data,datasize);
  164.  
  165.   while(1) {
  166.     int bwrote;
  167.     
  168.     ((IcmpHeader*)icmp_data)->i_cksum = 0;
  169.     ((IcmpHeader*)icmp_data)->timestamp = GetTickCount();
  170.  
  171.     ((IcmpHeader*)icmp_data)->i_seq = seq_no++;
  172.     ((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, 
  173.                                             datasize);
  174.  
  175.     bwrote = sendto(sockRaw,icmp_data,datasize,0,(struct sockaddr*)&dest,
  176.                     sizeof(dest));
  177.     if (bwrote == SOCKET_ERROR){
  178.       if (WSAGetLastError() == WSAETIMEDOUT) {
  179.           printf("timed out\n");
  180.         continue;
  181.       }
  182.       fprintf(stderr,"sendto failed: %d\n",WSAGetLastError());
  183.       ExitProcess(STATUS_FAILED);
  184.     }
  185.     if (bwrote < datasize ) {
  186.       fprintf(stdout,"Wrote %d bytes\n",bwrote);
  187.     }
  188.     bread = recvfrom(sockRaw,recvbuf,MAX_PACKET,0,(struct sockaddr*)&from,
  189.                  &fromlen);
  190.     if (bread == SOCKET_ERROR){
  191.       if (WSAGetLastError() == WSAETIMEDOUT) {
  192.           printf("timed out\n");
  193.         continue;
  194.       }
  195.       fprintf(stderr,"recvfrom failed: %d\n",WSAGetLastError());
  196.       ExitProcess(STATUS_FAILED);
  197.     }
  198.     decode_resp(recvbuf,bread,&from);
  199.     Sleep(1000);
  200.  
  201.   }
  202.   return 0;
  203.  
  204. }
  205. /* 
  206.     The response is an IP packet. We must decode the IP header to locate 
  207.     the ICMP data 
  208. */
  209. void decode_resp(char *buf, int bytes,struct sockaddr_in *from) {
  210.  
  211.     IpHeader *iphdr;
  212.     IcmpHeader *icmphdr;
  213.     unsigned short iphdrlen;
  214.  
  215.     iphdr = (IpHeader *)buf;
  216.  
  217.     iphdrlen = iphdr->h_len * 4 ; // number of 32-bit words *4 = bytes
  218.  
  219.     if (bytes  < iphdrlen + ICMP_MIN) {
  220.         printf("Too few bytes from %s\n",inet_ntoa(from->sin_addr));
  221.     }
  222.  
  223.     icmphdr = (IcmpHeader*)(buf + iphdrlen);
  224.  
  225.     if (icmphdr->i_type != ICMP_ECHOREPLY) {
  226.         fprintf(stderr,"non-echo type %d recvd\n",icmphdr->i_type);
  227.         return;
  228.     }
  229.     if (icmphdr->i_id != (USHORT)GetCurrentProcessId()) {
  230.         fprintf(stderr,"someone else's packet!\n");
  231.         return ;
  232.     }
  233.     printf("%d bytes from %s:",bytes, inet_ntoa(from->sin_addr));
  234.     printf(" icmp_seq = %d. ",icmphdr->i_seq);
  235.     printf(" time: %d ms ",GetTickCount()-icmphdr->timestamp);
  236.     printf("\n");
  237.         
  238. }
  239.  
  240.  
  241. USHORT checksum(USHORT *buffer, int size) {
  242.  
  243.   unsigned long cksum=0;
  244.  
  245.   while(size >1) {
  246.     cksum+=*buffer++;
  247.     size -=sizeof(USHORT);
  248.   }
  249.   
  250.   if(size ) {
  251.     cksum += *(UCHAR*)buffer;
  252.   }
  253.  
  254.   cksum = (cksum >> 16) + (cksum & 0xffff);
  255.   cksum += (cksum >>16);
  256.   return (USHORT)(~cksum);
  257. }
  258. /* 
  259.     Helper function to fill in various stuff in our ICMP request.
  260. */
  261. void fill_icmp_data(char * icmp_data, int datasize){
  262.  
  263.   IcmpHeader *icmp_hdr;
  264.   char *datapart;
  265.  
  266.   icmp_hdr = (IcmpHeader*)icmp_data;
  267.  
  268.   icmp_hdr->i_type = ICMP_ECHO;
  269.   icmp_hdr->i_code = 0;
  270.   icmp_hdr->i_id = (USHORT)GetCurrentProcessId();
  271.   icmp_hdr->i_cksum = 0;
  272.   icmp_hdr->i_seq = 0;
  273.   
  274.   datapart = icmp_data + sizeof(IcmpHeader);
  275.   //
  276.   // Place some junk in the buffer.
  277.   //
  278.   memset(datapart,'E', datasize - sizeof(IcmpHeader));
  279.  
  280. }
  281.