Merge pull request #25959 from neo1973/TagLib_deprecation_warnings
[xbmc.git] / lib / libUPnP / Neptune / Source / System / Bsd / NptBsdNetwork.cpp
blob6208185e5019cf6f39362bf483442c71bc6e70b4
1 /*****************************************************************
3 | Neptune - Network :: BSD Implementation
5 | (c) 2001-2016 Gilles Boccon-Gibod
6 | Author: Gilles Boccon-Gibod (bok@bok.net)
8 ****************************************************************/
10 /*----------------------------------------------------------------------
11 | includes
12 +---------------------------------------------------------------------*/
13 #include <sys/types.h>
14 #include <sys/socket.h>
15 #include <sys/select.h>
16 #include <sys/time.h>
17 #include <sys/ioctl.h>
18 #include <netinet/in.h>
19 #include <net/if.h>
20 //#include <net/if_arp.h>
21 #include <netdb.h>
22 #include <fcntl.h>
23 #include <unistd.h>
24 #include <errno.h>
26 #include "NptConfig.h"
27 #include "NptTypes.h"
28 #include "NptStreams.h"
29 #include "NptThreads.h"
30 #include "NptNetwork.h"
31 #include "NptUtils.h"
32 #include "NptConstants.h"
33 #include "NptSockets.h"
35 #if defined(NPT_CONFIG_HAVE_NET_IF_DL_H)
36 #include <net/if_dl.h>
37 #endif
38 #if defined(NPT_CONFIG_HAVE_NET_IF_TYPES_H)
39 #include <net/if_types.h>
40 #endif
42 #if defined(NPT_CONFIG_HAVE_GETIFADDRS)
43 #include <ifaddrs.h>
44 #endif
46 /*----------------------------------------------------------------------
47 | platform adaptation
48 +---------------------------------------------------------------------*/
49 #if !defined(IFHWADDRLEN)
50 #define IFHWADDRLEN 6 // default to 48 bits
51 #endif
52 #if !defined(ARPHRD_ETHER)
53 #define ARPHRD_ETHER 1
54 #endif
56 #if defined(_SIZEOF_ADDR_IFREQ)
57 #define NPT_IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr)
58 #elif defined(NPT_CONFIG_HAVE_SOCKADDR_SA_LEN)
59 #define NPT_IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)
60 #else
61 #define NPT_IFREQ_SIZE(ifr) sizeof(*ifr)
62 #endif
64 /*----------------------------------------------------------------------
65 | IPv6 support
66 +---------------------------------------------------------------------*/
67 #if defined(NPT_CONFIG_HAVE_ARPA_INET_H)
68 #include <arpa/inet.h>
69 #endif
71 /*----------------------------------------------------------------------
72 | NPT_IpAddress::Any and NPT_IpAddress::Loopback
73 +---------------------------------------------------------------------*/
74 #if defined(NPT_CONFIG_ENABLE_IPV6)
75 const NPT_IpAddress NPT_IpAddress::Any(NPT_IpAddress::IPV6, in6addr_any.s6_addr, 16);
76 const NPT_IpAddress NPT_IpAddress::Loopback(NPT_IpAddress::IPV6, in6addr_loopback.s6_addr, 16);
77 #else
78 const NPT_IpAddress NPT_IpAddress::Any;
79 const NPT_IpAddress NPT_IpAddress::Loopback(127,0,0,1);
80 #endif
82 #if defined(NPT_CONFIG_HAVE_INET_NTOP)
83 /*----------------------------------------------------------------------
84 | NPT_IpAddress::ToString
85 +---------------------------------------------------------------------*/
86 NPT_String
87 NPT_IpAddress::ToString() const
89 NPT_String address;
90 char workspace[128];
91 int af = AF_INET;
92 #if defined(NPT_CONFIG_ENABLE_IPV6)
93 if (m_Type == IPV6) {
94 af = AF_INET6;
96 #endif
97 const char* string = inet_ntop(af, &m_Address[0], workspace, sizeof(workspace));
98 if (string) {
99 address = string;
102 return address;
104 #else
105 /*----------------------------------------------------------------------
106 | NPT_IpAddress::ToString
107 +---------------------------------------------------------------------*/
108 NPT_String
109 NPT_IpAddress::ToString() const
111 NPT_String address;
112 address.Reserve(16);
113 address += NPT_String::FromInteger(m_Address[0]);
114 address += '.';
115 address += NPT_String::FromInteger(m_Address[1]);
116 address += '.';
117 address += NPT_String::FromInteger(m_Address[2]);
118 address += '.';
119 address += NPT_String::FromInteger(m_Address[3]);
121 return address;
123 #endif
125 #if defined(NPT_CONFIG_HAVE_INET_PTON)
126 /*----------------------------------------------------------------------
127 | NPT_IpAddress::Parse
128 +---------------------------------------------------------------------*/
129 NPT_Result
130 NPT_IpAddress::Parse(const char* name)
132 int result;
134 // check the name
135 if (name == NULL) return NPT_ERROR_INVALID_PARAMETERS;
137 // clear the address
138 NPT_SetMemory(&m_Address[0], 0, sizeof(m_Address));
140 #if defined(NPT_CONFIG_ENABLE_IPV6)
141 // try IPv6 first
142 result = inet_pton(AF_INET6, name, &m_Address[0]);
143 if (result > 0) {
144 m_Type = IPV6;
145 return NPT_SUCCESS;
147 #endif
149 // try IPv4 next
150 result = inet_pton(AF_INET, name, &m_Address[0]);
151 if (result > 0) {
152 m_Type = IPV4;
153 return NPT_SUCCESS;
156 if (result == 0) {
157 return NPT_ERROR_INVALID_SYNTAX;
158 } else {
159 return NPT_FAILURE;
162 #else
163 /*----------------------------------------------------------------------
164 | NPT_IpAddress::Parse
165 +---------------------------------------------------------------------*/
166 NPT_Result
167 NPT_IpAddress::Parse(const char* name)
169 // check the name
170 if (name == NULL) return NPT_ERROR_INVALID_PARAMETERS;
172 // clear the address
173 NPT_SetMemory(&m_Address[0], 0, sizeof(m_Address));
175 // parse
176 unsigned int fragment;
177 bool fragment_empty = true;
178 unsigned char address[4];
179 unsigned int accumulator;
180 for (fragment = 0, accumulator = 0; fragment < 4; ++name) {
181 if (*name == '\0' || *name == '.') {
182 // fragment terminator
183 if (fragment_empty) return NPT_ERROR_INVALID_SYNTAX;
184 address[fragment++] = accumulator;
185 if (*name == '\0') break;
186 accumulator = 0;
187 fragment_empty = true;
188 } else if (*name >= '0' && *name <= '9') {
189 // numerical character
190 accumulator = accumulator*10 + (*name - '0');
191 if (accumulator > 255) return NPT_ERROR_INVALID_SYNTAX;
192 fragment_empty = false;
193 } else {
194 // invalid character
195 return NPT_ERROR_INVALID_SYNTAX;
199 if (fragment == 4 && *name == '\0' && !fragment_empty) {
200 m_Address[0] = address[0];
201 m_Address[1] = address[1];
202 m_Address[2] = address[2];
203 m_Address[3] = address[3];
204 return NPT_SUCCESS;
205 } else {
206 return NPT_ERROR_INVALID_SYNTAX;
209 #endif
211 #if defined(NPT_CONFIG_HAVE_GETIFADDRS)
212 /*----------------------------------------------------------------------
213 | NPT_NetworkInterface::GetNetworkInterfaces
214 +---------------------------------------------------------------------*/
215 NPT_Result
216 NPT_NetworkInterface::GetNetworkInterfaces(NPT_List<NPT_NetworkInterface*>& interfaces)
218 interfaces.Clear();
220 struct ifaddrs* addrs = NULL;
221 int result = getifaddrs(&addrs);
222 if (result != 0) {
223 return NPT_ERROR_BASE_UNIX-errno;
226 for (struct ifaddrs* addr = addrs;
227 addr;
228 addr = addr->ifa_next) {
230 // get detailed info about the interface
231 NPT_Flags flags = 0;
232 // process the flags
233 if ((addr->ifa_flags & IFF_UP) == 0) {
234 // the interface is not up, ignore it
235 continue;
237 if (addr->ifa_flags & IFF_BROADCAST) {
238 flags |= NPT_NETWORK_INTERFACE_FLAG_BROADCAST;
240 if (addr->ifa_flags & IFF_LOOPBACK) {
241 flags |= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK;
243 #if defined(IFF_POINTOPOINT)
244 if (addr->ifa_flags & IFF_POINTOPOINT) {
245 flags |= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT;
247 #endif // defined(IFF_POINTOPOINT)
248 if (addr->ifa_flags & IFF_PROMISC) {
249 flags |= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS;
251 if (addr->ifa_flags & IFF_MULTICAST) {
252 flags |= NPT_NETWORK_INTERFACE_FLAG_MULTICAST;
255 // get a pointer to an interface we've looped over before
256 // or create a new one
257 NPT_NetworkInterface* interface = NULL;
258 for (NPT_List<NPT_NetworkInterface*>::Iterator iface_iter = interfaces.GetFirstItem();
259 iface_iter;
260 ++iface_iter) {
261 if ((*iface_iter)->GetName() == (const char*)addr->ifa_name) {
262 interface = *iface_iter;
263 break;
266 if (interface == NULL) {
267 // create a new interface object
268 interface = new NPT_NetworkInterface(addr->ifa_name, flags);
270 // add the interface to the list
271 interfaces.Add(interface);
274 if (addr->ifa_addr == NULL) {
275 continue;
277 switch (addr->ifa_addr->sa_family) {
278 case AF_INET: {
279 // primary address
280 NPT_IpAddress primary_address(ntohl(((struct sockaddr_in*)addr->ifa_addr)->sin_addr.s_addr));
282 // broadcast address
283 NPT_IpAddress broadcast_address;
284 if (addr->ifa_broadaddr) {
285 broadcast_address.Set(ntohl(((struct sockaddr_in*)addr->ifa_broadaddr)->sin_addr.s_addr));
288 // point to point address
289 NPT_IpAddress destination_address;
290 if (addr->ifa_dstaddr) {
291 destination_address.Set(ntohl(((struct sockaddr_in*)addr->ifa_dstaddr)->sin_addr.s_addr));
294 // netmask
295 NPT_IpAddress netmask(0xFFFFFFFF);
296 if (addr->ifa_netmask) {
297 netmask.Set(ntohl(((struct sockaddr_in*)addr->ifa_netmask)->sin_addr.s_addr));
300 // add the address to the interface
301 NPT_NetworkInterfaceAddress iface_address(
302 primary_address,
303 broadcast_address,
304 destination_address,
305 netmask);
306 interface->AddAddress(iface_address);
308 break;
311 #if defined(NPT_CONFIG_ENABLE_IPV6)
312 case AF_INET6: {
313 // primary address
314 const struct sockaddr_in6* ipv6_address = (const struct sockaddr_in6*)addr->ifa_addr;
315 NPT_IpAddress primary_address(NPT_IpAddress::IPV6, ipv6_address->sin6_addr.s6_addr, 16, ipv6_address->sin6_scope_id);
317 // empty broadcast address (no broadcast address for IPv6)
318 NPT_IpAddress broadcast_address(NPT_IpAddress::IPV6);
320 // point to point address
321 NPT_IpAddress destination_address(NPT_IpAddress::IPV6);
322 if (flags & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT) {
323 if (addr->ifa_dstaddr) {
324 ipv6_address = (const struct sockaddr_in6*)addr->ifa_dstaddr;
325 destination_address.Set(ipv6_address->sin6_addr.s6_addr, 16, ipv6_address->sin6_scope_id);
329 // empty netmask (does not work for IPv6)
330 NPT_IpAddress netmask((NPT_IpAddress::IPV6));
332 // add the address to the interface
333 NPT_NetworkInterfaceAddress iface_address(
334 primary_address,
335 broadcast_address,
336 destination_address,
337 netmask);
338 interface->AddAddress(iface_address);
340 break;
342 #endif
344 #if defined(AF_LINK) && defined(NPT_CONFIG_HAVE_SOCKADDR_DL)
345 case AF_LINK: {
346 struct sockaddr_dl* mac_addr = (struct sockaddr_dl*)addr->ifa_addr;
347 NPT_MacAddress::Type mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN;
348 switch (mac_addr->sdl_type) {
349 #if defined(IFT_LOOP)
350 case IFT_LOOP: mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK; break;
351 #endif
352 #if defined(IFT_ETHER)
353 case IFT_ETHER: mac_addr_type = NPT_MacAddress::TYPE_ETHERNET; break;
354 #endif
355 #if defined(IFT_PPP)
356 case IFT_PPP: mac_addr_type = NPT_MacAddress::TYPE_PPP; break;
357 #endif
359 interface->SetMacAddress(mac_addr_type,
360 (const unsigned char*)(&mac_addr->sdl_data[mac_addr->sdl_nlen]),
361 mac_addr->sdl_alen);
362 break;
364 #endif
368 freeifaddrs(addrs);
370 return NPT_SUCCESS;
372 #else
373 const unsigned int NPT_BSD_NETWORK_MAX_IFCONF_SIZE = 1<<20;
375 /*----------------------------------------------------------------------
376 | NPT_NetworkInterface::GetNetworkInterfaces
377 +---------------------------------------------------------------------*/
378 NPT_Result
379 NPT_NetworkInterface::GetNetworkInterfaces(NPT_List<NPT_NetworkInterface*>& interfaces)
381 //#if defined(NPT_CONFIG_ENABLE_IPV6)
382 // int net = socket(PF_INET6, SOCK_DGRAM, 0);
383 //#else
384 int net = socket(PF_INET, SOCK_DGRAM, 0);
385 //#endif
386 if (net < 0) {
387 return NPT_ERROR_BASE_UNIX-errno;
390 // Try to get the config until we have enough memory for it
391 // According to "Unix Network Programming", some implementations
392 // do not return an error when the supplied buffer is too small
393 // so we need to try, increasing the buffer size every time,
394 // until we get the same size twice. We cannot assume success when
395 // the returned size is smaller than the supplied buffer, because
396 // some implementations can return less that the buffer size if
397 // another structure does not fit.
398 unsigned int buffer_size = 4096; // initial guess
399 unsigned int last_size = 0;
400 struct ifconf config;
401 unsigned char* buffer = NULL;
402 for (;buffer_size < NPT_BSD_NETWORK_MAX_IFCONF_SIZE;) {
403 buffer = new unsigned char[buffer_size];
404 config.ifc_len = buffer_size;
405 config.ifc_buf = (char*)buffer;
406 if (ioctl(net, SIOCGIFCONF, &config) < 0) {
407 if (errno != EINVAL || last_size != 0) {
408 delete[] buffer;
409 close(net);
410 return NPT_ERROR_BASE_UNIX-errno;
412 } else {
413 if ((unsigned int)config.ifc_len == last_size) {
414 // same size, we can use the buffer
415 break;
417 // different size, we need to reallocate
418 last_size = config.ifc_len;
421 // supply 4096 more bytes more next time around
422 buffer_size += 4096;
423 delete[] buffer;
424 buffer = NULL;
426 if (buffer == NULL) {
427 close(net);
428 return NPT_ERROR_NOT_ENOUGH_SPACE;
431 // iterate over all objects
432 unsigned char *entries;
433 for (entries = (unsigned char*)config.ifc_req; entries < (unsigned char*)config.ifc_req+config.ifc_len;) {
434 struct ifreq* entry = (struct ifreq*)entries;
436 // point to the next entry
437 entries += NPT_IFREQ_SIZE(entry);
439 // ignore anything except AF_INET, AF_INET6 (if enabled) and AF_LINK addresses
440 if (entry->ifr_addr.sa_family != AF_INET
441 #if defined(NPT_CONFIG_ENABLE_IPV6)
442 && entry->ifr_addr.sa_family != AF_INET6
443 #endif
444 #if defined(AF_LINK)
445 && entry->ifr_addr.sa_family != AF_LINK
446 #endif
448 continue;
451 // get detailed info about the interface
452 NPT_Flags flags = 0;
453 #if defined(SIOCGIFFLAGS)
454 struct ifreq query = *entry;
455 if (ioctl(net, SIOCGIFFLAGS, &query) < 0) continue;
457 // process the flags
458 if ((query.ifr_flags & IFF_UP) == 0) {
459 // the interface is not up, ignore it
460 continue;
462 if (query.ifr_flags & IFF_BROADCAST) {
463 flags |= NPT_NETWORK_INTERFACE_FLAG_BROADCAST;
465 if (query.ifr_flags & IFF_LOOPBACK) {
466 flags |= NPT_NETWORK_INTERFACE_FLAG_LOOPBACK;
468 #if defined(IFF_POINTOPOINT)
469 if (query.ifr_flags & IFF_POINTOPOINT) {
470 flags |= NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT;
472 #endif // defined(IFF_POINTOPOINT)
473 if (query.ifr_flags & IFF_PROMISC) {
474 flags |= NPT_NETWORK_INTERFACE_FLAG_PROMISCUOUS;
476 if (query.ifr_flags & IFF_MULTICAST) {
477 flags |= NPT_NETWORK_INTERFACE_FLAG_MULTICAST;
479 #endif // defined(SIOCGIFFLAGS)
481 // get a pointer to an interface we've looped over before
482 // or create a new one
483 NPT_NetworkInterface* interface = NULL;
484 for (NPT_List<NPT_NetworkInterface*>::Iterator iface_iter = interfaces.GetFirstItem();
485 iface_iter;
486 ++iface_iter) {
487 if ((*iface_iter)->GetName() == (const char*)entry->ifr_name) {
488 interface = *iface_iter;
489 break;
492 if (interface == NULL) {
493 // create a new interface object
494 interface = new NPT_NetworkInterface(entry->ifr_name, flags);
496 // add the interface to the list
497 interfaces.Add(interface);
499 // get the mac address
500 #if defined(SIOCGIFHWADDR)
501 if (ioctl(net, SIOCGIFHWADDR, &query) == 0) {
502 NPT_MacAddress::Type mac_addr_type;
503 unsigned int mac_addr_length = IFHWADDRLEN;
504 switch (query.ifr_addr.sa_family) {
505 #if defined(ARPHRD_ETHER)
506 case ARPHRD_ETHER:
507 mac_addr_type = NPT_MacAddress::TYPE_ETHERNET;
508 break;
509 #endif
511 #if defined(ARPHRD_LOOPBACK)
512 case ARPHRD_LOOPBACK:
513 mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK;
514 length = 0;
515 break;
516 #endif
518 #if defined(ARPHRD_PPP)
519 case ARPHRD_PPP:
520 mac_addr_type = NPT_MacAddress::TYPE_PPP;
521 mac_addr_length = 0;
522 break;
523 #endif
525 #if defined(ARPHRD_IEEE80211)
526 case ARPHRD_IEEE80211:
527 mac_addr_type = NPT_MacAddress::TYPE_IEEE_802_11;
528 break;
529 #endif
531 default:
532 mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN;
533 mac_addr_length = sizeof(query.ifr_addr.sa_data);
534 break;
537 interface->SetMacAddress(mac_addr_type, (const unsigned char*)query.ifr_addr.sa_data, mac_addr_length);
539 #endif
542 switch (entry->ifr_addr.sa_family) {
543 case AF_INET: {
544 // primary address
545 NPT_IpAddress primary_address(ntohl(((struct sockaddr_in*)&entry->ifr_addr)->sin_addr.s_addr));
547 // broadcast address
548 NPT_IpAddress broadcast_address;
549 #if defined(SIOCGIFBRDADDR)
550 if (flags & NPT_NETWORK_INTERFACE_FLAG_BROADCAST) {
551 if (ioctl(net, SIOCGIFBRDADDR, &query) == 0) {
552 broadcast_address.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr));
555 #endif
557 // point to point address
558 NPT_IpAddress destination_address;
559 #if defined(SIOCGIFDSTADDR)
560 if (flags & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT) {
561 if (ioctl(net, SIOCGIFDSTADDR, &query) == 0) {
562 destination_address.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr));
565 #endif
567 // netmask
568 NPT_IpAddress netmask(0xFFFFFFFF);
569 #if defined(SIOCGIFNETMASK)
570 if (ioctl(net, SIOCGIFNETMASK, &query) == 0) {
571 netmask.Set(ntohl(((struct sockaddr_in*)&query.ifr_addr)->sin_addr.s_addr));
573 #endif
575 // add the address to the interface
576 NPT_NetworkInterfaceAddress iface_address(
577 primary_address,
578 broadcast_address,
579 destination_address,
580 netmask);
581 interface->AddAddress(iface_address);
583 break;
586 #if defined(NPT_CONFIG_ENABLE_IPV6)
587 case AF_INET6: {
588 // primary address
589 const struct sockaddr_in6* ipv6_address = (const struct sockaddr_in6*)&entry->ifr_addr;
590 NPT_IpAddress primary_address(NPT_IpAddress::IPV6, ipv6_address->sin6_addr.s6_addr, 16, ipv6_address->sin6_scope_id);
592 // empty broadcast address (no broadcast address for IPv6)
593 NPT_IpAddress broadcast_address(NPT_IpAddress::IPV6);
595 // point to point address
596 NPT_IpAddress destination_address(NPT_IpAddress::IPV6);
597 #if defined(SIOCGIFDSTADDR)
598 if (flags & NPT_NETWORK_INTERFACE_FLAG_POINT_TO_POINT) {
599 if (ioctl(net, SIOCGIFDSTADDR, &query) == 0) {
600 ipv6_address = (const struct sockaddr_in6*)&query.ifr_addr;
601 destination_address.Set(ipv6_address->sin6_addr.s6_addr, 16, ipv6_address->sin6_scope_id);
604 #endif
606 // empty netmask (does not work for IPv6)
607 NPT_IpAddress netmask((NPT_IpAddress::IPV6));
609 // add the address to the interface
610 NPT_NetworkInterfaceAddress iface_address(
611 primary_address,
612 broadcast_address,
613 destination_address,
614 netmask);
615 interface->AddAddress(iface_address);
617 break;
619 #endif
621 #if defined(AF_LINK) && defined(NPT_CONFIG_HAVE_SOCKADDR_DL)
622 case AF_LINK: {
623 struct sockaddr_dl* mac_addr = (struct sockaddr_dl*)&entry->ifr_addr;
624 NPT_MacAddress::Type mac_addr_type = NPT_MacAddress::TYPE_UNKNOWN;
625 switch (mac_addr->sdl_type) {
626 #if defined(IFT_LOOP)
627 case IFT_LOOP: mac_addr_type = NPT_MacAddress::TYPE_LOOPBACK; break;
628 #endif
629 #if defined(IFT_ETHER)
630 case IFT_ETHER: mac_addr_type = NPT_MacAddress::TYPE_ETHERNET; break;
631 #endif
632 #if defined(IFT_PPP)
633 case IFT_PPP: mac_addr_type = NPT_MacAddress::TYPE_PPP; break;
634 #endif
636 interface->SetMacAddress(mac_addr_type,
637 (const unsigned char*)(&mac_addr->sdl_data[mac_addr->sdl_nlen]),
638 mac_addr->sdl_alen);
639 break;
641 #endif
645 // free resources
646 delete[] buffer;
647 close(net);
649 return NPT_SUCCESS;
651 #endif