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