BPicture: Fix archive constructor.
[haiku.git] / src / kits / network / getifaddrs.cpp
blob585a347da0f116670b6868e04e93ccc2036da14e
1 /*
2 * Copyright 2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Adrien Destugues, pulkomandy@pulkomandy.tk
7 * Axel Dörfler, axeld@pinc-software.de
8 */
11 #include <algorithm>
12 #include <new>
14 #include <errno.h>
15 #include <net/if.h>
16 #include <netinet/in.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <sys/socket.h>
20 #include <sys/sockio.h>
21 #include <unistd.h>
23 #include <AutoDeleter.h>
25 #include <ifaddrs.h>
28 static sockaddr*
29 copy_address(const sockaddr& address)
31 if (address.sa_family == AF_UNSPEC)
32 return NULL;
34 sockaddr_storage* copy = new (std::nothrow) sockaddr_storage;
35 if (copy == NULL)
36 return NULL;
38 size_t length = std::min(sizeof(sockaddr_storage), (size_t)address.sa_len);
39 switch (address.sa_family) {
40 case AF_INET:
41 length = sizeof(sockaddr_in);
42 break;
43 case AF_INET6:
44 length = sizeof(sockaddr_in6);
45 break;
47 memcpy(copy, &address, length);
48 copy->ss_len = length;
49 return (sockaddr*)copy;
53 /*! Returns a chained list of all interfaces.
55 We follow BSD semantics, and only return one entry per interface,
56 not per address; since this is mainly used by NetBSD's netresolv, it's
57 probably what it expects.
59 int
60 getifaddrs(struct ifaddrs** _ifaddrs)
62 if (_ifaddrs == NULL) {
63 errno = B_BAD_VALUE;
64 return -1;
67 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
68 if (socket < 0)
69 return -1;
71 FileDescriptorCloser closer(socket);
73 // Get interface count
74 ifconf config;
75 config.ifc_len = sizeof(config.ifc_value);
76 if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
77 return -1;
79 size_t count = (size_t)config.ifc_value;
80 if (count == 0) {
81 // No interfaces found
82 *_ifaddrs = NULL;
83 return 0;
86 // Allocate a buffer for ifreqs for all interfaces
87 char* buffer = (char*)malloc(count * sizeof(struct ifreq));
88 if (buffer == NULL) {
89 errno = B_NO_MEMORY;
90 return -1;
93 MemoryDeleter deleter(buffer);
95 // Get interfaces configuration
96 config.ifc_len = count * sizeof(struct ifreq);
97 config.ifc_buf = buffer;
98 if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
99 return -1;
101 ifreq* interfaces = (ifreq*)buffer;
102 ifreq* end = (ifreq*)(buffer + config.ifc_len);
103 struct ifaddrs* previous = NULL;
105 for (uint32_t i = 0; interfaces < end; i++) {
106 struct ifaddrs* current = new(std::nothrow) ifaddrs();
107 if (current == NULL) {
108 freeifaddrs(previous);
109 errno = B_NO_MEMORY;
110 return -1;
113 // Chain this interface with the next one
114 current->ifa_next = previous;
115 previous = current;
117 current->ifa_name = strdup(interfaces[0].ifr_name);
118 current->ifa_addr = copy_address(interfaces[0].ifr_addr);
119 current->ifa_netmask = NULL;
120 current->ifa_dstaddr = NULL;
121 current->ifa_data = NULL;
123 ifreq request;
124 strlcpy(request.ifr_name, interfaces[0].ifr_name, IF_NAMESIZE);
126 if (ioctl(socket, SIOCGIFFLAGS, &request, sizeof(struct ifreq)) == 0)
127 current->ifa_flags = request.ifr_flags;
128 if (ioctl(socket, SIOCGIFNETMASK, &request, sizeof(struct ifreq))
129 == 0) {
130 current->ifa_netmask = copy_address(request.ifr_mask);
132 if (ioctl(socket, SIOCGIFDSTADDR, &request, sizeof(struct ifreq))
133 == 0) {
134 current->ifa_dstaddr = copy_address(request.ifr_dstaddr);
137 // Move on to next interface
138 interfaces = (ifreq*)((uint8_t*)interfaces
139 + _SIZEOF_ADDR_IFREQ(interfaces[0]));
142 *_ifaddrs = previous;
143 return 0;
147 void
148 freeifaddrs(struct ifaddrs* ifa)
150 while (ifa != NULL) {
151 free((void*)ifa->ifa_name);
152 delete ifa->ifa_addr;
153 delete ifa->ifa_netmask;
154 delete ifa->ifa_dstaddr;
156 struct ifaddrs* next = ifa->ifa_next;
157 delete ifa;
158 ifa = next;