1 /* 2 * Copyright 2010-2011, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <NetworkAddressResolver.h> 8 9 #include <errno.h> 10 #include <netdb.h> 11 12 #include <NetworkAddress.h> 13 14 15 static bool 16 strip_port(BString& host, BString& port) 17 { 18 int32 first = host.FindFirst(':'); 19 int32 separator = host.FindLast(':'); 20 if (separator != first 21 && (separator == 0 || host.ByteAt(separator - 1) != ']')) 22 return false; 23 24 if (separator != -1) { 25 // looks like there is a port 26 host.CopyInto(port, separator + 1, -1); 27 host.Truncate(separator); 28 29 return true; 30 } 31 32 return false; 33 } 34 35 36 // #pragma mark - 37 38 39 BNetworkAddressResolver::BNetworkAddressResolver() 40 : 41 fInfo(NULL), 42 fStatus(B_NO_INIT) 43 { 44 } 45 46 47 BNetworkAddressResolver::BNetworkAddressResolver(const char* address, 48 uint16 port, uint32 flags) 49 : 50 fInfo(NULL), 51 fStatus(B_NO_INIT) 52 { 53 SetTo(address, port, flags); 54 } 55 56 BNetworkAddressResolver::BNetworkAddressResolver(const char* address, 57 const char* service, uint32 flags) 58 : 59 fInfo(NULL), 60 fStatus(B_NO_INIT) 61 { 62 SetTo(address, service, flags); 63 } 64 65 66 BNetworkAddressResolver::BNetworkAddressResolver(int family, 67 const char* address, uint16 port, uint32 flags) 68 : 69 fInfo(NULL), 70 fStatus(B_NO_INIT) 71 { 72 SetTo(family, address, port, flags); 73 } 74 75 76 BNetworkAddressResolver::BNetworkAddressResolver(int family, 77 const char* address, const char* service, uint32 flags) 78 : 79 fInfo(NULL), 80 fStatus(B_NO_INIT) 81 { 82 SetTo(family, address, service, flags); 83 } 84 85 86 BNetworkAddressResolver::~BNetworkAddressResolver() 87 { 88 Unset(); 89 } 90 91 92 status_t 93 BNetworkAddressResolver::InitCheck() const 94 { 95 return fStatus; 96 } 97 98 99 void 100 BNetworkAddressResolver::Unset() 101 { 102 if (fInfo != NULL) { 103 freeaddrinfo(fInfo); 104 fInfo = NULL; 105 } 106 fStatus = B_NO_INIT; 107 } 108 109 110 status_t 111 BNetworkAddressResolver::SetTo(const char* address, uint16 port, uint32 flags) 112 { 113 return SetTo(AF_UNSPEC, address, port, flags); 114 } 115 116 117 status_t 118 BNetworkAddressResolver::SetTo(const char* address, const char* service, 119 uint32 flags) 120 { 121 return SetTo(AF_UNSPEC, address, service, flags); 122 } 123 124 125 status_t 126 BNetworkAddressResolver::SetTo(int family, const char* address, uint16 port, 127 uint32 flags) 128 { 129 BString service; 130 service << port; 131 132 return SetTo(family, address, port != 0 ? service.String() : NULL, flags); 133 } 134 135 136 status_t 137 BNetworkAddressResolver::SetTo(int family, const char* host, 138 const char* service, uint32 flags) 139 { 140 Unset(); 141 142 // Check if the address contains a port 143 144 BString hostString(host); 145 146 BString portString; 147 if (!strip_port(hostString, portString) && service != NULL) 148 portString = service; 149 150 // Resolve address 151 152 addrinfo hint = {0}; 153 hint.ai_family = family; 154 if ((flags & B_NO_ADDRESS_RESOLUTION) != 0) 155 hint.ai_flags |= AI_NUMERICHOST; 156 else if ((flags & B_UNCONFIGURED_ADDRESS_FAMILIES) == 0) 157 hint.ai_flags |= AI_ADDRCONFIG; 158 159 if (host == NULL && portString.Length() == 0) { 160 portString = "0"; 161 hint.ai_flags |= AI_PASSIVE; 162 } 163 164 int status = getaddrinfo(host != NULL ? hostString.String() : NULL, 165 portString.Length() != 0 ? portString.String() : NULL, &hint, &fInfo); 166 if (status == 0) 167 return fStatus = B_OK; 168 169 // Map errors 170 // TODO: improve error reporting, maybe add specific error codes? 171 172 switch (status) { 173 case EAI_ADDRFAMILY: 174 case EAI_BADFLAGS: 175 case EAI_PROTOCOL: 176 case EAI_BADHINTS: 177 case EAI_SOCKTYPE: 178 case EAI_SERVICE: 179 case EAI_NONAME: 180 case EAI_FAMILY: 181 fStatus = B_BAD_VALUE; 182 break; 183 184 case EAI_SYSTEM: 185 fStatus = errno; 186 break; 187 188 case EAI_OVERFLOW: 189 case EAI_MEMORY: 190 fStatus = B_NO_MEMORY; 191 break; 192 193 case EAI_AGAIN: 194 // TODO: better error code to denote temporary failure? 195 fStatus = B_TIMED_OUT; 196 break; 197 198 default: 199 fStatus = B_ERROR; 200 break; 201 } 202 203 return fStatus; 204 } 205 206 207 status_t 208 BNetworkAddressResolver::GetNextAddress(uint32* cookie, 209 BNetworkAddress& address) const 210 { 211 if (fStatus != B_OK) 212 return fStatus; 213 214 // Skip previous info entries 215 216 addrinfo* info = fInfo; 217 int32 first = *cookie; 218 for (int32 index = 0; index < first && info != NULL; index++) { 219 info = info->ai_next; 220 } 221 222 if (info == NULL) 223 return B_BAD_VALUE; 224 225 // Return current 226 227 address.SetTo(*info->ai_addr, info->ai_addrlen); 228 (*cookie)++; 229 230 return B_OK; 231 } 232 233 234 status_t 235 BNetworkAddressResolver::GetNextAddress(int family, uint32* cookie, 236 BNetworkAddress& address) const 237 { 238 if (fStatus != B_OK) 239 return fStatus; 240 241 // Skip previous info entries, and those that have a non-matching family 242 243 addrinfo* info = fInfo; 244 int32 first = *cookie; 245 for (int32 index = 0; index < first && info != NULL; index++) { 246 while (info != NULL && info->ai_family != family) 247 info = info->ai_next; 248 } 249 250 if (info == NULL) 251 return B_BAD_VALUE; 252 253 // Return current 254 255 address.SetTo(*info->ai_addr, info->ai_addrlen); 256 (*cookie)++; 257 258 return B_OK; 259 } 260