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 #include "talk/base/byteorder.h" 31 #include "talk/base/signalthread.h" 32 33 namespace talk_base { 34 35 #if defined(LINUX) || defined(ANDROID) 36 static const size_t kInitHostentLen = 1024; 37 static const size_t kMaxHostentLen = kInitHostentLen * 8; 38 #endif 39 40 // AsyncResolver 41 42 AsyncResolver::AsyncResolver() : result_(NULL), error_(0) { 43 } 44 45 AsyncResolver::~AsyncResolver() { 46 FreeHostEnt(result_); 47 } 48 49 void AsyncResolver::DoWork() { 50 result_ = SafeGetHostByName(addr_.hostname().c_str(), &error_); 51 } 52 53 void AsyncResolver::OnWorkDone() { 54 if (result_) { 55 addr_.SetIP(NetworkToHost32( 56 *reinterpret_cast<uint32*>(result_->h_addr_list[0]))); 57 } 58 } 59 60 // The functions below are used to do gethostbyname, but with an allocated 61 // instead of a static buffer. 62 hostent* SafeGetHostByName(const char* hostname, int* herrno) { 63 if (NULL == hostname || NULL == herrno) { 64 return NULL; 65 } 66 hostent* result = NULL; 67 #if defined(WIN32) 68 // On Windows we have to allocate a buffer, and manually copy the hostent, 69 // along with its embedded pointers. 70 hostent* ent = gethostbyname(hostname); 71 if (!ent) { 72 *herrno = WSAGetLastError(); 73 return NULL; 74 } 75 76 // Get the total number of bytes we need to copy, and allocate our buffer. 77 int num_aliases = 0, num_addrs = 0; 78 int total_len = sizeof(hostent); 79 total_len += strlen(ent->h_name) + 1; 80 while (ent->h_aliases[num_aliases]) { 81 total_len += sizeof(char*) + strlen(ent->h_aliases[num_aliases]) + 1; 82 ++num_aliases; 83 } 84 total_len += sizeof(char*); 85 while (ent->h_addr_list[num_addrs]) { 86 total_len += sizeof(char*) + ent->h_length; 87 ++num_addrs; 88 } 89 total_len += sizeof(char*); 90 91 result = static_cast<hostent*>(malloc(total_len)); 92 if (NULL == result) { 93 return NULL; 94 } 95 char* p = reinterpret_cast<char*>(result) + sizeof(hostent); 96 97 // Copy the hostent into it, along with its embedded pointers. 98 result->h_name = p; 99 memcpy(p, ent->h_name, strlen(ent->h_name) + 1); 100 p += strlen(ent->h_name) + 1; 101 102 result->h_aliases = reinterpret_cast<char**>(p); 103 p += (num_aliases + 1) * sizeof(char*); 104 for (int i = 0; i < num_aliases; ++i) { 105 result->h_aliases[i] = p; 106 memcpy(p, ent->h_aliases[i], strlen(ent->h_aliases[i]) + 1); 107 p += strlen(ent->h_aliases[i]) + 1; 108 } 109 result->h_aliases[num_aliases] = NULL; 110 111 result->h_addrtype = ent->h_addrtype; 112 result->h_length = ent->h_length; 113 114 result->h_addr_list = reinterpret_cast<char**>(p); 115 p += (num_addrs + 1) * sizeof(char*); 116 for (int i = 0; i < num_addrs; ++i) { 117 result->h_addr_list[i] = p; 118 memcpy(p, ent->h_addr_list[i], ent->h_length); 119 p += ent->h_length; 120 } 121 result->h_addr_list[num_addrs] = NULL; 122 123 *herrno = 0; 124 #elif defined(LINUX) || defined(ANDROID) 125 // gethostbyname() is not thread safe, so we need to call gethostbyname_r() 126 // which is a reentrant version of gethostbyname(). 127 ASSERT(kInitHostentLen > sizeof(hostent)); 128 size_t size = kInitHostentLen; 129 int ret; 130 void* buf = malloc(size); 131 if (NULL == buf) { 132 return NULL; 133 } 134 char* aux = static_cast<char*>(buf) + sizeof(hostent); 135 size_t aux_len = size - sizeof(hostent); 136 while ((ret = gethostbyname_r(hostname, reinterpret_cast<hostent*>(buf), aux, 137 aux_len, &result, herrno)) == ERANGE) { 138 size *= 2; 139 if (size > kMaxHostentLen) { 140 break; // Just to be safe. 141 } 142 buf = realloc(buf, size); 143 if (NULL == buf) { 144 return NULL; 145 } 146 aux = static_cast<char*>(buf) + sizeof(hostent); 147 aux_len = size - sizeof(hostent); 148 } 149 if (ret != 0 || buf != result) { 150 free(buf); 151 return NULL; 152 } 153 *herrno = 0; 154 #elif defined(OSX) || defined(IOS) 155 // Mac OS returns an object with everything allocated. 156 result = getipnodebyname(hostname, AF_INET, AI_DEFAULT, herrno); 157 #else 158 #error "I don't know how to do gethostbyname safely on your system." 159 #endif 160 return result; 161 } 162 163 // This function should mirror the above function, and free any resources 164 // allocated by the above. 165 void FreeHostEnt(hostent* host) { 166 #if defined(OSX) || defined(IOS) 167 freehostent(host); 168 #elif defined(WIN32) || defined(POSIX) 169 free(host); 170 #else 171 #error "I don't know how to free a hostent on your system." 172 #endif 173 } 174 175 } // namespace talk_base 176