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