LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1639|回复: 1

ping 源代码问题(续)

[复制链接]
发表于 2005-12-5 18:43:14 | 显示全部楼层 |阅读模式
有了kj501的提醒这次重新发了代码,希望各位朋友帮我分析一下代码。
主要问题:每次只执行 send_icmp() ,有时执行 recv_icmp() ,用 gdb 跟踪
发现如执行 recv_icmp() 也执行到 /?????????/处不再往下执行。

  1. #include<stdio.h>
  2. #include<sys/types.h>
  3. #include<sys/time.h>
  4. #include<sys/socket.h>
  5. #include<sys/signal.h>
  6. #include<netdb.h>
  7. #include<netinet/in.h>
  8. #include<netinet/in_systm.h>
  9. #include<netinet/ip.h>
  10. #include<netinet/ip_icmp.h>
  11. #include<errno.h>
  12. #include<unistd.h>
  13. #include<stdlib.h>
  14. #include<ctype.h>
  15. #include<string.h>


  16. #define MSG_BUF_SIZE 256
  17. #define HOST_BUF_SIZE 128


  18. struct sockaddr_in dest,send_addr;
  19. int sockfd;
  20. int pid;
  21. int datalen=56;
  22. char hostname[HOST_BUF_SIZE];
  23. char message_buf[MSG_BUF_SIZE];
  24. int seq=0;

  25. // some functions will be used
  26. void handle_singal(int);
  27. void handle_tv(struct timeval *,struct timeval *);
  28. unsigned short check_sum(unsigned short *,int);
  29. void handle_icmp(char *,int);
  30. void recv_icmp(void);
  31. void send_icmp(struct sockaddr_in);
  32. void handle_signal(int);
  33. void stat();

  34. int main(int argc,char *argv[])
  35. {
  36.         int n;
  37.         struct hostent *he;
  38.         struct sigaction action;
  39.         if(argc!=2)
  40.         {
  41.                 fprintf(stderr,"USAGE:ping host!\n");
  42.                 exit(1);
  43.         }
  44.         action.sa_handler=handle_signal;
  45.         sigemptyset(&action.sa_mask);
  46.         action.sa_flags=0;
  47.         // use the signal
  48.         sigaction(SIGALRM,&action,NULL);

  49.         /* get pid of 'main' to set the flag of ICMP */
  50.         pid=getpid();

  51.         dest.sin_family=AF_INET;
  52.         // use inet_aton() making IP_address(argv[1]) to binary
  53.         if(inet_aton(argv[1],&dest.sin_addr)==1)
  54.         {
  55.                 strcpy(hostname,argv[1]);
  56.         }
  57.         // if argv[1] is not IP_address
  58.         else
  59.         {
  60.                 // get info by host_name
  61.                 he=gethostbyname(argv[1]);
  62.                 if(he!=NULL)
  63.                 {
  64.                         dest.sin_addr=*(struct in_addr *)he->h_addr[0];
  65.                         strcpy(hostname,he->h_name);
  66.                         exit(1);               
  67.                 }
  68.                 else
  69.                 {
  70.                         fprintf(stderr,"host name error:%s%s\n",argv[1],hstrerror(h_errno));
  71.                         exit(1);
  72.                 }
  73.         }
  74.         printf("PING %s(%s):\n",hostname,inet_ntoa(dest.sin_addr));
  75.        
  76.         // create a socket
  77.         sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
  78.         if(sockfd<0)
  79.         {
  80.                 fprintf(stderr,"socket error\n");
  81.                 exit(1);
  82.         }

  83.         // set uid( get back root's right,set current's right)
  84.         setuid(getuid());
  85.         /* handle sigalrm */
  86.         handle_signal(SIGALRM);
  87.         /* receive data */
  88.         recv_icmp();
  89. }

  90. // handle sigalrm : call send_icmp() interval 1 second
  91. void handle_signal(int signal)
  92. {
  93.         send_icmp(dest);
  94.         arlarm(1);
  95.         return;
  96. }


  97. // send message to host
  98. void send_icmp(struct sockaddr_in send_addr)
  99. {
  100.         int len;
  101.         struct icmphdr *icmp;
  102.         icmp=(struct icmphdr *)message_buf;
  103.         icmp->type=ICMP_ECHO;
  104.         icmp->code=0;
  105.         icmp->un.echo.sequence=seq++;

  106.         /* ?????? */
  107.         struct timeval *a=(struct timeval *)(icmp+1);
  108.         gettimeofday(a,NULL);                //calc process time

  109.         len=datalen+8;
  110.         icmp->checksum=0;
  111.         icmp->checksum=check_sum((u_short *)icmp,len);

  112.         // use the sendto
  113.         len=sendto(sockfd,message_buf,len,0,(struct sockaddr *)&send_addr,sizeof(send_addr));
  114.        
  115.         if(len<0)        // if unsuccess
  116.         {
  117.                 fprintf(stderr,"send to error!\n");
  118.                 exit(1);
  119.         }
  120.         printf("%d bytes sendto %s!\n",len,inet_ntoa(send_addr.sin_addr));
  121. }


  122. // receive answer from host
  123. void recv_icmp(void)
  124. {
  125.         int n=0;
  126.         while(1)
  127.         {
  128.                 n=recvfrom(sockfd,message_buf,sizeof(message_buf),0,NULL,NULL);
  129.                
  130.                 /* recive nothing */
  131.                 if(n<0)
  132.                 {
  133.                         if(errno==EINTR)       
  134.                                 continue;
  135.                         else
  136.                         {
  137.                                 fprintf(stderr,"recvfrom error");
  138.                                 continue;
  139.                         }
  140.                 }

  141.                 else       
  142.                  /* call hand_icmp() */
  143.                 {handle_icmp(message_buf,n);}
  144.         }
  145. }

  146. // handle the ICMP data
  147. void handle_icmp(char *ptr,int len)
  148. {
  149.         int hlen1,icmplen;
  150.         double rtt;
  151.         struct ip *ip;
  152.         struct icmphdr *icmp;
  153.         struct timeval *tvsend;
  154.         struct timeval tvrecv;
  155.        
  156.         ip=(struct ip *)ptr;
  157.         hlen1=ip->ip_hl<<2;        // move right 2 bit to get IP's length

  158.         // why! try to understand
  159.        
  160.         // get begin address of icmp
  161.         icmp=(struct icmphdr *)(ptr+hlen1);       
  162.       
  163.         // icmplen is often 8 bit
  164.         if((icmplen=len-hlen1)<8)
  165.                 printf("icmplen(%d)<8",icmplen);

  166.         /* if the type is not so ,do not do anything */
  167.         /* ICMP_ECHORELY :xiangying -- yingdai */
  168.         if(icmp->type==ICMP_ECHOREPLY)
  169.         {
  170.                 if(icmp->un.echo.id!=pid)     /??????????/ 到这就不往下执行了
  171.                         return;
  172.                 if(icmplen<16)
  173.                         printf("icmplen(%d)<16");

  174.                 /* get current time */
  175.                 gettimeofday(&tvrecv,NULL);
  176.                 /* get time address */
  177.                 tvsend=(struct timeval *)(icmp+1);       
  178.                                                                                 
  179.                 handle_tv(&tvrecv,tvsend);        /* calc the interval time */
  180.                                                                                 
  181.                 rtt=tvrecv.tv_sec*1000.0+tvrecv.tv_usec/1000.0;
  182.                 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);
  183.         }
  184. }

  185. // process the interval time (icmp to and back time)
  186. void handle_tv(struct timeval *out,struct timeval *in)
  187. {
  188.         if((out->tv_usec-=in->tv_usec)<0)
  189.         {
  190.                 out->tv_sec--;
  191.                 out->tv_usec+=1000000;
  192.         }
  193.         out->tv_sec-=in->tv_sec;
  194. }
  195.                                                                                 
  196.                                                                                 
  197. unsigned short check_sum(unsigned short *addr,int len)
  198. {
  199.         int nleft=len;
  200.         int sum=0;
  201.         unsigned short *w=addr;
  202.         unsigned short answer=0;
  203.         while(nleft>1)
  204.         {
  205.                 sum+=*w++;
  206.                 nleft-=2;
  207.         }
  208.         if(nleft==1)
  209.         {
  210.                 *(unsigned char *)(&answer)=*(unsigned char *)w;
  211.                 sum+=answer;
  212.         }
  213.         sum=(sum>>16)+(sum&0xffff);
  214.         sum+=(sum>>16);
  215.         answer=sum;
  216.         return(answer);
  217. }
