xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/NetAddress.cpp (revision 4052469d007d17112b0fdf8814c92c77414a1398)
1 // NetAddress.cpp
2 
3 #include <new>
4 #include <netdb.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 
8 #if defined(HAIKU_TARGET_PLATFORM_DANO) || defined(HAIKU_TARGET_PLATFORM_DANO)
9 #	include <net/route.h>
10 #	include <sys/sockio.h>
11 #	include <stdlib.h>
12 #endif
13 
14 #include <AutoLocker.h>
15 #include <ByteOrder.h>
16 #include <HashString.h>
17 #include <Referenceable.h>
18 
19 #include "Compatibility.h"
20 #include "Locker.h"
21 #include "NetAddress.h"
22 
23 // constructor
24 NetAddress::NetAddress()
25 {
26 	fAddress.sin_family = AF_INET;
27 	fAddress.sin_addr.s_addr = 0;
28 	fAddress.sin_port = 0;
29 }
30 
31 // constructor
32 NetAddress::NetAddress(const sockaddr_in& address)
33 {
34 	fAddress = address;
35 }
36 
37 // copy constructor
38 NetAddress::NetAddress(const NetAddress& address)
39 {
40 	fAddress = address.fAddress;
41 }
42 
43 // SetIP
44 void
45 NetAddress::SetIP(int32 address)
46 {
47 	fAddress.sin_addr.s_addr = B_HOST_TO_BENDIAN_INT32(address);
48 }
49 
50 // GetIP
51 int32
52 NetAddress::GetIP() const
53 {
54 	return B_BENDIAN_TO_HOST_INT32(fAddress.sin_addr.s_addr);
55 }
56 
57 // SetPort
58 void
59 NetAddress::SetPort(uint16 port)
60 {
61 	fAddress.sin_port = B_HOST_TO_BENDIAN_INT32(port);
62 }
63 
64 // GetPort
65 uint16
66 NetAddress::GetPort() const
67 {
68 	return B_BENDIAN_TO_HOST_INT16(fAddress.sin_port);
69 }
70 
71 // SetAddress
72 void
73 NetAddress::SetAddress(const sockaddr_in& address)
74 {
75 	fAddress = address;
76 }
77 
78 // GetAddress
79 const sockaddr_in&
80 NetAddress::GetAddress() const
81 {
82 	return fAddress;
83 }
84 
85 // IsLocal
86 bool
87 NetAddress::IsLocal() const
88 {
89 	// special address?
90 	if (fAddress.sin_addr.s_addr == INADDR_ANY
91 		|| fAddress.sin_addr.s_addr == INADDR_BROADCAST) {
92 		return false;
93 	}
94 	// create a socket and try to bind it to a port of this address
95 	int fd = socket(AF_INET, SOCK_DGRAM, 0);
96 	if (fd < 0)
97 		return false;
98 #if defined(HAIKU_TARGET_PLATFORM_DANO)
99 	// BONE does allow you to bind to any address!
100 	// Therefore, we iterate over all routes, and see if there are any local
101 	// ones for this address.
102 
103 	bool result = false;
104 	uint32 count;
105 	if (ioctl(fd, SIOCGRTSIZE, &count) == 0) {
106 		route_req_t* routes = (route_req_t*)malloc(count * sizeof(route_req_t));
107 		if (routes != NULL) {
108 			route_table_req table;
109 			table.rrtp = routes;
110 			table.len = count * sizeof(route_req_t);
111 			table.cnt = count;
112 			if (ioctl(fd, SIOCGRTTABLE, &table) == 0) {
113 				for (uint32 i = 0; i < table.cnt; i++) {
114 					if ((routes[i].flags & RTF_LOCAL) == 0)
115 						continue;
116 					if (((sockaddr_in*)&routes[i].dst)->sin_addr.s_addr
117 							== fAddress.sin_addr.s_addr) {
118 						result = true;
119 						break;
120 					}
121 				}
122 			}
123 			free(routes);
124 		}
125 	}
126 #else
127 	// bind it to a port
128 	sockaddr_in addr = fAddress;
129 	addr.sin_port = 0;
130 	bool result = (bind(fd, (sockaddr*)&addr, sizeof(addr)) == 0);
131 #endif
132 	closesocket(fd);
133 
134 	return result;
135 }
136 
137 
138 // GetString
139 status_t
140 NetAddress::GetString(HashString* string, bool includePort) const
141 {
142 	if (!string)
143 		return B_BAD_VALUE;
144 	char buffer[32];
145 	uint32 ip = GetIP();
146 	if (includePort) {
147 		sprintf(buffer, "%lu.%lu.%lu.%lu:%hu",
148 			ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff,
149 			GetPort());
150 	} else {
151 		sprintf(buffer, "%lu.%lu.%lu.%lu",
152 			ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
153 	}
154 	return (string->SetTo(buffer) ? B_OK : B_NO_MEMORY);
155 }
156 
157 // GetHashCode
158 uint32
159 NetAddress::GetHashCode() const
160 {
161 	return (fAddress.sin_addr.s_addr * 31 + fAddress.sin_port);
162 }
163 
164 // =
165 NetAddress&
166 NetAddress::operator=(const NetAddress& address)
167 {
168 	fAddress = address.fAddress;
169 	return *this;
170 }
171 
172 // ==
173 bool
174 NetAddress::operator==(const NetAddress& address) const
175 {
176 	return (fAddress.sin_addr.s_addr == address.fAddress.sin_addr.s_addr
177 		&& fAddress.sin_port == address.fAddress.sin_port);
178 }
179 
180 // !=
181 bool
182 NetAddress::operator!=(const NetAddress& address) const
183 {
184 	return !(*this == address);
185 }
186 
187 
188 // #pragma mark -
189 
190 // Resolver
191 class NetAddressResolver::Resolver : public BReferenceable {
192 public:
193 	Resolver()
194 		: BReferenceable(false),
195 		  fLock()
196 	{
197 	}
198 
199 	status_t InitCheck() const
200 	{
201 		return (fLock.Sem() >= 0 ? B_OK : B_NO_INIT);
202 	}
203 
204 	status_t GetHostAddress(const char* hostName, NetAddress* address)
205 	{
206 		AutoLocker<Locker> _(fLock);
207 		struct hostent* host = gethostbyname(hostName);
208 		if (!host)
209 			return h_errno;
210 		if (host->h_addrtype != AF_INET || !host->h_addr_list[0])
211 			return B_BAD_VALUE;
212 		sockaddr_in addr;
213 		addr.sin_family = AF_INET;
214 		addr.sin_port = 0;
215 		addr.sin_addr = *(in_addr*)host->h_addr_list[0];
216 		*address = addr;
217 		return B_OK;
218 	}
219 
220 private:
221 	Locker	fLock;
222 };
223 
224 // constructor
225 NetAddressResolver::NetAddressResolver()
226 {
227 	_Lock();
228 	// initialize static instance, if not done yet
229 	if (sResolver) {
230 		sResolver->AddReference();
231 		fResolver = sResolver;
232 	} else {
233 		sResolver = new(std::nothrow) Resolver;
234 		if (sResolver) {
235 			if (sResolver->InitCheck() != B_OK) {
236 				delete sResolver;
237 				sResolver = NULL;
238 			}
239 		}
240 		fResolver = sResolver;
241 	}
242 	_Unlock();
243 }
244 
245 // destructor
246 NetAddressResolver::~NetAddressResolver()
247 {
248 	if (fResolver) {
249 		_Lock();
250 		if (sResolver->RemoveReference()) {
251 			delete sResolver;
252 			sResolver = NULL;
253 		}
254 		_Unlock();
255 	}
256 }
257 
258 // InitCheck
259 status_t
260 NetAddressResolver::InitCheck() const
261 {
262 	return (fResolver ? B_OK : B_NO_INIT);
263 }
264 
265 // GetAddress
266 status_t
267 NetAddressResolver::GetHostAddress(const char* hostName, NetAddress* address)
268 {
269 	if (!fResolver)
270 		return B_NO_INIT;
271 	if (!hostName || !address)
272 		return B_BAD_VALUE;
273 	return fResolver->GetHostAddress(hostName, address);
274 }
275 
276 // _Lock
277 void
278 NetAddressResolver::_Lock()
279 {
280 	while (atomic_add(&sLockCounter, 1) > 0) {
281 		atomic_add(&sLockCounter, -1);
282 		snooze(10000);
283 	}
284 }
285 
286 // _Unlock
287 void
288 NetAddressResolver::_Unlock()
289 {
290 	atomic_add(&sLockCounter, -1);
291 }
292 
293 
294 // sResolver
295 NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL;
296 
297 // sLockCounter
298 vint32 NetAddressResolver::sLockCounter = 0;
299