免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: duanjigang
打印 上一主题 下一主题

源码阅读第一期:axel和wget [复制链接]

论坛徽章:
0
191 [报告]
发表于 2011-10-13 09:26 |只看该作者
还有就是对宏编译不是很熟悉
就是axel.h里面有个这个
#ifndef        NOGETOPTLONG
#define _GNU_SOURCE
#incl ...
xbjpkpk 发表于 2011-10-13 00:09



    基本上是的,最好自己编译测试下,源码在手,随你修改,呵呵

论坛徽章:
0
192 [报告]
发表于 2011-10-13 09:28 |只看该作者
提个建议,大哥们在分析代码时,能不能在开头就说明下分析的源代码在哪个项目哪个文件中。这样,看的人,即 ...
janock 发表于 2011-10-13 08:27



    有道理,分析自己的代码,某段代码其实这样写别人就能看明白了,比如:

axel/src/text.c:main()
里面的代码段

  1. xxxxxxxxxxxx
  2. xxxxxxxx
复制代码
好建议,不过不要指望别人把不分析的部分也告知你在哪个目录下啊,这样就太懒了

论坛徽章:
0
193 [报告]
发表于 2011-10-13 14:41 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-13 16:06 编辑

  1. 接着处理:/src/host.c

  2. 663 struct address_list *;=============>
  3. 664 lookup_host (const char *host, int flags)
  4. 665 {
  5. 677   {
  6. 678     uint32_t addr_ipv4 = (uint32_t)inet_addr (host);1、________--------->
  7. 679     if (addr_ipv4 != (uint32_t) -1)  /*如果返回成功*/
  8. 680       {
  9. 681         /* No need to cache host->addr relation, just return the
  10. 682            address.  */
  11. 683         char *vec[2];
  12. 684         vec[0] = (char *)&addr_ipv4;
  13. 685         vec[1] = NULL;
  14. 686         return address_list_from_ipv4_addresses (vec);2、_______--------->
  15. 687       }
  16. 688   }
  17.    /*ipv6的不分析了*/
  18. 713   if (use_cache)  /*如果用cache的主机名,并且LH_REFRECH不为1*/
  19. 714     {
  20. 715       if (!(flags & LH_REFRESH))
  21. 716         {
  22. 717           al = cache_query (host);  /*这是在hash_table中查这个主机的名字,前面说过将名字相同的存储到一个链表中*/
  23. 718           if (al)
  24. 719             return al; /*返回这个地址*/
  25. 720         }
  26. 721       else
  27. 722         cache_remove (host); /*否则,就删除这个host名*/
  28. 723     }


复制代码

  1. =============>
  2. 77 struct address_list {
  3. 78   int count;                    /* number of adrresses ,地址的个数*/
  4. 79   ip_address *addresses;        /* pointer to the string of addresses指向地址类型的字符串 */
  5. 80
  6. 81   int faulty;                   /* number of addresses known not to work. 不工作的地址*/
  7. 82   bool connected;               /* whether we were able to connect to
  8. 83                                    one of the addresses in the list,
  9. 84                                    at least once. 是否能够连接表中的地址*/
  10. 85
  11. 86   int refcount;                 /* reference count; when it drops to
  12. 87                                    0, the entry is freed. 引用此地址的计数,当到0时,就释放了*/
  13. 88 };
复制代码

  1. 1、_________----------->
  2. The inet_addr() function converts the Internet host address cp from numbers-and-dots notation into binary data in network byte order. If the input is invalid, INADDR_NONE (usually -1) is returned. This is an obsolete interface to inet_aton(), described immediately above; it is obsolete because -1 is a valid address (255.255.255.255), and inet_aton() provides a cleaner way to indicate error return
  3. /*函数将无符号整数网络地址转化成二进制网络字序,如果输入无效返回-1返回。*/
  4. 2、_______---------->
复制代码

  1. 262 static struct address_list *
  2. 263 address_list_from_ipv4_addresses (char **vec)
  3. 264 {
  4. 265   int count, i;
  5. 266   struct address_list *al = xnew0 (struct address_list); /*建立一个address_list结构*/
  6. 267
  7. 268   count = 0;
  8. 269   while (vec[count])  
  9. 270     ++count;
  10. 271   assert (count > 0);
  11. 272
  12. 273   al->addresses = xnew_array (ip_address, count);  /*建立count个ip_address地址*/
  13. 274   al->count     = count;
  14. 275   al->refcount  = 1;
  15. 276
  16. 277   for (i = 0; i < count; i++)
  17. 278     {
  18. 279       ip_address *ip = &al->addresses[i]; /*给指针一个指向的地址==========>*/
  19. 280       ip->family = AF_INET;  /*所在域是AF_INET*/
  20. 281       memcpy (IP_INADDR_DATA (ip), vec[i], 4);  /*将地址赋值过去ip地址为4个字节*/
  21. 282     }
  22. 283
  23. 284   return al;  /*返回al这个里面包含了很多ip信息*/

  24. }
复制代码

  1. =================>
  2. 55 typedef struct {
  3. 56   
  4. 57   int family;
  5. 58     
  6. 60   union {
  7. 61     struct in_addr d4;          /* IPv4 address 这就是ip地址 */
  8. 62 #ifdef ENABLE_IPV6
  9. 63     struct in6_addr d6;         /* IPv6 address */
  10. 64 #endif
  11. 65   } data;
复制代码

论坛徽章:
0
194 [报告]
发表于 2011-10-13 16:05 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-13 16:11 编辑

  1. connect.c的struct address_list *al = lookup_host(host, 0)
  2. 调用的
  3. 在lookup_host()过程中
  4. /*
  5. 263 address_list_from_ipv4_addresses (char **vec)
  6. 设置ip地址,ip域,等*/
  7. /*
  8. 717           al = cache_query (host);
  9. 从cashe中寻找要访问的主机名称*/
  10. 65 struct addrinfo /*存储地址信息的结构体*/
  11. 66 {
  12. 67   int ai_flags;                 /* Input flags.  */
  13. 68   int ai_family;                /* Protocol family for socket.  */
  14. 69   int ai_socktype;              /* Socket type.  */
  15. 70   int ai_protocol;              /* Protocol for socket.  */
  16. 71   socklen_t ai_addrlen;         /* Length of socket address.  */
  17. 72   struct sockaddr *ai_addr;     /* Socket address for socket.  */
  18. 73   char *ai_canonname;           /* Canonical name for service location.  */
  19. 74   struct addrinfo *ai_next;     /* Pointer to next in list.  */
  20. 75 };  
  21. 372 struct gaiwt_context {
  22. 373   const char *node;
  23. 374   const char *service;
  24. 375   const struct addrinfo *hints;
  25. 376   struct addrinfo **res;
  26. 377   int exit_code;
  27. 378 };
复制代码

  1. /*是否运行超时
  2. err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout);/timeout是规定的计时器*/
  3.      
  4. 2023   if (timeout == 0)
  5. 2024     {
  6. 2025       fun (arg);
  7. 2026       return false;
  8. 2027     }
  9. 2028
  10. 2029   signal (SIGALRM, abort_run_with_timeout);
  11. 1950 static void
  12. 1951 alarm_set (double timeout)
  13. 1952 {
  14. /*从新设置定时器,并且为addrinfo 类型的hints变量赋值,并且将端口也转化成host转化成inet格式*/
复制代码

  1. 从创建的addrinfo中创建address_list链表 al
  2.   al = address_list_from_addrinfo (res); 完成后,al中存储着所有的ip地址,其中ipv6和ipv4类型在函数中分开
  3. */
  4. 打印一些信息到logfp文件*/
复制代码

  1. 846   if (use_cache)
  2. 847     cache_store (host, al); /*根据host名存储到hash表,其中以host名字作为hash方程的hash元素,al存储到cell->value*/
复制代码
结束了*/
返回到

  1. connect_to_host()函数  
  2.   address_list_get_bounds (al, &start, &end); 获得边界*/
  3. 398   for (i = start; i < end; i++)
  4. 399     {
  5. 400       const ip_address *ip = address_list_address_at (al, i);
  6. 401       sock = connect_to_ip (ip, port, host); /*这个就开始连接网络*/
复制代码

  1. connect_to_ip()函数
  2. 00   sockaddr_set_data (sa, ip, port);  /*struct sockaddr 类型的======>1、________------->*/
  3. 301
  4. 302   
  5. 303   sock = socket (sa->sa_family, SOCK_STREAM, 0);  /*显然是面向TCP协议的,创建sock文件*/
  6. 304   if (sock < 0)
  7. 305     goto err;
复制代码

  1. ========================>
  2. struct sockaddr {
  3.   unsigned short sa_family; /* address family, AF_xxx */
  4.   char sa_data[14]; /* 14 bytes of protocol address */
  5.   };
  6.   sa_family是地址家族,一般都是“AF_xxx”的形式。好像通常大多用的是都是AF_INET。
  7.   sa_data是14字节协议地址。
  8. 但一般编程中并不直接针对此数据结构操作,而是使用另一个与sockaddr等价的数据结构
  9.   sockaddr_in(在netinet/in.h中定义):
  10.   struct sockaddr_in {
  11.   short int sin_family; /* Address family */
  12.   unsigned short int sin_port; /* Port number */
  13.   struct in_addr sin_addr; /* Internet address */
  14.   unsigned char sin_zero[8]; /* Same size as struct sockaddr */
  15.   };
复制代码

  1. 1、______________------------->
  2. 82 static void
  3. 83 sockaddr_set_data (struct sockaddr *sa, const ip_address *ip, int port)
  4. 84 {
  5. 85   switch (ip->family)
  6. 86     {
  7. 87     case AF_INET:
  8. 88       {
  9. 89         struct sockaddr_in *sin = (struct sockaddr_in *)sa;
  10. 90         xzero (*sin);
  11. 91         sin->sin_family = AF_INET;
  12. 92         sin->sin_port = htons (port);
  13. 93         sin->sin_addr = ip->data.d4;
  14. 94         break;
  15. 95       }
  16. 96 #ifdef ENABLE_IPV6
  17. 97     case AF_INET6:
  18. 98       {
  19. 99         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
  20. 100         xzero (*sin6);
  21. 101         sin6->sin6_family = AF_INET6;
  22. 102         sin6->sin6_port = htons (port);
  23. 103         sin6->sin6_addr = ip->data.d6;
  24. 104 #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
  25. 105         sin6->sin6_scope_id = ip->ipv6_scope;
  26. 106 #endif
  27. 107         break;
  28. 108       }
  29. 108       }
  30. 109 #endif /* ENABLE_IPV6 */
  31. 110     default:
  32. 111       abort ();
  33. 112     }
  34. 113 }
  35. 114
复制代码
[code]
接着就是
322   if (opt.limit_rate && opt.limit_rate < 8192)
323     {
324       int bufsize = opt.limit_rate;
设置buffer大小,至少为512字节*/
343           if (bind (sock, bind_sa, sockaddr_size (bind_sa)) < 0)
          /*这是给上面的sock文件编号,使之可以对应进行访问此sock文件*/
connect_with_timeout_________---------->230 connect_with_timeout_callback (void *arg)
231 {
232   struct cwt_context *ctx = (struct cwt_context *)arg;
233   ctx->result = connect (ctx->fd, ctx->addr, ctx->addrlen);
234 }
/*这就是开始连接了,伴随计时开始了*/

论坛徽章:
0
195 [报告]
发表于 2011-10-13 16:20 |只看该作者
本帖最后由 wangzhen11aaa 于 2011-10-13 16:22 编辑

貌似要结束了。 虽然有点乱,但是到后面就越来月清楚了。
怎么没人分析wget?
是不是因为大啊?

论坛徽章:
0
196 [报告]
发表于 2011-10-13 16:57 |只看该作者
本帖最后由 duanjigang 于 2011-10-13 22:23 编辑
貌似要结束了。 虽然有点乱,但是到后面就越来月清楚了。
怎么没人分析wget?
是不是因为大啊?
wangzhen11aaa 发表于 2011-10-13 16:20



    呵呵,辛苦了!

有个事情商量下,第一期开展阅读活动,设想的不够周到,一个帖子分析两个工具,有些乱。

因此计划,在分析完成后,把 wget 和 axel 的分开成两个帖子。

也就是说,后面需要整理下,axel整理成一个帖子, wget 整理成一个帖子。
不知道你这边时间是否充裕,需要把 wget 的内容整理下,搞个word文档,或者pdf都行,另起个帖子发布下。
如果你时间不够,俺们几个来搞,嘿嘿

另外,根据现在状况,下期开始,每期最多2个源码,看现在这状况,分析,好讨论确实比较耗时。。。
因为大家可能都有突然忙的时候。

论坛徽章:
0
197 [报告]
发表于 2011-10-13 18:43 |只看该作者
回复 195# duanjigang
我分析的是wget。

整理成pdf文档吧。
我尽量弄。

论坛徽章:
0
198 [报告]
发表于 2011-10-13 20:01 |只看该作者
反汇编指令及代码如下:
  2 #include<stdio.h>
  3 int main()
  4 {
  5 #define XNUM_TO_DIGIT(x) ("0123456789abcdef"[x]+ 0)
  6 int a = 2;
  7 int b = XNUM_TO_DIGIT(a);
  8 printf("%x",b);
  9 }

运行过程是这样的:
在调用main函数时,上面特意留出两个空间来表示堆栈。push 指令是 1: add $0x4, %esp 2: movl xx, %esp ;pop 指令是:1 : ovl %esp , xx ;2 : sub  $0x4, %esp
                   1 [         ] <-----esp + 8
                   2 [         ] <----esp + 4 ecx取道的地址是这里esp。 最后使用lea 不就是得到原来正好要使用到的esp么。真费劲,我觉得pop不行,因为pop %esp还没有听说过*/
                   3 [   xx    ] <----esp
                   4 [  原esp  ]<----esp -4
                   5 [  原ebp  ] <----esp - 8
                   6 [  原ecx  ]<---esp -12 最后堆栈esp 指向这里
                   7 [         ] <----esp  分配大小0x24
                      . . . . . .
                      [         ]       注意在mov %esp ,%ebp指令中是没有改变esp的。
                  
                     恢复堆栈
                                3 [   xx   ]<-------
                                4 [  原esp ]<-------最后用lea 去有效地址直接就能得到 原esp,不用出栈的pop了*/
                                5 [ 原ebp  ]<-------pop %ebp 将ebp出栈,出栈后esp指向原esp的位置,所以取esp的有效地址然后 - 4就是当前的esp。
                                6 [ ecx内值]<-------add $0x24 , %esp返回到这里,从这里pop %ecx
                                7 [    . .  ]<-------
                                8 [    . .  ]<-------

            



080483a4 <main>:

80483a4:       8d 4c 24 04             lea    0x4(%esp),%ecx  /*这是原esp的有效地址即为偏移地址esp为了使esp入栈,因为没有指令可以让esp直接入栈。入栈出栈,esp只是辅助操作的*/
80483a8:       83 e4 f0                and    $0xfffffff0,%esp
80483ab:       ff 71 fc                pushl  0xfffffffc(%ecx) /*出入ecx之后就是前一个esp的偏移值,那么- 4 就是esp的值*/
80483ae:       55                      push   %ebp
80483af:       89 e5                   mov    %esp,%ebp
80483b1:       51                      push   %ecx
80483b2:       83 ec 24                sub    $0x24,%esp
80483b5:       c7 45 f4 02 00 00 00    movl   $0x2,0xfffffff4(%ebp)
80483bc:       8b 45 f4                mov    0xfffffff4(%ebp),%eax
80483bf:       0f b6 80 c3 84 04 08    movzbl 0x80484c3(%eax),%eax
80483c6:       0f be c0                movsbl %al,%eax
80483c9:       89 45 f8                mov    %eax,0xfffffff8(%ebp)
80483cc:       8b 45 f8                mov    0xfffffff8(%ebp),%eax
80483cf:       89 44 24 04             mov    %eax,0x4(%esp)
80483d3:       c7 04 24 c0 84 04 08    movl   $0x80484c0,(%esp)
80483da:       e8 d9 fe ff ff          call   80482b8 <printf@plt>
80483df:       83 c4 24                add    $0x24,%esp
80483e2:       59                      pop    %ecx
80483e3:       5d                      pop    %ebp
80483e4:       8d 61 fc                lea    0xfffffffc(%ecx),%esp


总结:这里我认为pushl可能不用也行吧。如果没有pushl仍然可以用ecx来恢复原esp的啊。

论坛徽章:
1
午马
日期:2013-09-10 11:03:08
199 [报告]
发表于 2011-10-13 21:18 |只看该作者
回复 189# duanjigang


    诶,没得看到上面的if,光看下面的switch了,谢了

论坛徽章:
1
午马
日期:2013-09-10 11:03:08
200 [报告]
发表于 2011-10-13 21:49 |只看该作者
本帖最后由 xbjpkpk 于 2011-10-13 22:25 编辑

再次请问版主一个问题,我想把debug打开,我是这样输入的    ./configure --debug=1

但是为什么不行嘞?

找到了 直接在configure里面改 debug=1,现在想问下能不能直接用./configure 设置debug=1?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP