在Libjingle+Linphone for Windows的voice call测试中, 遇到了一些问题. 而这些问题的root cause竟然源于Google code的一些小bug. 这里先指出一个.
SocketAddress这个类的其中一个构造函数是:
// Creates the address with the given host and port. If use_dns is true, // the hostname will be immediately resolved to an IP (which may block for // several seconds if DNS is not available). Alternately, set use_dns to // false, and then call Resolve() to complete resolution later, or use // SetResolvedIP to set the IP explictly. SocketAddress(const std::string& hostname, int port);
这个构造函数的参数看起来很简单, 一般人很少注意上面那堆罗嗦的注释, 第一个参数是hostname, 第二参数是port. 问题就出在hostname上面.
那这个构造函数的实现是什么呢?
SocketAddress::SocketAddress(const std::string& hostname, int port) { SetIP(hostname); SetPort(port); } void SocketAddress::SetIP(const std::string& hostname) { hostname_ = hostname; ip_ = StringToIP(hostname); } uint32 SocketAddress::StringToIP(const std::string& hostname) { uint32 ip = 0; StringToIP(hostname, &ip); return ip; } bool SocketAddress::StringToIP(const std::string& hostname, uint32* ip) { in_addr addr; if (inet_aton(hostname.c_str(), &addr) == 0) return false; *ip = NetworkToHost32(addr.s_addr); return true; } #ifdef WIN32 // Win32 doesn't provide inet_aton, so we add our own version here. // Since inet_addr returns 0xFFFFFFFF on error, if we get this value // we need to test the input to see if the address really was 255.255.255.255. // This is slightly fragile, but better than doing nothing. int inet_aton(const char* cp, struct in_addr* inp) { inp->s_addr = inet_addr(cp); return (inp->s_addr == INADDR_NONE && strcmp(cp, "255.255.255.255") != 0) ? 0 : 1; } #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
也就是说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.