人到中年有点甜
#include <os.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define ICMP_ECHO 8 #define ICMP_ECHOREPLY 0 #define ICMP_MIN 8 // Minimum 8 byte icmp packet (just header) // // ICMP header //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 source_ip; unsigned int dest_ip; };// // ICMP header //struct icmphdr { unsigned char i_type; unsigned char i_code; // type sub codeunsigned short i_cksum; unsigned short i_id; unsigned short i_seq; // This is not the std header, but we reserve space for timeunsigned long timestamp; }; struct pingstat{int tmin;int tmax;int tsum;int ntransmitted;int nreceived;};#define DEF_PACKET_SIZE 32 #define MAX_PACKET 1024 #define PKTSIZ (sizeof(struct icmphdr) + MAX_PACKET)void fill_icmp_data(char *icmp_data, int datasize);unsigned short checksum(unsigned short *buffer, int size); void decode_resp(char *buf, int bytes, struct sockaddr_in *from, struct pingstat *stat);int cmd_ping(int argc, char *argv[]){ int sockraw; struct sockaddr_in dest, from; struct hostent *hp; int bread, datasize, rc; int fromlen = sizeof(from); int timeout = 1000; char *dest_ip; char icmp_data[PKTSIZ]; char recvbuf[PKTSIZ];unsigned int addr = 0; unsigned short seq_no = 0; int numpackets;char *hostname;struct pingstat stat;if (argc < 2) {fprintf(stderr, "usage: %s <host> [data_size]\n", argv[0]); return 0;}hostname = argv[1];memset(&dest, 0, sizeof(dest)); hp = gethostbyname(hostname);if (!hp) addr = inet_addr(hostname); if (!hp && addr == INADDR_NONE){fprintf(stderr, "%s: unknown host %s\n", argv[0], hostname);return 1; } 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 = (unsigned char) hp->h_addrtype; else dest.sin_family = AF_INET; dest.sin_port = htons(53);dest_ip = inet_ntoa(dest.sin_addr); if (argc > 2){ datasize = atoi(argv[2]); if (datasize == 0) datasize = DEF_PACKET_SIZE; }else datasize = DEF_PACKET_SIZE; if (datasize + sizeof(struct icmphdr) > PKTSIZ){ fprintf(stderr, "%s: packet size too large\n", argv[0]); return 1; } sockraw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sockraw < 0) {perror("ping: socket");return 1; } rc = setsockopt(sockraw, SOL_SOCKET, SO_RCVTIMEO, (char *) &timeout, sizeof(timeout)); if (rc < 0) { perror("ping: recv timeout");return 1; } timeout = 1000; rc = setsockopt(sockraw, SOL_SOCKET, SO_SNDTIMEO, (char *) &timeout, sizeof(timeout)); if(rc < 0) { perror("ping: send timeout");return 1; }stat.tmin = 999999999;stat.tmax = 0;stat.tsum = 0;stat.ntransmitted = 0;stat.nreceived = 0;memset(icmp_data, 0, MAX_PACKET); fill_icmp_data(icmp_data, datasize + sizeof(struct icmphdr));if (dest.sin_family == AF_INET) printf("PING %s (%s): %d data bytes\n", hostname, inet_ntoa(dest.sin_addr), datasize);elseprintf("PING %s: %d data bytes\n", hostname, datasize);printf("\n");for (numpackets = 0; numpackets < 5; numpackets++){ int bwrote;struct icmphdr *icmphdr = (struct icmphdr *) &icmp_data;msleep(100);icmphdr->i_cksum = 0; icmphdr->timestamp = clock(); icmphdr->i_seq = seq_no++; icmphdr->i_cksum = checksum((unsigned short *) icmp_data, datasize + sizeof(struct icmphdr));bwrote = sendto(sockraw, icmp_data, datasize + sizeof(struct icmphdr), 0, (struct sockaddr *) &dest, sizeof(dest)); if (bwrote < 0){ if (errno == ETIMEDOUT){printf("timed out\n"); continue; } perror("ping: sendto"); return 1; }if (bwrote < datasize){fprintf(stdout, "Wrote %d bytes\n", bwrote); }fflush(stdout);stat.ntransmitted++;bread = recvfrom(sockraw ,recvbuf, MAX_PACKET, 0, (struct sockaddr *) &from, &fromlen); if (bread < 0){ if (errno == ETIMEDOUT){printf("timed out\n"); continue; } perror("ping: recvfrom"); return 1; }decode_resp(recvbuf, bread, &from, &stat); msleep(1000); } printf("----%s PING Statistics----\n", hostname);printf("%d packets transmitted, ", stat.ntransmitted);printf("%d packets received, ", stat.nreceived);if (stat.ntransmitted){if (stat.nreceived > stat.ntransmitted)printf("-- somebody's printing up packets!");elseprintf("%d%% packet loss", (int) (((stat.ntransmitted - stat.nreceived) * 100) / stat.ntransmitted));printf("\n");}if (stat.nreceived){printf("round-trip (ms) min/avg/max = %d/%d/%d\n", stat.tmin, stat.tsum / stat.nreceived, stat.tmax);}close(sockraw);return 0; } void decode_resp(char *buf, int bytes, struct sockaddr_in *from, struct pingstat *stat) { struct iphdr *iphdr; struct icmphdr *icmphdr; unsigned short iphdrlen; int triptime;iphdr = (struct iphdr *) 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)); return;} icmphdr = (struct icmphdr *) (buf + iphdrlen); if (icmphdr->i_type != ICMP_ECHOREPLY) { fprintf(stderr, "non-echo type %d recvd\n", icmphdr->i_type); return; } if (icmphdr->i_id != (unsigned short) gettid()) { fprintf(stderr, "someone else's packet!\n"); return; } triptime = clock() - icmphdr->timestamp;stat->tsum += triptime;if (triptime < stat->tmin) stat->tmin = triptime;if (triptime > stat->tmax) stat->tmax = triptime;stat->nreceived++;bytes -= iphdrlen + sizeof(struct icmphdr);printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr)); printf(" icmp_seq=%d", icmphdr->i_seq); printf(" time=%d ms", triptime); printf(" TTL=%d", iphdr->ttl); printf("\n"); } unsigned short checksum(unsigned short *buffer, int size) { unsigned long cksum = 0; while (size > 1){ cksum += *buffer++; size -= sizeof(unsigned short); } if (size) cksum += *(unsigned char *) buffer; cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >> 16); return (unsigned short) (~cksum); } void fill_icmp_data(char *icmp_data, int datasize){ struct icmphdr *icmp_hdr; char *datapart; icmp_hdr = (struct icmphdr *) icmp_data; icmp_hdr->i_type = ICMP_ECHO; icmp_hdr->i_code = 0; icmp_hdr->i_id = (unsigned short) gettid(); icmp_hdr->i_cksum = 0; icmp_hdr->i_seq = 0; datapart = icmp_data + sizeof(struct icmphdr); memset(datapart, 'E', datasize - sizeof(struct icmphdr));