xref: /haiku/src/kits/network/libnetapi/NetworkRoster.cpp (revision c80809a3ab0b0a2ce53ea861a2b00ace24ff452d)
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 <NetworkRoster.h>
8 
9 #include <errno.h>
10 #include <sys/sockio.h>
11 
12 #include <NetworkInterface.h>
13 
14 #include <net_notifications.h>
15 #include <AutoDeleter.h>
16 
17 
18 // TODO: using AF_INET for the socket isn't really a smart idea, as one
19 // could completely remove IPv4 support from the stack easily.
20 // Since in the stack, device_interfaces are pretty much interfaces now, we
21 // could get rid of them more or less, and make AF_LINK provide the same
22 // information as AF_INET for the interface functions mostly.
23 
24 
25 BNetworkRoster BNetworkRoster::sDefault;
26 
27 
28 /*static*/ BNetworkRoster&
29 BNetworkRoster::Default()
30 {
31 	return sDefault;
32 }
33 
34 
35 size_t
36 BNetworkRoster::CountInterfaces() const
37 {
38 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
39 	if (socket < 0)
40 		return 0;
41 
42 	FileDescriptorCloser closer(socket);
43 
44 	ifconf config;
45 	config.ifc_len = sizeof(config.ifc_value);
46 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) != 0)
47 		return 0;
48 
49 	return (size_t)config.ifc_value;
50 }
51 
52 
53 status_t
54 BNetworkRoster::GetNextInterface(uint32* cookie,
55 	BNetworkInterface& interface) const
56 {
57 	// TODO: think about caching the interfaces!
58 
59 	if (cookie == NULL)
60 		return B_BAD_VALUE;
61 
62 	// get a list of all interfaces
63 
64 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
65 	if (socket < 0)
66 		return errno;
67 
68 	FileDescriptorCloser closer(socket);
69 
70 	ifconf config;
71 	config.ifc_len = sizeof(config.ifc_value);
72 	if (ioctl(socket, SIOCGIFCOUNT, &config, sizeof(struct ifconf)) < 0)
73 		return errno;
74 
75 	size_t count = (size_t)config.ifc_value;
76 	if (count == 0)
77 		return B_BAD_VALUE;
78 
79 	char* buffer = (char*)malloc(count * sizeof(struct ifreq));
80 	if (buffer == NULL)
81 		return B_NO_MEMORY;
82 
83 	MemoryDeleter deleter(buffer);
84 
85 	config.ifc_len = count * sizeof(struct ifreq);
86 	config.ifc_buf = buffer;
87 	if (ioctl(socket, SIOCGIFCONF, &config, sizeof(struct ifconf)) < 0)
88 		return errno;
89 
90 	ifreq* interfaces = (ifreq*)buffer;
91 	ifreq* end = (ifreq*)(buffer + config.ifc_len);
92 
93 	for (uint32 i = 0; interfaces < end; i++) {
94 		interface.SetTo(interfaces[0].ifr_name);
95 		if (i == *cookie) {
96 			(*cookie)++;
97 			return B_OK;
98 		}
99 
100 		interfaces = (ifreq*)((uint8*)interfaces
101 			+ _SIZEOF_ADDR_IFREQ(interfaces[0]));
102 	}
103 
104 	return B_BAD_VALUE;
105 }
106 
107 
108 status_t
109 BNetworkRoster::AddInterface(const char* name)
110 {
111 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
112 	if (socket < 0)
113 		return errno;
114 
115 	ifaliasreq request;
116 	memset(&request, 0, sizeof(ifaliasreq));
117 	strlcpy(request.ifra_name, name, IF_NAMESIZE);
118 
119 	if (ioctl(socket, SIOCAIFADDR, &request, sizeof(request)) != 0)
120 		return errno;
121 
122 	return B_OK;
123 }
124 
125 
126 status_t
127 BNetworkRoster::AddInterface(const BNetworkInterface& interface)
128 {
129 	return AddInterface(interface.Name());
130 }
131 
132 
133 status_t
134 BNetworkRoster::RemoveInterface(const char* name)
135 {
136 	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
137 	if (socket < 0)
138 		return errno;
139 
140 	ifreq request;
141 	strlcpy(request.ifr_name, name, IF_NAMESIZE);
142 
143 	request.ifr_addr.sa_family = AF_UNSPEC;
144 
145 	if (ioctl(socket, SIOCDIFADDR, &request, sizeof(request)) != 0)
146 		return errno;
147 
148 	return B_OK;
149 }
150 
151 
152 status_t
153 BNetworkRoster::RemoveInterface(const BNetworkInterface& interface)
154 {
155 	return RemoveInterface(interface.Name());
156 }
157 
158 
159 status_t
160 BNetworkRoster::StartWatching(const BMessenger& target, uint32 eventMask)
161 {
162 	return start_watching_network(eventMask, target);
163 }
164 
165 
166 void
167 BNetworkRoster::StopWatching(const BMessenger& target)
168 {
169 	stop_watching_network(target);
170 }
171 
172 
173 // #pragma mark - private
174 
175 
176 BNetworkRoster::BNetworkRoster()
177 {
178 }
179 
180 
181 BNetworkRoster::~BNetworkRoster()
182 {
183 }
184