织梦CMS - 轻松建站从此开始!

罗索

Libjingle一个虽小但却很严重的bug - 误导人的SocketAddress构

落鹤生 发布于 2013-02-28 10:12 点击:次 
在Libjingle+Linphone for Windows的voice call测试中, 遇到了一些问题. 而这些问题的root cause竟然源于Google code的一些小bug. 这里先指出一个.
TAG:

在Libjingle+Linphone for Windows的voice call测试中, 遇到了一些问题. 而这些问题的root cause竟然源于Google code的一些小bug. 这里先指出一个.

SocketAddress这个类的其中一个构造函数是:

  1. // Creates the address with the given host and port.  If use_dns is true,   
  2. // the hostname will be immediately resolved to an IP (which may block for   
  3. // several seconds if DNS is not available).  Alternately, set use_dns to   
  4. // false, and then call Resolve() to complete resolution later, or use   
  5. // SetResolvedIP to set the IP explictly.   
  6. SocketAddress(const std::string& hostname, int port);   

这个构造函数的参数看起来很简单, 一般人很少注意上面那堆罗嗦的注释, 第一个参数是hostname, 第二参数是port. 问题就出在hostname上面.

那这个构造函数的实现是什么呢?

  1. SocketAddress::SocketAddress(const std::string& hostname, int port) {   
  2.   SetIP(hostname);   
  3.   SetPort(port);   
  4. }   
  5.    
  6. void SocketAddress::SetIP(const std::string& hostname) {   
  7.   hostname_ = hostname;   
  8.   ip_ = StringToIP(hostname);   
  9. }   
  10.    
  11. uint32 SocketAddress::StringToIP(const std::string& hostname) {   
  12.   uint32 ip = 0;   
  13.   StringToIP(hostname, &ip);   
  14.   return ip;   
  15. }   
  16.    
  17. bool SocketAddress::StringToIP(const std::string& hostname, uint32* ip) {   
  18.   in_addr addr;   
  19.   if (inet_aton(hostname.c_str(), &addr) == 0)   
  20.     return false;   
  21.   *ip = NetworkToHost32(addr.s_addr);   
  22.   return true;   
  23. }   
  24.    
  25. #ifdef WIN32   
  26. // Win32 doesn't provide inet_aton, so we add our own version here.   
  27. // Since inet_addr returns 0xFFFFFFFF on error, if we get this value   
  28. // we need to test the input to see if the address really was 255.255.255.255.   
  29. // This is slightly fragile, but better than doing nothing.   
  30. int inet_aton(const char* cp, struct in_addr* inp) {   
  31.   inp->s_addr = inet_addr(cp);   
  32.   return (inp->s_addr == INADDR_NONE &&   
  33.           strcmp(cp, "255.255.255.255") != 0) ? 0 : 1;   
  34. }   
  35. #endif  // WIN32  

hostname被传递的顺序是SocketAddress()->SetIP()->StringToIP()->inet_aton()->inet_addr()

那我们再来看看inet_addr()的说明, 这是一个系统函数. Refer to:

http://msdn.microsoft.com/en-us/library/ms738563%28v=vs.85%29.aspx

写道
The inet_addr function converts a string containing an IPv4 dotted-decimal address into a proper address for the IN_ADDR structure.
Parameters

cp [in]

A NULL-terminated character string representing a number expressed in the Internet standard ".'' (dotted) notation.
 

 也就是说inet_addr()函数的参数是一个IP地址字符串, 如"192.168.1.1".

而SocketAddress类的构造函数的参数按照字面意思应该是hostname (主机名),  所以如果传入hostname, 最终inet_addr()函数将无法正确解析, 那么构造的对象将会代表一个无效的地址.

偶被这个隐藏的小bug捉弄了好几天, 差点放弃Libjingle的测试, 幸亏最终静下心来仔细分析了一下.  如果传入hostname (比如"localhost") 构造这样一个SocketAddress对象, 然后调用SendTo()发送数据, 会返回-1, 系统错误码为WSAEADDRNOTAVAIL (10049) Cannot assign requested address.

写道
被请求的地址在它的环境中是不合法的。通常地在bind()函数试图将一个本地机器不合法的
地址绑扎到套接字时产生。它也可能在connect()、sendto()、WSAConnect()、WSAJoinLeaf()
或WSASendTo()函数调用时因远程机器的远程地址或端口号非法(如0地址或0端口号)而
产生。
(mysuperbaby)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/201302/16517.html]
本文出处:iteye 作者:mysuperbaby 原文
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容