Microsoft PingProgramSource codeFull Version
Author: Hou zhijiang
Writing a Ping program is the first step of network programming for many people !! Source of the Ping programCodeAfter my modifications and debugging, I can basically Replace the self-contained Ping program in windows. Each module has my detailed comments and modification logs, and I hope it will be helpful to everyone !!
/* The main source code of this program comes from the msdn website. I just made some improvements and comments! In addition, you must add the ws2_32.lib library file before building. Otherwise, an error "error lnk2001:" is displayed! */
/*************************************** ***************************************\
| Version 1.1 modification record: |
| <1> the socket blocking problem is solved, so that timeout requests can be correctly processed! |
| Bytes |
| Version 1.2 modification record: |
| <1> added the user-controlled ICMP packet sending function (the second parameter of the command). |
| <2> added the ping result statistics function. |
\*************************************** ***************************************/
# Pragma pack (4)
# Include
# Include
# Include
# Define ICMP_Echo 8
# Define ICMP_ECHOREPLY 0
# Define icmp_min 8 // minimum 8 byte ICMP packet (just header)
/* The IP header */
Typedef struct iphdr {
Unsigned int h_len: 4; // length of the header
Unsigned int version: 4; // version of IP
Unsigned char TOS; // type of service
Unsigned short total_len; // total length of the packet
Unsigned short ident; // Unique Identifier
Unsigned short frag_and_flags; // flags
Unsigned char TTL;
Unsigned char proto; // protocol (TCP, UDP etc)
Unsigned short checksum; // IP checksum
Unsigned int sourceip;
Unsigned int destip;
} Ipheader;
//
// ICMP Header
//
Typedef struct icmphdr {
Byte I _type;
Byte I _code;/* type sub Code */
Ushort I _cksum;
Ushort I _id;
Ushort I _seq;
/* This is not the STD header, But we reserve space for time */
Ulong timestamp;
} Icmpheader;
# Define status_failed 0 xFFFF
# Define def_packet_size 32
# Define def_packet_number 4/* Number of sent data packets */
# Define max_packet 1024
# Define xmalloc (s) heapalloc (getprocessheap (), heap_zero_memory, (s ))
# Define xfree (p) heapfree (getprocessheap (), 0, (p ))
Void fill_icmp_data (char *, INT );
Ushort checksum (ushort *, INT );
Int decode_resp (char *, Int, struct sockaddr_in *);
Void usage (char * progname ){
Fprintf (stderr, "Usage: \ n ");
Fprintf (stderr, "% s [number of packets] [data_size] \ n", progname );
Fprintf (stderr, "datasize can be up to 1kb \ n ");
Exitprocess (status_failed );
}
Int main (INT argc, char ** argv ){
Wsadata;
Socket sockraw;
Struct sockaddr_in DEST, from;
Struct hostent * HP;
Int bread, datasize, times;
Int fromlen = sizeof (from );
Int timeout = 1000;
Int statistic = 0;/* used for Statistics */
Char * dest_ip;
Char * icmp_data;
Char * recvbuf;
Unsigned int ADDR = 0;
Ushort seq_no = 0;
If (wsastartup (makeword (2, 1), & wsadata )! = 0 ){
Fprintf (stderr, "wsastartup failed: % d \ n", getlasterror ());
Exitprocess (status_failed );
}
If (argc <2 ){
Usage (argv [0]);
}
Sockraw = wsasocket (af_inet, sock_raw, ipproto_icmp, null, 0, wsa_flag_overlapped );
//
// Note: In order to use the sending and receiving timeout settings (that is, set so_rcvtimeo, so_sndtimeo ),
// The flag must be set to wsa_flag_overlapped!
//
If (sockraw = invalid_socket ){
Fprintf (stderr, "wsasocket () failed: % d \ n", wsagetlasterror ());
Exitprocess (status_failed );
}
Bread = setsockopt (sockraw, sol_socket, so_rcvtimeo, (char *) & timeout,
Sizeof (timeout ));
If (bread = socket_error ){
Fprintf (stderr, "failed to set Recv Timeout: % d \ n", wsagetlasterror ());
Exitprocess (status_failed );
}
Timeout = 1000;
Bread = setsockopt (sockraw, sol_socket, so_sndtimeo, (char *) & timeout,
Sizeof (timeout ));
If (bread = socket_error ){
Fprintf (stderr, "failed to set send Timeout: % d \ n", wsagetlasterror ());
Exitprocess (status_failed );
}
Memset (& DEST, 0, sizeof (DEST ));
HP = gethostbyname (argv [1]);
If (! HP ){
ADDR = inet_addr (argv [1]);
}
If ((! HP) & (ADDR = inaddr_none )){
Fprintf (stderr, "unable to resolve % s \ n", argv [1]);
Exitprocess (status_failed );
}
If (HP! = NULL)
Memcpy (& (DEST. sin_addr), HP-> h_addr, HP-> h_length );
Else
DeST. sin_addr.s_addr = ADDR;
If (HP)
DeST. sin_family = hp-> h_addrtype;
Else
DeST. sin_family = af_inet;
Dest_ip = inet_ntoa (DEST. sin_addr );
//
// The prototype of the atoi function is: int atoi (const char * string );
// The return value is 0 if the input cannot be converted to an integer!
//
If (argc> 2)
{
Times = atoi (argv [2]);
If (Times = 0)
Times = def_packet_number;
}
Else
Times = def_packet_number;
If (argc> 3)
{
Datasize = atoi (argv [3]);
If (datasize = 0)
Datasize = def_packet_size;
If (datasize> 1024)/* The data packet size given by the user is too large */
{
Fprintf (stderr, "Warning: data_size is too large! \ N ");
Datasize = def_packet_size;
}
}
Else
Datasize = def_packet_size;
Datasize + = sizeof (icmpheader );
Icmp_data = (char *) xmalloc (max_packet );
Recvbuf = (char *) xmalloc (max_packet );
If (! Icmp_data ){
Fprintf (stderr, "heapalloc failed % d \ n", getlasterror ());
Exitprocess (status_failed );
}
Memset (icmp_data, 0, max_packet );
Fill_icmp_data (icmp_data, datasize );
//
// Display prompt information
//
Fprintf (stdout, "\ npinging % s... \ n", dest_ip );
For (INT I = 0; I {
Int bwrote;
(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 (sockraw, icmp_data, datasize, 0, (struct sockaddr *) & DEST, sizeof (DEST ));
If (bwrote = socket_error) {
If (wsagetlasterror () = wsaetimedout) {
printf ("request timed out. \ n ");
continue;
}< br>
fprintf (stderr," sendto failed: % d \ n ", wsagetlasterror ();
exitprocess (status_failed);
}< br>
If (bwrote fprintf (stdout, "W Rote % d bytes \ n ", bwrote);
}< br>
bread = recvfrom (sockraw, recvbuf, max_packet, 0, (struct sockaddr *) & from, & fromlen);
If (bread = socket_error) {
If (wsagetlasterror () = wsaetimedout) {
printf ("request timed out. \ n ");
continue;
}< br>
fprintf (stderr," recvfrom failed: % d \ n ", wsagetlasterror ();
exitprocess (status_failed);
}< br>
If (! Decode_resp (recvbuf, bread, & from)
statistic ++; /* Number of successfully received messages + + */
sleep (1000);
}
/*
Display the statistic result
*/
Fprintf (stdout, "\ nping statistics for % s \ n", dest_ip );
Fprintf (stdout, "packets: Sent = % d, received = % d, lost = % d (% 2.0f % loss) \ n", times,
Statistic, (times-statistic), (float) (times-statistic)/times * 100 );
Wsacleanup ();
Return 0;
}
/*
The response is an IP packet. We must decode the IP header to locate
The ICMP data
*/
Int decode_resp (char * Buf, int bytes, struct sockaddr_in * From ){
Ipheader * iphdr;
Icmpheader * icmphdr;
Unsigned short iphdrlen;
Iphdr = (ipheader *) BUF;
Iphdrlen = (iphdr-> h_len) * 4; // Number of 32-bit words * 4 = bytes
If (Bytes <iphdrlen + icmp_min ){
Printf ("too few bytes from % s \ n", inet_ntoa (from-> sin_addr ));
}
Icmphdr = (icmpheader *) (BUF + iphdrlen );
If (icmphdr-> I _type! = ICMP_ECHOREPLY ){
Fprintf (stderr, "non-echo type % d recvd \ n", icmphdr-> I _type );
Return 1;
}
If (icmphdr-> I _id! = (Ushort) getcurrentprocessid ()){
Fprintf (stderr, "someone else's packet! \ N ");
Return 1;
}
Printf ("% d bytes from % s:", bytes, inet_ntoa (from-> sin_addr ));
Printf ("icmp_seq = % d.", icmphdr-> I _seq );
Printf ("Time: % d MS", gettickcount ()-icmphdr-> timestamp );
Printf ("\ n ");
Return 0;
}
Ushort 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 & 0 xFFFF );
Cksum + = (cksum> 16 );
Return (ushort )(~ Cksum );
}
/*
Helper function to fill in various stuff in our ICMP request.
*/
Void fill_icmp_data (char * icmp_data, int datasize ){
Icmpheader * icmp_hdr;
Char * datapart;
Icmp_hdr = (icmpheader *) icmp_data;
Icmp_hdr-> I _type = ICMP_Echo;
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 );
//
// Place some junk in the buffer.
//
Memset (datapart, 'E', datasize-sizeof (icmpheader ));
}
/********************* With the following attachment: screen displayed during Ping Command Execution ***************\
* C: \ Documents and Settings \ houzhijiang> Ping 236.56.54.12 *
**
* Pinging 236.56.54.12 with 32 bytes of data :*
**
* Request timed out .*
* Request timed out .*
* Request timed out .*
* Request timed out .*
**
* Ping statistics for 236.56.54.12 :*
* Packets: Sent = 4, received = 0, lost = 4 (100% loss ),*
**
\*************************************** ******************/
/*************************************** ******************\
* C: \ Documents ents and Settings \ houzhijiang> Ping 127.0.0.1 *
**
* Pinging 127.0.0.1 with 32 bytes of data :*
**
* Reply from 127.0.0.1: bytes = 32 time <1 ms TTL = 128 *
* Reply from 127.0.0.1: bytes = 32 time <1 ms TTL = 128 *
* Reply from 127.0.0.1: bytes = 32 time <1 ms TTL = 128 *
* Reply from 127.0.0.1: bytes = 32 time <1 ms TTL = 128 *
**
* Ping statistics for 127.0.0.1 :*
* Packets: Sent = 4, stored ED = 4, lost = 0 (0% loss ),*
* Approximate round trip times in Milli-seconds :*
* Minimum = 0 ms, maximum = 0 ms, average = 0 Ms *
**
\*************************************** *****************/