复制代码
 楼主| 发表于 2005-12-5 18:48:35 | 显示全部楼层
代码可能太长,我将我认为出问题的部分截下,这样可能更方便

  1. int main(int argc,char *argv[])
  2. {
  3. ......
  4.         /* handle sigalrm */
  5.         handle_signal(SIGALRM);
  6.         /* receive data */
  7.         recv_icmp();
  8. }

  9. // handle sigalrm : call send_icmp() interval 1 second
  10. void handle_signal(int signal)
  11. {
  12.         send_icmp(dest);
  13.         arlarm(1);
  14.         return;
  15. }


  16. // receive answer from host
  17. void recv_icmp(void)
  18. {
  19.         int n=0;
  20.         while(1)
  21.         {
  22.                 n=recvfrom(sockfd,message_buf,sizeof(message_buf),0,NULL,NULL);
  23.                
  24.                 /* recive nothing */
  25.                 if(n<0)
  26.                 {
  27.                         if(errno==EINTR)       
  28.                                 continue;
  29.                         else
  30.                         {
  31.                                 fprintf(stderr,"recvfrom error");
  32.                                 continue;
  33.                         }
  34.                 }

  35.                 else       
  36.                  /* call hand_icmp() */
  37.                 {handle_icmp(message_buf,n);}
  38.         }
  39. }

  40. // handle the ICMP data
  41. void handle_icmp(char *ptr,int len)
  42. {
  43.         int hlen1,icmplen;
  44.         double rtt;
  45.         struct ip *ip;
  46.         struct icmphdr *icmp;
  47.         struct timeval *tvsend;
  48.         struct timeval tvrecv;
  49.        
  50.         ip=(struct ip *)ptr;
  51.         hlen1=ip->ip_hl<<2;        // move right 2 bit to get IP's length

  52.         // why! try to understand
  53.        
  54.         // get begin address of icmp
  55.         icmp=(struct icmphdr *)(ptr+hlen1);       
  56.       
  57.         // icmplen is often 8 bit
  58.         if((icmplen=len-hlen1)<8)
  59.                 printf("icmplen(%d)<8",icmplen);

  60.         /* if the type is not so ,do not do anything */
  61.         /* ICMP_ECHORELY :xiangying -- yingdai */
  62.         if(icmp->type==ICMP_ECHOREPLY)
  63.         {
  64.                 if(icmp->un.echo.id!=pid)
  65.                         return;
  66.                 if(icmplen<16)
  67.                         printf("icmplen(%d)<16");

  68.                 /* get current time */
  69.                 gettimeofday(&tvrecv,NULL);
  70.                 /* get time address */
  71.                 tvsend=(struct timeval *)(icmp+1);       
  72.                                                                                 
  73.                 handle_tv(&tvrecv,tvsend);        /* calc the interval time */
  74.                                                                                 
  75.                 rtt=tvrecv.tv_sec*1000.0+tvrecv.tv_usec/1000.0;
  76.                 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);
  77.         }
  78. }
  79. ......
  80. ......
复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表