LinuxSir.cn,穿越时空的Linuxsir!

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

ping的原代码问题

[复制链接]
发表于 2005-12-4 18:25:36 | 显示全部楼层 |阅读模式
#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下调试过,但总是不明白错在哪里?希望高手帮帮我,不甚感激!
 楼主| 发表于 2005-12-4 18:51:32 | 显示全部楼层
int main(int argc,char *argv[])
{
        ......
        /* handle sigalrm */
        handle_signal(SIGALRM);
        /* receive data */
        recv_icmp();
}

// 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 sigalrm : call send_icmp() interval 1 second
void handle_signal(int signal)
{
        send_icmp(dest);
        alarm(1);       //每隔一秒调用handle_signal()
        return;
}



// 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);
        }
}

以上为我认为出错的地方,各位一定要帮忙!
回复 支持 反对

使用道具 举报

发表于 2005-12-4 23:04:58 | 显示全部楼层
代码没有缩进,让人怎么看?!
先把格式改过来再说吧。具体方法可以看看置顶的贴子
回复 支持 反对

使用道具 举报

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

本版积分规则

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