zoukankan      html  css  js  c++  java
  • Ping

    #include"unp.h"
    #include<netinet/in_systm.h>
    #include<netinet/ip.h>
    #include<netinet/ip_icmp.h>
    #define BUFSIZE 1500
    /*Globals*/
    char sendbuf[BUFSIZE];
    int datalen;
    char *host;
    int nsent; /* add 1 for each sendto() */
    pid_t pid; /* out PID */
    int sockfd;
    int verbose;
    /* function prototype */
    void init_v6(void);
    void proc_v4(char * ,ssize_t,struct msghdr *,struct timeval *);
    void proc_v6(char *, ssize_t,struct msghdr *,struct timeval *);
    void send_v4(void);
    void send_v6(void);
    void readloop(void);
    void sig_alam(int);
    void tv_sub(struct timeval *,struct timeval *);

    struct proto
    {
     void (*fproc)(char *,ssize_t,struct msghdr *,struct timeval *);
     void (*fsend)(void);
     void (*finit)(void);
     struct sockaddr *sasend; /* sockaddr() for send,from getaddrinfo */
     struct sockaddr *sarecv; /* sockaddr() for receving */
     socklen_t salen;  /* length of sockaddr()s*/
     int icmpproto;   /* IPPROTO_XXX value for ICMP */
     
    }*pr;
    #ifdef IPV6

    #include<netinet/ip6.h>
    #include<netinet/icmp6.h>

    #endif

    #define _GNU_SOURCE
    #include <sys/time.h>
    #include <sys/un.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <signal.h>
    #include <stdarg.h>
    #include <syslog.h>
    #include <errno.h>
    #include <netinet/in_systm.h>
    #include <netinet/ip.h>
    #include <netinet/ip_icmp.h>
    #include <sys/types.h>
    #include <time.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/ip6.h>
    #include <netinet/icmp6.h>

    #define BUFSIZE  1500
    //#define IPV6
    /* globals */
    char sendbuf[BUFSIZE];

    int datalen;   /* # bytes of data following ICMP header */
    char *host;
    int nsent;   /* add 1 for each sendto() */
    pid_t pid;   /* our PID */
    int sockfd;
    int verbose;

    struct proto {
     void (*fproc) (char *, ssize_t, struct msghdr *, struct timeval *);
     void (*fsend) (void);
     void (*finit) (void);
     struct sockaddr *sasend; /* sockaddr{} for send, from getaddrinfo */
     struct sockaddr *sarecv; /* sockaddr{} for receiving */
     socklen_t salen; /* length of sockaddr{}s */
     int icmpproto;  /* IPPROTO_xxx value for ICMP */
    } *pr;

    #define MAXLINE  4096 /* max text line length */
    int daemon_proc;  /* set nonzero by daemon_init() */
    void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
    {
     int errno_save, n;
     char buf[MAXLINE + 1];

     errno_save = errno; /* value caller might want printed */
    #ifdef HAVE_VSNPRINTF
     vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
    #else
     vsprintf(buf, fmt, ap); /* not safe */
    #endif
     n = strlen(buf);
     if (errnoflag)
      snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
     strcat(buf, " ");

     if (daemon_proc) {
      syslog(level, "%s", buf);
     } else {
      fflush(stdout); /* in case stdout and stderr are the same */
      fputs(buf, stderr);
      fflush(stderr);
     }
     return;
    }

    void err_quit(const char *fmt, ...)
    {
     va_list ap;

     va_start(ap, fmt);
     err_doit(0, LOG_ERR, fmt, ap);
     va_end(ap);
     exit(1);
    }

    void err_sys(const char *fmt, ...)
    {
     va_list ap;

     va_start(ap, fmt);
     err_doit(1, LOG_ERR, fmt, ap);
     va_end(ap);
     exit(1);
    }

    char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
    {
     static char str[128]; /* Unix domain is largest */

     switch (sa->sa_family) {
     case AF_INET:{
       struct sockaddr_in *sin = (struct sockaddr_in *)sa;

       if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
           == NULL)
        return (NULL);
       return (str);
      }

    #ifdef IPV6
     case AF_INET6:{
       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;

       if (inet_ntop
           (AF_INET6, &sin6->sin6_addr, str,
            sizeof(str)) == NULL)
        return (NULL);
       return (str);
      }
    #endif

    #ifdef AF_UNIX
     case AF_UNIX:{
       struct sockaddr_un *unp = (struct sockaddr_un *)sa;

       /* OK to have no pathname bound to the socket: happens on
          every connect() unless client calls bind() first. */
       if (unp->sun_path[0] == 0)
        strcpy(str, "(no pathname bound)");
       else
        snprintf(str, sizeof(str), "%s", unp->sun_path);
       return (str);
      }
    #endif

    #ifdef HAVE_SOCKADDR_DL_STRUCT
     case AF_LINK:{
       struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;

       if (sdl->sdl_nlen > 0)
        snprintf(str, sizeof(str), "%*s",
          sdl->sdl_nlen, &sdl->sdl_data[0]);
       else
        snprintf(str, sizeof(str), "AF_LINK, index=%d",
          sdl->sdl_index);
       return (str);
      }
    #endif
     default:
      snprintf(str, sizeof(str),
        "sock_ntop_host: unknown AF_xxx: %d, len %d",
        sa->sa_family, salen);
      return (str);
     }
     return (NULL);
    }

    char *Sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
    {
     char *ptr;

     if ((ptr = sock_ntop_host(sa, salen)) == NULL)
      err_sys("sock_ntop_host error"); /* inet_ntop() sets errno */
     return (ptr);
    }

    void tv_sub(struct timeval *out, struct timeval *in)
    {
     if ((out->tv_usec -= in->tv_usec) < 0) { /* out -= in */
      --out->tv_sec;
      out->tv_usec += 1000000;
     }
     out->tv_sec -= in->tv_sec;
    }

    void proc_v4(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
    {
     int hlen1, icmplen;
     double rtt;
     struct ip *ip;
     struct icmp *icmp;
     struct timeval *tvsend;

     ip = (struct ip *)ptr; /* start of IP header */
     hlen1 = ip->ip_hl << 2; /* length of IP header */
     if (ip->ip_p != IPPROTO_ICMP)
      return;  /* not ICMP */

     icmp = (struct icmp *)(ptr + hlen1); /* start of ICMP header */
     if ((icmplen = len - hlen1) < 8)
      return;  /* malformed packet */

     if (icmp->icmp_type == ICMP_ECHOREPLY) {
      if (icmp->icmp_id != pid)
       return; /* not a response to our ECHO_REQUEST */
      if (icmplen < 16)
       return; /* not enough data to use */

      tvsend = (struct timeval *)icmp->icmp_data;
      tv_sub(tvrecv, tvsend);
      rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;

      printf("%d bytes from %s: seq=%u, ttl=%d, rtt=%.3f ms ",
             icmplen, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp->icmp_seq, ip->ip_ttl, rtt);

     } else if (verbose) {
      printf("  %d bytes from %s: type = %d, code = %d ",
             icmplen, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp->icmp_type, icmp->icmp_code);
     }
    }

    void Gettimeofday(struct timeval *tv, void *foo)
    {
     if (gettimeofday(tv, foo) == -1)
      err_sys("gettimeofday error");
     return;
    }

    uint16_t in_cksum(uint16_t * addr, int len)
    {
     int nleft = len;
     uint32_t sum = 0;
     uint16_t *w = addr;
     uint16_t answer = 0;

     /*
      * Our algorithm is simple, using a 32 bit accumulator (sum), we add
      * sequential 16 bit words to it, and at the end, fold back all the
      * carry bits from the top 16 bits into the lower 16 bits.
      */
     while (nleft > 1) {
      sum += *w++;
      nleft -= 2;
     }

     /* 4mop up an odd byte, if necessary */
     if (nleft == 1) {
      *(unsigned char *)(&answer) = *(unsigned char *)w;
      sum += answer;
     }

     /* 4add back carry outs from top 16 bits to low 16 bits */
     sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
     sum += (sum >> 16); /* add carry */
     answer = ~sum;  /* truncate to 16 bits */
     return (answer);
    }

    void
    Sendto(int fd, const void *ptr, size_t nbytes, int flags,
           const struct sockaddr *sa, socklen_t salen)
    {
     if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)
      err_sys("sendto error");
    }

    void send_v4(void)
    {
     int len;
     struct icmp *icmp;

     icmp = (struct icmp *)sendbuf;
     icmp->icmp_type = ICMP_ECHO;
     icmp->icmp_code = 0;
     icmp->icmp_id = pid;
     icmp->icmp_seq = nsent++;
     memset(icmp->icmp_data, 0xa5, datalen); /* fill with pattern */
     Gettimeofday((struct timeval *)icmp->icmp_data, NULL);

     len = 8 + datalen; /* checksum ICMP header and data */
     icmp->icmp_cksum = 0;
     icmp->icmp_cksum = in_cksum((u_short *) icmp, len);

     Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
    }

    int datalen = 56;  /* data that goes with ICMP echo request */

    typedef void Sigfunc(int); /* for signal handlers */
    Sigfunc *signal(int signo, Sigfunc * func)
    {
     struct sigaction act, oact;

     act.sa_handler = func;
     sigemptyset(&act.sa_mask);
     act.sa_flags = 0;
     if (signo == SIGALRM) {
    #ifdef SA_INTERRUPT
      act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
    #endif
     } else {
    #ifdef SA_RESTART
      act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
    #endif
     }
     if (sigaction(signo, &act, &oact) < 0)
      return (SIG_ERR);
     return (oact.sa_handler);
    }

    Sigfunc *Signal(int signo, Sigfunc * func)
    {    /* for our signal() function */
     Sigfunc *sigfunc;

     if ((sigfunc = signal(signo, func)) == SIG_ERR)
      err_sys("signal error");
     return (sigfunc);
    }

    struct addrinfo *Host_serv(const char *host, const char *serv, int family,
          int socktype)
    {
     int n;
     struct addrinfo hints, *res;

     bzero(&hints, sizeof(struct addrinfo));
     hints.ai_flags = AI_CANONNAME; /* always return canonical name */
     hints.ai_family = family; /* 0, AF_INET, AF_INET6, etc. */
     hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */

     if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
      err_quit("host_serv error for %s, %s: %s",
        (host == NULL) ? "(no hostname)" : host,
        (serv == NULL) ? "(no service name)" : serv,
        gai_strerror(n));

     return (res);  /* return pointer to first on linked list */
    }

    void *Calloc(size_t n, size_t size)
    {
     void *ptr;

     if ((ptr = calloc(n, size)) == NULL)
      err_sys("calloc error");
     return (ptr);
    }

    void sig_alrm(int signo)
    {
     (*pr->fsend) ();

     alarm(1);
     return;
    }

    int Socket(int family, int type, int protocol)
    {
     int n;

     if ((n = socket(family, type, protocol)) < 0)
      err_sys("socket error");
     return (n);
    }

    void readloop(void)
    {
     int size;
     char recvbuf[BUFSIZE];
     char controlbuf[BUFSIZE];
     struct msghdr msg;
     struct iovec iov;
     ssize_t n;
     struct timeval tval;

     sockfd = Socket(pr->sasend->sa_family, SOCK_RAW, pr->icmpproto);
     setuid(getuid()); /* don't need special permissions any more */
     if (pr->finit)
      (*pr->finit) ();

     size = 60 * 1024; /* OK if setsockopt fails */
     setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));

     sig_alrm(SIGALRM); /* send first packet */

     iov.iov_base = recvbuf;
     iov.iov_len = sizeof(recvbuf);
     msg.msg_name = pr->sarecv;
     msg.msg_iov = &iov;
     msg.msg_iovlen = 1;
     msg.msg_control = controlbuf;
     for (;;) {
      msg.msg_namelen = pr->salen;
      msg.msg_controllen = sizeof(controlbuf);
      n = recvmsg(sockfd, &msg, 0);
      if (n < 0) {
       if (errno == EINTR)
        continue;
       else
        err_sys("recvmsg error");
      }

      Gettimeofday(&tval, NULL);
      (*pr->fproc) (recvbuf, n, &msg, &tval);
     }
    }

    void proc_v6(char *ptr, ssize_t len, struct msghdr *msg, struct timeval *tvrecv)
    {
    #ifdef IPV6
     double rtt;
     struct icmp6_hdr *icmp6;
     struct timeval *tvsend;
     struct cmsghdr *cmsg;
     int hlim;

     icmp6 = (struct icmp6_hdr *)ptr;
     if (len < 8)
      return;  /* malformed packet */

     if (icmp6->icmp6_type == ICMP6_ECHO_REPLY) {
      if (icmp6->icmp6_id != pid)
       return; /* not a response to our ECHO_REQUEST */
      if (len < 16)
       return; /* not enough data to use */

      tvsend = (struct timeval *)(icmp6 + 1);
      tv_sub(tvrecv, tvsend);
      rtt = tvrecv->tv_sec * 1000.0 + tvrecv->tv_usec / 1000.0;

      hlim = -1;
      for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
           cmsg = CMSG_NXTHDR(msg, cmsg)) {
       if (cmsg->cmsg_level == IPPROTO_IPV6
           && cmsg->cmsg_type == IPV6_HOPLIMIT) {
        hlim = *(u_int32_t *) CMSG_DATA(cmsg);
        break;
       }
      }
      printf("%d bytes from %s: seq=%u, hlim=",
             len, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp6->icmp6_seq);
      if (hlim == -1)
       printf("???"); /* ancillary data missing */
      else
       printf("%d", hlim);
      printf(", rtt=%.3f ms ", rtt);
     } else if (verbose) {
      printf("  %d bytes from %s: type = %d, code = %d ",
             len, Sock_ntop_host(pr->sarecv, pr->salen),
             icmp6->icmp6_type, icmp6->icmp6_code);
     }
    #endif    /* IPV6 */
    }

    void send_v6()
    {
    #ifdef IPV6
     int len;
     struct icmp6_hdr *icmp6;

     icmp6 = (struct icmp6_hdr *)sendbuf;
     icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
     icmp6->icmp6_code = 0;
     icmp6->icmp6_id = pid;
     icmp6->icmp6_seq = nsent++;
     memset((icmp6 + 1), 0xa5, datalen); /* fill with pattern */
     Gettimeofday((struct timeval *)(icmp6 + 1), NULL);

     len = 8 + datalen; /* 8-byte ICMPv6 header */

     Sendto(sockfd, sendbuf, len, 0, pr->sasend, pr->salen);
     /* 4kernel calculates and stores checksum for us */
    #endif    /* IPV6 */
    }

    void init_v6()
    {
    #ifdef IPV6
     int on = 1;

     if (verbose == 0) {
      /* install a filter that only passes ICMP6_ECHO_REPLY unless verbose */
      struct icmp6_filter myfilt;
      ICMP6_FILTER_SETBLOCKALL(&myfilt);
      ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &myfilt);
      setsockopt(sockfd, IPPROTO_IPV6, ICMP6_FILTER, &myfilt,
          sizeof(myfilt));
      /* ignore error return; the filter is an optimization */
     }

     /* ignore error returned below; we just won't receive the hop limit */
    #ifdef IPV6_RECVHOPLIMIT
     /* RFC 3542 */
     setsockopt(sockfd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on));
    #else
     /* RFC 2292 */
     setsockopt(sockfd, IPPROTO_IPV6, IPV6_HOPLIMIT, &on, sizeof(on));
    #endif
    #endif
    }
    struct proto proto_v4 = { proc_v4, send_v4, NULL, NULL, NULL, 0, IPPROTO_ICMP };

    #ifdef IPV6
    struct proto proto_v6 =
        { proc_v6, send_v6, init_v6, NULL, NULL, 0, IPPROTO_ICMPV6 };
    #endif
    int main(int argc, char **argv)
    {
     int c;
     struct addrinfo *ai;
     char *h;

     opterr = 0;  /* don't want getopt() writing to stderr */
     while ((c = getopt(argc, argv, "v")) != -1) {
      switch (c) {
      case 'v':
       verbose++;
       break;

      case '?':
       err_quit("unrecognized option: %c", c);
      }
     }

     if (optind != argc - 1)
      err_quit("usage: ping [ -v ] <hostname>");
     host = argv[optind];

     pid = getpid() & 0xffff; /* ICMP ID field is 16 bits */
     Signal(SIGALRM, sig_alrm);

     ai = Host_serv(host, NULL, 0, 0);

     h = Sock_ntop_host(ai->ai_addr, ai->ai_addrlen);
     printf("PING %s (%s): %d data bytes ",
            ai->ai_canonname ? ai->ai_canonname : h, h, datalen);

     /* 4initialize according to protocol */
     if (ai->ai_family == AF_INET) {
      pr = &proto_v4;
    #ifdef IPV6
     } else if (ai->ai_family == AF_INET6) {
      pr = &proto_v6;
      if (IN6_IS_ADDR_V4MAPPED(&(((struct sockaddr_in6 *)
             ai->ai_addr)->sin6_addr)))
       err_quit("cannot ping IPv4-mapped IPv6 address");
    #endif
     } else
      err_quit("unknown address family %d", ai->ai_family);

     pr->sasend = ai->ai_addr;
     pr->sarecv = Calloc(1, ai->ai_addrlen);
     pr->salen = ai->ai_addrlen;

     readloop();

     exit(0);
    }

  • 相关阅读:
    Unique Binary Search Trees 解答
    Unique Paths II 解答
    Unique Paths 解答
    Maximum Subarray 解答
    Climbing Stairs 解答
    House Robber II 解答
    House Robber 解答
    Valid Palindrome 解答
    Container With Most Water 解答
    Remove Duplicates from Sorted List II 解答
  • 原文地址:https://www.cnblogs.com/liuhg/p/Ping.html
Copyright © 2011-2022 走看看