|
|
#include<stdio.h>
#include<sys/types.h>
#include<sys/time.h>
#include<sys/socket.h>
#include<sys/signal.h>
#include<netdb.h>
#include<netinet/in.h>
#include<netinet/in_systm.h>
#include<netinet/ip.h>
#include<netinet/ip_icmp.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<ctype.h>
#include<string.h>
#define MSG_BUF_SIZE 256
#define HOST_BUF_SIZE 128
struct sockaddr_in dest,send_addr;
int sockfd;
int pid;
int datalen=56;
char hostname[HOST_BUF_SIZE];
char message_buf[MSG_BUF_SIZE];
int seq=0;
// some functions will be used
void handle_singal(int);
void handle_tv(struct timeval *,struct timeval *);
unsigned short check_sum(unsigned short *,int);
void handle_icmp(char *,int);
void recv_icmp(void);
void send_icmp(struct sockaddr_in);
void handle_signal(int);
void stat();
int main(int argc,char *argv[])
{
int n;
struct hostent *he;
struct sigaction action;
if(argc!=2)
{
fprintf(stderr,"USAGE:ping host!\n");
exit(1);
}
action.sa_handler=handle_signal;
sigemptyset(&action.sa_mask);
action.sa_flags=0;
// use the signal
sigaction(SIGALRM,&action,NULL);
/* when press Ctrl+c */
sigset(SIGINT,stat);
/* get pid of 'main' to set the flag of ICMP */
pid=getpid();
dest.sin_family=AF_INET;
// use inet_aton() making IP_address(argv[1]) to binary
if(inet_aton(argv[1],&dest.sin_addr)==1)
{
strcpy(hostname,argv[1]);
}
// if argv[1] is not IP_address
else
{
// get info by host_name
he=gethostbyname(argv[1]);
if(he!=NULL)
{
dest.sin_addr=*(struct in_addr *)he->h_addr[0];
strcpy(hostname,he->h_name);
exit(1);
}
else
{
fprintf(stderr,"host name error:%s%s\n",argv[1],hstrerror(h_errno));
exit(1);
}
}
printf(" ING %s(%s):\n",hostname,inet_ntoa(dest.sin_addr));
// create a socket
sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
if(sockfd<0)
{
fprintf(stderr,"socket error\n");
exit(1);
}
// set uid( get back root's right,set current's right)
setuid(getuid());
/* handle sigalrm */
handle_signal(SIGALRM);
/* receive data */
recv_icmp();
}
// handle sigalrm : call send_icmp() interval 1 second
void handle_signal(int signal)
{
send_icmp(dest);
alarm(1);
return;
}
/* when press Ctrl+C ,print the info of ping */
void stat()
{
printf("--- %s ping statistics ---\n",hostname);
exit(0);
}
// send message to host
void send_icmp(struct sockaddr_in send_addr)
{
int len;
struct icmphdr *icmp;
icmp=(struct icmphdr *)message_buf;
icmp->type=ICMP_ECHO;
icmp->code=0;
icmp->un.echo.sequence=seq++;
struct timeval *a=(struct timeval *)(icmp+1);
gettimeofday(a,NULL); //calc process time
len=datalen+8;
icmp->checksum=0;
icmp->checksum=check_sum((u_short *)icmp,len);
// use the sendto
len=sendto(sockfd,message_buf,len,0,(struct sockaddr *)&send_addr,sizeof(send_addr));
if(len<0) // if unsuccess
{
fprintf(stderr,"send to error!\n");
exit(1);
}
printf("%d bytes sendto %s!\n",len,inet_ntoa(send_addr.sin_addr));
}
// receive answer from host
void recv_icmp(void)
{
int n=0;
while(1)
{
n=recvfrom(sockfd,message_buf,sizeof(message_buf),0,NULL,NULL);
/* recive nothing */
if(n<0)
{
if(errno==EINTR) /* when alarm happing */
continue;
else
{
fprintf(stderr,"recvfrom error");
continue;
}
}
else
/* call hand_icmp() */
{handle_icmp(message_buf,n);}
}
}
// handle the ICMP data
void handle_icmp(char *ptr,int len)
{
int hlen1,icmplen;
double rtt;
struct ip *ip;
struct icmphdr *icmp;
struct timeval *tvsend;
struct timeval tvrecv;
ip=(struct ip *)ptr;
hlen1=ip->ip_hl<<2; // move right 2 bit to get IP's length
// get begin address of icmp
icmp=(struct icmphdr *)(ptr+hlen1);
// icmplen is often 8 bit
if((icmplen=len-hlen1)<8)
printf("icmplen(%d)<8",icmplen);
/* if the type is not so ,do not do anything */
if(icmp->type==ICMP_ECHOREPLY)
{
if(icmp->un.echo.id!=pid)
return;
if(icmplen<16)
printf("icmplen(%d)<16");
/* get current time */
gettimeofday(&tvrecv,NULL);
/* get time address */
tvsend=(struct timeval *)(icmp+1);
handle_tv(&tvrecv,tvsend); /* calc the interval time */
rtt=tvrecv.tv_sec*1000.0+tvrecv.tv_usec/1000.0;
printf("%d bytes from %s:seq=%u,ttl=%d,rtt=%.3fms\n",icmplen,hostname,inet_ntoa(dest.sin_addr),icmp->un.echo.sequence,ip->ip_ttl,rtt);
}
}
// process the interval time (icmp to and back time)
void handle_tv(struct timeval *out,struct timeval *in)
{
if((out->tv_usec-=in->tv_usec)<0)
{
out->tv_sec--;
out->tv_usec+=1000000;
}
out->tv_sec-=in->tv_sec;
}
unsigned short check_sum(unsigned short *addr,int len)
{
int nleft=len;
int sum=0;
unsigned short *w=addr;
unsigned short answer=0;
while(nleft>1)
{
sum+=*w++;
nleft-=2;
}
if(nleft==1)
{
*(unsigned char *)(&answer)=*(unsigned char *)w;
sum+=answer;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
answer=sum;
return(answer);
}
原代码如上,问题在于程序只执行 send_icmp(),有时执行recv_icmp(),handle_icmp()
但在handle_icmp()中只执行到 if(icmp->type==ICMP_ECHOREPLY) 就不再往下执行
在gdb下调试过,但总是不明白错在哪里?希望高手帮帮我,不甚感激! |
|