亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

Chinaunix

標題: [已解決] ping程序的問題. [打印本頁]

作者: PCliangtao    時間: 2010-11-17 19:58
標題: [已解決] ping程序的問題.
本帖最后由 PCliangtao 于 2010-11-17 20:50 編輯

在看UNP的時候,把書中的ping程序的例子的原理掌握之后,自己嘗試寫了一下.換湯不換藥... 只不過純粹只于IPv4打交道...
  不知道什么原理. 在發(fā)出echo的ICMP之后... 卻一直阻塞在recvmsg調用上... 我用tcpdump看...的確發(fā)生了ICMP ECHO...
  還有奇怪的一點的所... ping  www.hao123.com能夠正常工作... ping www.baidu.com www.goolge.com這樣的時候就一直阻塞在recvmsg上...
接觸網絡變成不久... 希望有經驗的兄弟們給瞧瞧... 多謝..

NB: 仔細想了一下... 估計是發(fā)送的ICMP 包被遠端丟棄了...  仔細看了一下構造ICMP 頭部的代碼... 汗ing... 校驗和的計算參數(shù)傳錯了...沒有把ICMP頭部算在內...修改了一下...
       就好了...
       可是還有一點奇怪的是... ICMP 對回送請求的應答應該是在內核里進行的吧...  但是為什么www.hao123.com主機能夠接受錯誤的校驗和的ICMP ECHO請求包呢?
       翻一翻TCP/IP的源代碼去...

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <signal.h>
  6. #include <errno.h>
  7. #include <netinet/in.h>
  8. #include <arpa/inet.h>
  9. #include <netinet/ip.h>
  10. #include <netinet/ip_icmp.h>
  11. #include <netdb.h>

  12. #define BUFSIZE 1024
  13. /* need those global vars, for simplicity */
  14. const char Usage[] = "Usage: ping [-v] host(hostname or hostIP)\n";
  15. static int nsnd;
  16. static int datalen;
  17. static int sockfd;
  18. static int verbose;
  19. static pid_t pid;
  20. static char sndbuf[BUFSIZE];
  21. static struct sockaddr *rcvaddr;
  22. static struct sockaddr *sndaddr;
  23. static socklen_t addrlen;
  24. /* some of the function prototypes */
  25. static void send_echo_icmp(void);
  26. static void recv_echoreply_icmp(char *, int, struct timeval *);
  27. static void sig_alrm(int signo);
  28. static char *show_addr_ip(struct sockaddr *, socklen_t len);
  29. static inline u_int16_t ip_fast_csum(const void *, unsigned int);

  30. static inline void err_quit(const char *str)
  31. {
  32.         perror(str);
  33.         exit(-1);
  34. }
  35. static inline void err_sys(const char *str)
  36. {
  37.         perror(str);
  38. }

  39. int main(int argc, char *argv[])
  40. {

  41.         int c;
  42.         char *host;
  43.         char *hostip;
  44.         char rcvbuf[BUFSIZE], ctlbuf[BUFSIZE];
  45.         struct msghdr msg;
  46.         struct iovec iov;
  47.         struct timeval rcvtv;
  48.         int size, n;
  49.         struct addrinfo *ai, *saved_ai, hint;
  50.        
  51.         while((c = getopt(argc, argv, "v")) != -1) {
  52.                 switch(c) {
  53.                 case 'v':
  54.                         verbose++;
  55.                         break;
  56.                 default:
  57.                         printf("unrecognized option %c\n", c);
  58.                         exit(-1);
  59.                 }
  60.         }
  61.         if(optind !=  argc - 1) {
  62.                 printf(Usage);
  63.                 exit(-1);
  64.         }
  65.         host = argv[optind];
  66.         datalen = 56;
  67.         signal(SIGALRM, sig_alrm);
  68.         pid = getpid() & 0xffff;
  69.         bzero(&hint, sizeof(hint));
  70.         hint.ai_flags = AI_CANONNAME;
  71.         hint.ai_family = AF_INET;
  72.         if(getaddrinfo(host, NULL, &hint, &ai) < 0)
  73.                 err_quit("getaddrinfo error: ");
  74.         saved_ai = ai;    /* don't need to do this actually */
  75.         for(; ai; ai = ai->ai_next)
  76.                 if(ai->ai_family == AF_INET)
  77.                         break;
  78.         if(!ai) {
  79.                 printf("cann't get IPv4 addrinfo\n");
  80.                 exit(-1);
  81.         }
  82.         hostip = show_addr_ip(ai->ai_addr, ai->ai_addrlen);
  83.         printf("ping %s (%s): %d data bytes\n", ai->ai_canonname ? \
  84.                 ai->ai_canonname : hostip, hostip, datalen);
  85.         sndaddr = ai->ai_addr;
  86.         addrlen = ai->ai_addrlen;
  87.         rcvaddr = (struct sockaddr *) malloc(addrlen);
  88.         if(!rcvaddr) {
  89.                 printf("malloc failed, OOM\n");
  90.                 exit(-1);
  91.         }

  92.         /* now we got all the information required, create the RAW socket and get started */
  93.         sockfd = socket(sndaddr->sa_family, SOCK_RAW, IPPROTO_ICMP);
  94.         if(sockfd < 0)
  95.                 err_quit("create socket error: ");
  96.         setuid(getuid()); /* only create RAW sock need privilege */

  97.         size = 60 * 1024;
  98.         setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
  99.         sig_alrm(SIGALRM);
  100.        
  101.         iov.iov_base = rcvbuf;
  102.         iov.iov_len = sizeof(rcvbuf);
  103.         msg.msg_name = rcvaddr;
  104.         msg.msg_namelen = addrlen;
  105.         msg.msg_iov = &iov;
  106.         msg.msg_iovlen = 1;
  107.         msg.msg_control = ctlbuf;
  108.         msg.msg_controllen = sizeof(ctlbuf);
  109.         while(1) {
  110.                 n = recvmsg(sockfd, &msg, 0);
  111.                 if(n < 0) {
  112.                         if(errno == EINTR)
  113.                                 continue;
  114.                         else {
  115.                                 err_sys("recvmsg error: ");
  116.                                 continue;
  117.                         }
  118.                 }
  119.                 gettimeofday(&rcvtv, NULL);
  120.         /*
  121.          * what if this process is slower than recv...maybe we'll get corrupted
  122.          * rcvtv .this should not be a problem, cause the internet is much much
  123.          * slower, respectly.
  124.          */
  125.                 recv_echoreply_icmp(rcvbuf, n, &rcvtv);
  126.         }
  127. }


  128. static void sig_alrm(int signo)
  129. {
  130.         send_echo_icmp();
  131.         alarm(1);
  132.         return;
  133. }


  134. /* send the icmp echo request */
  135. static void send_echo_icmp()
  136. {
  137.         int len;
  138.         struct icmp *icmp;
  139.         icmp = (struct icmp *)sndbuf;
  140.         /* build the icmp header */
  141.         icmp->icmp_type = ICMP_ECHO;
  142.         icmp->icmp_code = 0;
  143.         icmp->icmp_id = pid;
  144.         icmp->icmp_seq = ++nsnd;
  145.         if(datalen & 3) {
  146.                 fprintf(stderr, "datalen must be a multiple of 4!\n");
  147.                 datalen = (datalen + 3) & (~3UL);
  148.         }
  149.         memset(icmp->icmp_data, 0xa5, datalen);
  150.         gettimeofday((struct timeval *)icmp->icmp_data, NULL);
  151.         len = 8 + datalen;
  152.         icmp->icmp_cksum = 0;
  153.         icmp->icmp_cksum = ip_fast_csum(icmp->icmp_data, len >> 2);
  154.         if(sendto(sockfd, sndbuf, len, 0, sndaddr, addrlen) < 0)
  155.                 if(errno != EINTR)
  156.                         err_quit("sendto error: ");
  157. }

  158. static inline void cal_rtt(struct timeval *rcv, struct timeval *snd, double *rtt)
  159. {
  160.         if((rcv->tv_usec -= snd->tv_usec) < 0) {
  161.                 rcv->tv_sec--;
  162.                 rcv->tv_usec += 1000000;
  163.         }
  164.         rcv->tv_sec -= snd->tv_sec;
  165.         *rtt = rcv->tv_sec * 1000.0+ rcv->tv_usec / 1000.0;
  166. }

  167. static void recv_echoreply_icmp(char *rcvbuf, int len, struct timeval *rcv_tv)
  168. {
  169.         int iplen, icmplen;
  170.         double rtt;
  171.         struct ip *ip;
  172.         struct icmp *icmp;
  173.         struct timeval *snd_tv;
  174.         ip = (struct ip *)rcvbuf;
  175.         iplen = ip->ip_hl << 2;
  176.         if(ip->ip_p != IPPROTO_ICMP)
  177.                 goto ignore;
  178.         icmp = (struct icmp *)(rcvbuf + iplen);
  179.         icmplen = len - iplen;
  180.         if(icmplen < 8)
  181.                 goto ignore;
  182.         if(icmp->icmp_type == ICMP_ECHOREPLY) {
  183.                 if(icmp->icmp_id != pid)
  184.                         goto ignore;
  185.                 if(icmplen < 8+sizeof(struct timeval))
  186.                         goto ignore;
  187.                 snd_tv = (struct timeval *)icmp->icmp_data;
  188.                 cal_rtt(rcv_tv, snd_tv, &rtt);

  189.                 printf("%d bytes from %s: seq=%d, ttl=%d, rtt=%.3f ms\n", \
  190.                 icmplen, show_addr_ip(rcvaddr, addrlen), icmp->icmp_seq, \
  191.                         ip->ip_ttl, rtt);
  192.         } else if(verbose) {
  193.                 printf("%d bytes from %s: type=%d, code=%d\n", icmplen, \
  194.                 show_addr_ip(rcvaddr, addrlen), icmp->icmp_type,\
  195.                  icmp->icmp_code);
  196.         }
  197. ignore:
  198.         return;       
  199. }

  200. /* it's not safe, though */
  201. static char *show_addr_ip(struct sockaddr *sa, socklen_t len)
  202. {
  203.         static char ipbuf[INET6_ADDRSTRLEN];
  204.         switch(sa->sa_family) {
  205.         case AF_INET: {
  206.                 struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  207.                 if(len < sizeof(struct sockaddr_in))
  208.                         return NULL;
  209.                 if(inet_ntop(AF_INET, &sin->sin_addr, ipbuf,\
  210.                                                  INET6_ADDRSTRLEN) < 0)
  211.                         return NULL;
  212.                 return ipbuf;
  213.                 break;
  214.                 }
  215.         default:
  216.                 printf("don't support other addr type\n");
  217.                 return NULL;
  218.         }
  219. }

  220. /*
  221. *        This is a version of ip_compute_csum() optimized for IP headers,
  222. *        which always checksum on 4 octet boundaries.
  223. *
  224. *        By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by
  225. *        Arnt Gulbrandsen.
  226. */
  227. static inline u_int16_t ip_fast_csum(const void *iph, unsigned int ihl)
  228. {
  229.         unsigned int sum;

  230.         asm volatile("movl (%1), %0        ;\n"
  231.                      "subl $4, %2        ;\n"
  232.                      "jbe 2f                ;\n"
  233.                      "addl 4(%1), %0        ;\n"
  234.                      "adcl 8(%1), %0        ;\n"
  235.                      "adcl 12(%1), %0;\n"
  236.                      "1:        adcl 16(%1), %0        ;\n"
  237.                      "lea 4(%1), %1        ;\n"
  238.                      "decl %2        ;\n"
  239.                      "jne 1b                ;\n"
  240.                      "adcl $0, %0        ;\n"
  241.                      "movl %0, %2        ;\n"
  242.                      "shrl $16, %0        ;\n"
  243.                      "addw %w2, %w0        ;\n"
  244.                      "adcl $0, %0        ;\n"
  245.                      "notl %0        ;\n"
  246.                      "2:                ;\n"
  247.         /* Since the input registers which are loaded with iph and ihl
  248.            are modified, we must also specify them as outputs, or gcc
  249.            will assume they contain their original values. */
  250.                      : "=r" (sum), "=r" (iph), "=r" (ihl)
  251.                      : "1" (iph), "2" (ihl)
  252.                      : "memory");
  253.         return (u_int16_t)sum;
  254. }
復制代碼





歡迎光臨 Chinaunix (http://www.72891.cn/) Powered by Discuz! X3.2