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