Assorted whitespace cleanup and typo fixes.
[haiku.git] / src / kits / network / libnetapi / NetworkAddressResolver.cpp
blobe7e61eac4e4f8958e2ca3e35109a22523ad1a4a7
1 /*
2 * Copyright 2010-2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <NetworkAddressResolver.h>
9 #include <errno.h>
10 #include <netdb.h>
12 #include <NetworkAddress.h>
15 static bool
16 strip_port(BString& host, BString& port)
18 int32 first = host.FindFirst(':');
19 int32 separator = host.FindLast(':');
20 if (separator != first
21 && (separator == 0 || host.ByteAt(separator - 1) != ']')) {
22 return false;
25 if (separator != -1) {
26 // looks like there is a port
27 host.CopyInto(port, separator + 1, -1);
28 host.Truncate(separator);
30 return true;
33 return false;
37 // #pragma mark -
40 BNetworkAddressResolver::BNetworkAddressResolver()
42 BReferenceable(),
43 fInfo(NULL),
44 fStatus(B_NO_INIT)
49 BNetworkAddressResolver::BNetworkAddressResolver(const char* address,
50 uint16 port, uint32 flags)
52 BReferenceable(),
53 fInfo(NULL),
54 fStatus(B_NO_INIT)
56 SetTo(address, port, flags);
59 BNetworkAddressResolver::BNetworkAddressResolver(const char* address,
60 const char* service, uint32 flags)
62 BReferenceable(),
63 fInfo(NULL),
64 fStatus(B_NO_INIT)
66 SetTo(address, service, flags);
70 BNetworkAddressResolver::BNetworkAddressResolver(int family,
71 const char* address, uint16 port, uint32 flags)
73 BReferenceable(),
74 fInfo(NULL),
75 fStatus(B_NO_INIT)
77 SetTo(family, address, port, flags);
81 BNetworkAddressResolver::BNetworkAddressResolver(int family,
82 const char* address, const char* service, uint32 flags)
84 BReferenceable(),
85 fInfo(NULL),
86 fStatus(B_NO_INIT)
88 SetTo(family, address, service, flags);
92 BNetworkAddressResolver::~BNetworkAddressResolver()
94 Unset();
98 status_t
99 BNetworkAddressResolver::InitCheck() const
101 return fStatus;
105 void
106 BNetworkAddressResolver::Unset()
108 if (fInfo != NULL) {
109 freeaddrinfo(fInfo);
110 fInfo = NULL;
112 fStatus = B_NO_INIT;
116 status_t
117 BNetworkAddressResolver::SetTo(const char* address, uint16 port, uint32 flags)
119 return SetTo(AF_UNSPEC, address, port, flags);
123 status_t
124 BNetworkAddressResolver::SetTo(const char* address, const char* service,
125 uint32 flags)
127 return SetTo(AF_UNSPEC, address, service, flags);
131 status_t
132 BNetworkAddressResolver::SetTo(int family, const char* address, uint16 port,
133 uint32 flags)
135 BString service;
136 service << port;
138 return SetTo(family, address, port != 0 ? service.String() : NULL, flags);
142 status_t
143 BNetworkAddressResolver::SetTo(int family, const char* host,
144 const char* service, uint32 flags)
146 Unset();
148 // Check if the address contains a port
150 BString hostString(host);
152 BString portString;
153 if (!strip_port(hostString, portString) && service != NULL)
154 portString = service;
156 // Resolve address
158 addrinfo hint = {0};
159 hint.ai_family = family;
160 if ((flags & B_NO_ADDRESS_RESOLUTION) != 0)
161 hint.ai_flags |= AI_NUMERICHOST;
162 else if ((flags & B_UNCONFIGURED_ADDRESS_FAMILIES) == 0)
163 hint.ai_flags |= AI_ADDRCONFIG;
165 if (host == NULL && portString.Length() == 0) {
166 portString = "0";
167 hint.ai_flags |= AI_PASSIVE;
170 int status = getaddrinfo(host != NULL ? hostString.String() : NULL,
171 portString.Length() != 0 ? portString.String() : NULL, &hint, &fInfo);
172 if (status == 0)
173 return fStatus = B_OK;
175 // Map errors
176 // TODO: improve error reporting, maybe add specific error codes?
178 switch (status) {
179 case EAI_ADDRFAMILY:
180 case EAI_BADFLAGS:
181 case EAI_PROTOCOL:
182 case EAI_BADHINTS:
183 case EAI_SOCKTYPE:
184 case EAI_SERVICE:
185 case EAI_NONAME:
186 case EAI_FAMILY:
187 fStatus = B_BAD_VALUE;
188 break;
190 case EAI_SYSTEM:
191 fStatus = errno;
192 break;
194 case EAI_OVERFLOW:
195 case EAI_MEMORY:
196 fStatus = B_NO_MEMORY;
197 break;
199 case EAI_AGAIN:
200 // TODO: better error code to denote temporary failure?
201 fStatus = B_TIMED_OUT;
202 break;
204 default:
205 fStatus = B_ERROR;
206 break;
209 return fStatus;
213 status_t
214 BNetworkAddressResolver::GetNextAddress(uint32* cookie,
215 BNetworkAddress& address) const
217 if (fStatus != B_OK)
218 return fStatus;
220 // Skip previous info entries
222 addrinfo* info = fInfo;
223 int32 first = *cookie;
224 for (int32 index = 0; index < first && info != NULL; index++) {
225 info = info->ai_next;
228 if (info == NULL)
229 return B_BAD_VALUE;
231 // Return current
233 address.SetTo(*info->ai_addr, info->ai_addrlen);
234 (*cookie)++;
236 return B_OK;
240 status_t
241 BNetworkAddressResolver::GetNextAddress(int family, uint32* cookie,
242 BNetworkAddress& address) const
244 if (fStatus != B_OK)
245 return fStatus;
247 // Skip previous info entries, and those that have a non-matching family
249 addrinfo* info = fInfo;
250 int32 first = *cookie;
251 for (int32 index = 0; index < first && info != NULL; index++)
252 info = info->ai_next;
254 while (info != NULL && info->ai_family != family)
255 info = info->ai_next;
257 if (info == NULL)
258 return B_BAD_VALUE;
260 // Return current
262 address.SetTo(*info->ai_addr, info->ai_addrlen);
263 (*cookie)++;
265 return B_OK;
269 /*static*/ BReference<const BNetworkAddressResolver>
270 BNetworkAddressResolver::Resolve(const char* address, const char* service,
271 uint32 flags)
273 return Resolve(AF_UNSPEC, address, service, flags);
277 /*static*/ BReference<const BNetworkAddressResolver>
278 BNetworkAddressResolver::Resolve(const char* address, uint16 port, uint32 flags)
280 return Resolve(AF_UNSPEC, address, port, flags);
284 /*static*/ BReference<const BNetworkAddressResolver>
285 BNetworkAddressResolver::Resolve(int family, const char* address,
286 uint16 port, uint32 flags)
288 BString service;
289 service << port;
291 return Resolve(family, address, port == 0 ? NULL : service.String(), flags);
295 /*static*/ BReference<const BNetworkAddressResolver>
296 BNetworkAddressResolver::Resolve(int family, const char* address,
297 const char* service, uint32 flags)
299 // TODO it may be faster to use an hash map to have faster lookup of the
300 // cache. However, we also need to access the cache by LRU, and for that
301 // a doubly-linked list is better. We should have these two share the same
302 // items, so it's easy to remove the LRU from the map, or insert a new
303 // item in both structures.
304 for (int i = 0; i < sCacheMap.CountItems(); i++) {
305 CacheEntry* entry = sCacheMap.ItemAt(i);
306 if (entry->Matches(family, address, service, flags)) {
307 // This entry is now the MRU, move to end of list.
308 // TODO if the item is old (more than 1 minute), it should be
309 // dropped and a new request made.
310 sCacheMap.MoveItem(i, sCacheMap.CountItems());
311 return entry->fResolver;
315 BNetworkAddressResolver* resolver = new(std::nothrow)
316 BNetworkAddressResolver(family, address, service, flags);
318 if (resolver != NULL && resolver->InitCheck() == B_OK) {
319 // TODO adjust capacity. Chrome uses 256 entries with a timeout of
320 // 1 minute, IE uses 1000 entries with a timeout of 30 seconds.
321 if (sCacheMap.CountItems() > 255)
322 delete sCacheMap.RemoveItemAt(0);
324 CacheEntry* entry = new(std::nothrow) CacheEntry(family, address,
325 service, flags, resolver);
326 if (entry)
327 sCacheMap.AddItem(entry, sCacheMap.CountItems());
330 return BReference<const BNetworkAddressResolver>(resolver, true);
334 BObjectList<BNetworkAddressResolver::CacheEntry>
335 BNetworkAddressResolver::sCacheMap;