#include<stdio.h>
#include<netinet/in.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<unistd.h>
#include<signal.h>
#include<arpa/inet.h>
#include<errno.h>
#include<sys/time.h>
#include<string.h>
#include<netdb.h>
#include<pthread.h>
#define MAX_SEND_NUM 64//SET MAX=64 SEND PACKETS
typedef struct packet_ping_STATUS{
struct timeval begin_time;//record the begin_time of each packets
struct timeval end_time;//record the end_time of each packet
int flag; //record wether send or not
int seq;//record the seqence of each packet
}packet_ping_STATUS;
packet_ping_STATUS packet_ping[MAX_SEND_NUM];
struct timeval start_time;//the start_time of sending
struct timeval end_time;//the end time of this program
struct timeval time_interval;//the offset of this program
int alive_flag;//whether this program is alive
int rawsock;//raw_Socket
int send_count;//the number of send packet
int recv_count;//the number of received packet
pid_t pid;//the port_num
struct sockaddr_in dest;//sockaddr_in defined in netinet/in.h,saving addr and port
//calculate the offset of time
struct timeval calculate_time_offset(struct timeval begin, struct timeval end){
struct timeval res;
res.tv_sec = end.tv_sec - begin.tv_sec;
res.tv_usec = end.tv_usec - begin.tv_usec;
if(res.tv_usec < 0){
res.tv_sec--;
res.tv_usec+=1000000;
}
return res;
}
//calculate the checksum
unsigned short calculate_checksum(unsigned short *address,int l){
int num_left = l;//the left num
int sum=0;
unsigned short *w_addr=address;
unsigned short ck_sum=0;
while(num_left>1){
sum+=*w_addr++;
num_left-=2;
}//calculate the sum
if(num_left==1){//means old bytes,then we need add 0
*((unsigned char*)&ck_sum)=*((unsigned char*)w_addr);
sum+=ck_sum;
}
sum = (sum>>16)+(sum&0xffff);
sum +=(sum>>16);
ck_sum=~sum;
return ck_sum;
}
void icmp_pack(struct icmp* icmp_header,int seq,int length){
int i=0;
icmp_header->icmp_type = ICMP_ECHO;
icmp_header->icmp_code = 0;//at this moment we ignore the icmp_code
icmp_header->icmp_cksum=0;//we must set it 0
icmp_header->icmp_seq = seq;
icmp_header->icmp_id = pid &0xffff;
for(i=0;i<length;i++){
icmp_header->icmp_data[i] = i;
}
icmp_header->icmp_cksum = calculate_checksum((unsigned short*)icmp_header,length);
}//pack the packet
int icmp_unpack(char* buf,int len){
int ipheader_len;
struct timeval begin_time,recv_time,offset_time;
double time;//round trip time;
struct ip* ip_header=(struct ip*)buf;
ipheader_len = ip_header->ip_hl*4;
struct icmp* icmp=(struct icmp*)(buf+ipheader_len);//buf+iphdr_len
len-=ipheader_len;//len is the length of icmp
if(len<8){
printf("This packet is invalid.Its length is less than 8\n");
return -1;
}//the shortest length of icmp packet is 8
//now judge whether the packet is from us or not
if((icmp->icmp_type == ICMP_ECHOREPLY)&&(icmp->icmp_id == (pid&0xffff))){
if((icmp->icmp_seq<0)||(icmp->icmp_seq>MAX_SEND_NUM)){
printf("icmp packet seq is out of range!\n");
return -1;
}
packet_ping[icmp->icmp_seq].flag = 0;
begin_time = packet_ping[icmp->icmp_seq].begin_time;
gettimeofday(&recv_time,NULL);
offset_time = calculate_time_offset(begin_time,recv_time);
time = offset_time.tv_sec*1000.0 + offset_time.tv_usec/1000.0;
printf("%d byte from: %s \nto: %s: \nicmp_seq=%u ttl=%d time=%.4f ms\n",len,inet_ntoa(ip_header->ip_src),inet_ntoa(ip_header->ip_dst),icmp->icmp_seq,ip_header->ip_ttl,time);
}
else{
printf("Invaid ICMP packet!Its id is not matched!\n");
return -1;
}
return 0;
}
void ping_send(){
char send_buf[128];
memset(send_buf,0,sizeof(send_buf));
gettimeofday(&start_time,NULL);//record the first packet
while(alive_flag){
int size=0;
gettimeofday(&(packet_ping[send_count].begin_time),NULL);
packet_ping[send_count].flag =1;//means this packet is sent
icmp_pack((struct icmp*)send_buf, send_count, 64);
size = sendto(rawsock,send_buf,64,0,(struct sockaddr*)&dest,sizeof(dest));
send_count++;
if(size<0){
printf("fail to send icmp packet!\n");
continue;
}
sleep(1);
}
}
void ping_recv(){
struct timeval tv;
tv.tv_usec = 200;
tv.tv_sec=0;
fd_set read_fd;//set fd
char recv_buf[512];
memset(recv_buf,0 ,sizeof(recv_buf));
while(alive_flag){
int ret=0;
FD_ZERO(&read_fd);//
FD_SET(rawsock,&read_fd);//
ret = select(rawsock+1,&read_fd,NULL,NULL,&tv);//select
switch(ret){
case-1:printf("fail to select!\n");break;
case 0:break;
default:
{
int size = recv(rawsock,recv_buf,sizeof(recv_buf),0);
if(size<0){
printf("fail to receive data!\n");
continue;
}
ret = icmp_unpack(recv_buf,size);
if(ret==-1)continue;
recv_count++;
}
break;
}
}
}
void icmp_sigint(int signo){
alive_flag=0;
gettimeofday(&end_time,NULL);
time_interval = calculate_time_offset(start_time,end_time);
}
void ping_final_show(){
long time = time_interval.tv_sec*1000+time_interval.tv_usec/1000;
printf("%d packes transmitted, %d recieved, %d%c packet loss,time %ldms\n",send_count,recv_count,(send_count - recv_count)*100/send_count,'%',time);
}//when the program is end
int main(int argc,char *argv[]){
int size = 128*1024;
struct protoent* protocol =NULL;
char dest_addr[80];
memset(dest_addr, 0 ,80);
unsigned int in_addr =1;
pthread_t send_id, recv_id;
if(argc<2)return -1;
protocol = getprotobyname("icmp");
if(protocol == NULL){
printf("FAIL TO getprotobyname!\n");
return -1;
}
memcpy(dest_addr,argv[1],strlen(argv[1])+1);//get the dest_addr
rawsock = socket(AF_INET,SOCK_RAW,protocol->p_proto);
if(rawsock < 0){
printf("Fail to create socket!\n");
return -1;
}
pid = getpid();
setsockopt(rawsock,SOL_SOCKET,SO_RCVBUF,&size, sizeof(size)); //enlarge the size
bzero(&dest,sizeof(dest));//zero dest
dest.sin_family=AF_INET;
in_addr = inet_addr(argv[1]);
memcpy((char*)&dest.sin_addr,&in_addr,sizeof(in_addr));
in_addr = dest.sin_addr.s_addr;
printf("Ping %s(%d.%d.%d.%d)56(84) bytes of data.\n",dest_addr,(in_addr&0x000000ff),(in_addr&0x0000ff00)>>8,(in_addr&0x00ff0000)>>16,(in_addr&0xff000000)>>24);
alive_flag=1;
signal(SIGINT,icmp_sigint);
if(pthread_create(&send_id,NULL,(void*)ping_send,NULL)){
printf("FAIL TO CREATE PING SEND THREAD!");
return -1;}//create send pthread
if(pthread_create(&recv_id,NULL,(void*)ping_recv,NULL)){
printf("FAIL to create ping recv thread!");
return -1;
}//create receive pthread
pthread_join(send_id,NULL);//send packet
pthread_join(recv_id,NULL);//receive packet
ping_final_show();
close(rawsock);
return 0;
}
评论0