|
| 1 | + |
| 2 | + |
| 3 | +#include <arpa/inet.h> //for using the in_addr data structure |
| 4 | +#include <sys/types.h> //for using process ids, clock ticks, etc |
| 5 | +#include <sys/param.h> |
| 6 | +#include <sys/socket.h> //for making socket connections |
| 7 | +#include <sys/file.h> //for file manipulation constants |
| 8 | +#include <sys/time.h> //for using clock related operations |
| 9 | +#include <netinet/in_systm.h> //for using sockaddr_in and in_addr structure |
| 10 | +#include <netinet/in.h> //for using in_port_t and in_addr_t structures |
| 11 | +#include <netinet/ip.h> // |
| 12 | +#include <netinet/ip_icmp.h> |
| 13 | +#include <netdb.h> |
| 14 | +#include <unistd.h> |
| 15 | +#include <stdio.h> |
| 16 | +#include <ctype.h> //useful for testing and mapping characters |
| 17 | +#include <string.h> |
| 18 | +#include <stdlib.h> |
| 19 | +#include <stdint.h> |
| 20 | +#include <iostream> |
| 21 | + |
| 22 | +using namespace std; |
| 23 | + |
| 24 | +uint16_t in_cksum(uint16_t *addr, unsigned len); //function to do check sum calculation for error checking |
| 25 | + |
| 26 | +#define DEFDATALEN (64-ICMP_MINLEN) /* default data length */ |
| 27 | +#define MAXIPLEN 60 |
| 28 | +#define MAXICMPLEN 76 |
| 29 | +#define MAXPACKET (65536 - 60 - ICMP_MINLEN)/* max packet size */ |
| 30 | + |
| 31 | +int ping(string target) |
| 32 | +{ |
| 33 | + |
| 34 | + int s, i, cc, packlen, datalen = DEFDATALEN; //setting the data length here |
| 35 | + struct hostent *hp; //used to store information about a specific host |
| 36 | + struct sockaddr_in to, from; //to specify a transport address and port for the AF_INET address family |
| 37 | + //AF_INET is the address family which specifies the addresses the socket can communicate with |
| 38 | + struct ip *ip; |
| 39 | + u_char *packet, outpack[MAXPACKET]; |
| 40 | + char hnamebuf[MAXHOSTNAMELEN]; |
| 41 | + string hostname; |
| 42 | + struct icmp *icp; |
| 43 | + int ret, fromlen, hlen; |
| 44 | + fd_set rfds; |
| 45 | + struct timeval tv; |
| 46 | + int retval; |
| 47 | + struct timeval start, end; |
| 48 | + int /*start_t, */end_t; |
| 49 | + bool cont = true; |
| 50 | + |
| 51 | + to.sin_family = AF_INET; |
| 52 | + |
| 53 | + // try to convert as dotted decimal address, else we will assume its a hostname |
| 54 | + to.sin_addr.s_addr = inet_addr(target.c_str()); |
| 55 | + if (to.sin_addr.s_addr != (u_int)-1) |
| 56 | + hostname = target; |
| 57 | + else |
| 58 | + { |
| 59 | + hp = gethostbyname(target.c_str()); |
| 60 | + if (!hp) |
| 61 | + { |
| 62 | + cerr << "unknown host "<< target << endl; |
| 63 | + return -1; |
| 64 | + } |
| 65 | + to.sin_family = hp->h_addrtype; |
| 66 | + bcopy(hp->h_addr, (caddr_t)&to.sin_addr, hp->h_length); |
| 67 | + strncpy(hnamebuf, hp->h_name, sizeof(hnamebuf) - 1); |
| 68 | + hostname = hnamebuf; |
| 69 | + } |
| 70 | + packlen = datalen + MAXIPLEN + MAXICMPLEN; |
| 71 | + if ( (packet = (u_char *)malloc((u_int)packlen)) == NULL) |
| 72 | + { |
| 73 | + cerr << "malloc error\n"; |
| 74 | + return -1; |
| 75 | + } |
| 76 | + |
| 77 | + |
| 78 | + if ( (s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) //creating a socket and storing the descriptor in s |
| 79 | + //domain = IPv4 protocol |
| 80 | + //communication type = SOCK_RAW |
| 81 | + //protocol = Internet Control Message Protocol |
| 82 | + { |
| 83 | + perror("socket"); /* probably not running as superuser */ |
| 84 | + return -1; |
| 85 | + } |
| 86 | + |
| 87 | + icp = (struct icmp *)outpack; |
| 88 | + icp->icmp_type = ICMP_ECHO; |
| 89 | + icp->icmp_code = 0; |
| 90 | + icp->icmp_cksum = 0; |
| 91 | + icp->icmp_seq = 12345; /* seq and id must be reflected */ |
| 92 | + icp->icmp_id = getpid(); |
| 93 | + |
| 94 | + |
| 95 | + cc = datalen + ICMP_MINLEN; |
| 96 | + icp->icmp_cksum = in_cksum((unsigned short *)icp,cc); |
| 97 | + |
| 98 | + gettimeofday(&start, NULL); |
| 99 | + |
| 100 | + i = sendto(s, (char *)outpack, cc, 0, (struct sockaddr*)&to, (socklen_t)sizeof(struct sockaddr_in)); |
| 101 | + if (i < 0 || i != cc) |
| 102 | + { |
| 103 | + if (i < 0) |
| 104 | + perror("sendto error"); |
| 105 | + cout << "wrote " << hostname << " " << cc << " chars, ret= " << i << endl; |
| 106 | + } |
| 107 | + |
| 108 | + //clear the fdset |
| 109 | + FD_ZERO(&rfds); |
| 110 | + //add socket descriptor to the fdset |
| 111 | + FD_SET(s, &rfds); |
| 112 | + //Wait up to one seconds. |
| 113 | + tv.tv_sec = 1; |
| 114 | + tv.tv_usec = 0; |
| 115 | + |
| 116 | + while(cont) //busy waiting |
| 117 | + { |
| 118 | + retval = select(s+1, &rfds, NULL, NULL, &tv); |
| 119 | + if (retval == -1) |
| 120 | + { |
| 121 | + perror("select()"); |
| 122 | + return -1; |
| 123 | + } |
| 124 | + else if (retval) |
| 125 | + { |
| 126 | + fromlen = sizeof(sockaddr_in); |
| 127 | + if ( (ret = recvfrom(s, (char *)packet, packlen, 0,(struct sockaddr *)&from, (socklen_t*)&fromlen)) < 0) |
| 128 | + { |
| 129 | + perror("recvfrom error"); |
| 130 | + return -1; |
| 131 | + } |
| 132 | + |
| 133 | + // Check the IP header |
| 134 | + ip = (struct ip *)((char*)packet); |
| 135 | + hlen = sizeof( struct ip ); |
| 136 | + if (ret < (hlen + ICMP_MINLEN)) |
| 137 | + { |
| 138 | + cerr << "packet too short (" << ret << " bytes) from " << hostname << endl;; |
| 139 | + return -1; |
| 140 | + } |
| 141 | + |
| 142 | + // Now the ICMP part |
| 143 | + icp = (struct icmp *)(packet + hlen); |
| 144 | + if (icp->icmp_type == ICMP_ECHOREPLY) |
| 145 | + { |
| 146 | + cout << "Echo reply"<< endl; |
| 147 | + if (icp->icmp_seq != 12345) |
| 148 | + { |
| 149 | + cout << "received sequence # " << icp->icmp_seq << endl; |
| 150 | + continue; |
| 151 | + } |
| 152 | + if (icp->icmp_id != getpid()) |
| 153 | + { |
| 154 | + cout << "received id " << icp->icmp_id << endl; |
| 155 | + continue; |
| 156 | + } |
| 157 | + cont = false; |
| 158 | + } |
| 159 | + else |
| 160 | + { |
| 161 | + cout << "Recv: not an echo reply" << endl; |
| 162 | + continue; |
| 163 | + } |
| 164 | + |
| 165 | + gettimeofday(&end, NULL); |
| 166 | + end_t = 1000000*(end.tv_sec - start.tv_sec) + (end.tv_usec - start.tv_usec); |
| 167 | + |
| 168 | + if(end_t < 1) |
| 169 | + end_t = 1; |
| 170 | + |
| 171 | + cout << "Elapsed time = " << end_t << " usec" << endl; |
| 172 | + return end_t; |
| 173 | + } |
| 174 | + else |
| 175 | + { |
| 176 | + cout << "No data within one seconds.\n"; |
| 177 | + return 0; |
| 178 | + } |
| 179 | + } |
| 180 | + return 0; |
| 181 | +} |
| 182 | + |
| 183 | +uint16_t in_cksum(uint16_t *addr, unsigned len) |
| 184 | +{ |
| 185 | + uint16_t answer = 0; |
| 186 | + /* |
| 187 | + * Using a 32 bit accumulator (sum), we add sequential 16 bit words and at the end, fold back all the |
| 188 | + * carry bits from the top 16 bits into the lower 16 bits. |
| 189 | + */ |
| 190 | + uint32_t sum = 0; |
| 191 | + while (len > 1) { |
| 192 | + sum += *addr++; |
| 193 | + len -= 2; |
| 194 | + } |
| 195 | + |
| 196 | + // mop up an odd byte, if necessary |
| 197 | + if (len == 1) { |
| 198 | + *(unsigned char *)&answer = *(unsigned char *)addr ; |
| 199 | + sum += answer; |
| 200 | + } |
| 201 | + |
| 202 | + // add back carry outs from top 16 bits to low 16 bits |
| 203 | + sum = (sum >> 16) + (sum & 0xffff); // add high 16 to low 16 |
| 204 | + sum += (sum >> 16); // add carry |
| 205 | + answer = ~sum; // truncate to 16 bits |
| 206 | + return answer; |
| 207 | +} |
| 208 | + |
| 209 | +int main(int argc, char** argv) |
| 210 | +{ |
| 211 | + if (argc != 2) |
| 212 | + { |
| 213 | + cout << "Type the hostname" << endl; |
| 214 | + exit(1); |
| 215 | + } |
| 216 | + cout << "ping returned " << ping(argv[1]) << endl; |
| 217 | + return 0; |
| 218 | +} |
0 commit comments