1 /* 2 * libjingle 3 * Copyright 2008, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/base/nethelpers.h" 29 30 #if defined(WIN32) 31 #include <ws2spi.h> 32 #include <ws2tcpip.h> 33 #include "talk/base/win32.h" 34 #endif 35 36 #include "talk/base/byteorder.h" 37 #include "talk/base/signalthread.h" 38 39 namespace talk_base { 40 41 int ResolveHostname(const std::string& hostname, int family, 42 std::vector<IPAddress>* addresses) { 43 if (!addresses) { 44 return -1; 45 } 46 addresses->clear(); 47 struct addrinfo* result = NULL; 48 struct addrinfo hints = {0}; 49 // TODO(djw): For now this is IPv4 only so existing users remain unaffected. 50 hints.ai_family = AF_INET; 51 hints.ai_flags = AI_ADDRCONFIG; 52 int ret = getaddrinfo(hostname.c_str(), NULL, &hints, &result); 53 if (ret != 0) { 54 return ret; 55 } 56 struct addrinfo* cursor = result; 57 for (; cursor; cursor = cursor->ai_next) { 58 if (family == AF_UNSPEC || cursor->ai_family == family) { 59 IPAddress ip; 60 if (IPFromAddrInfo(cursor, &ip)) { 61 addresses->push_back(ip); 62 } 63 } 64 } 65 freeaddrinfo(result); 66 return 0; 67 } 68 69 // AsyncResolver 70 AsyncResolver::AsyncResolver() : error_(-1) { 71 } 72 73 void AsyncResolver::Start(const SocketAddress& addr) { 74 addr_ = addr; 75 // SignalThred Start will kickoff the resolve process. 76 SignalThread::Start(); 77 } 78 79 bool AsyncResolver::GetResolvedAddress(int family, SocketAddress* addr) const { 80 if (error_ != 0 || addresses_.empty()) 81 return false; 82 83 *addr = addr_; 84 for (size_t i = 0; i < addresses_.size(); ++i) { 85 if (family == addresses_[i].family()) { 86 addr->SetIP(addresses_[i]); 87 return true; 88 } 89 } 90 return false; 91 } 92 93 void AsyncResolver::DoWork() { 94 error_ = ResolveHostname(addr_.hostname().c_str(), addr_.family(), 95 &addresses_); 96 } 97 98 void AsyncResolver::OnWorkDone() { 99 SignalDone(this); 100 } 101 102 const char* inet_ntop(int af, const void *src, char* dst, socklen_t size) { 103 #ifdef WIN32 104 return win32_inet_ntop(af, src, dst, size); 105 #else 106 return ::inet_ntop(af, src, dst, size); 107 #endif 108 } 109 110 int inet_pton(int af, const char* src, void *dst) { 111 #ifdef WIN32 112 return win32_inet_pton(af, src, dst); 113 #else 114 return ::inet_pton(af, src, dst); 115 #endif 116 } 117 118 bool HasIPv6Enabled() { 119 #ifndef WIN32 120 // We only need to check this for Windows XP (so far). 121 return true; 122 #else 123 if (IsWindowsVistaOrLater()) { 124 return true; 125 } 126 if (!IsWindowsXpOrLater()) { 127 return false; 128 } 129 DWORD protbuff_size = 4096; 130 scoped_ptr<char[]> protocols; 131 LPWSAPROTOCOL_INFOW protocol_infos = NULL; 132 int requested_protocols[2] = {AF_INET6, 0}; 133 134 int err = 0; 135 int ret = 0; 136 // Check for protocols in a do-while loop until we provide a buffer large 137 // enough. (WSCEnumProtocols sets protbuff_size to its desired value). 138 // It is extremely unlikely that this will loop more than once. 139 do { 140 protocols.reset(new char[protbuff_size]); 141 protocol_infos = reinterpret_cast<LPWSAPROTOCOL_INFOW>(protocols.get()); 142 ret = WSCEnumProtocols(requested_protocols, protocol_infos, 143 &protbuff_size, &err); 144 } while (ret == SOCKET_ERROR && err == WSAENOBUFS); 145 146 if (ret == SOCKET_ERROR) { 147 return false; 148 } 149 150 // Even if ret is positive, check specifically for IPv6. 151 // Non-IPv6 enabled WinXP will still return a RAW protocol. 152 for (int i = 0; i < ret; ++i) { 153 if (protocol_infos[i].iAddressFamily == AF_INET6) { 154 return true; 155 } 156 } 157 return false; 158 #endif 159 } 160 } // namespace talk_base 161