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
24NetAddress::NetAddress()
25{
26	fAddress.sin_family = AF_INET;
27	fAddress.sin_addr.s_addr = 0;
28	fAddress.sin_port = 0;
29}
30
31// constructor
32NetAddress::NetAddress(const sockaddr_in& address)
33{
34	fAddress = address;
35}
36
37// copy constructor
38NetAddress::NetAddress(const NetAddress& address)
39{
40	fAddress = address.fAddress;
41}
42
43// SetIP
44void
45NetAddress::SetIP(int32 address)
46{
47	fAddress.sin_addr.s_addr = B_HOST_TO_BENDIAN_INT32(address);
48}
49
50// GetIP
51int32
52NetAddress::GetIP() const
53{
54	return B_BENDIAN_TO_HOST_INT32(fAddress.sin_addr.s_addr);
55}
56
57// SetPort
58void
59NetAddress::SetPort(uint16 port)
60{
61	fAddress.sin_port = B_HOST_TO_BENDIAN_INT32(port);
62}
63
64// GetPort
65uint16
66NetAddress::GetPort() const
67{
68	return B_BENDIAN_TO_HOST_INT16(fAddress.sin_port);
69}
70
71// SetAddress
72void
73NetAddress::SetAddress(const sockaddr_in& address)
74{
75	fAddress = address;
76}
77
78// GetAddress
79const sockaddr_in&
80NetAddress::GetAddress() const
81{
82	return fAddress;
83}
84
85// IsLocal
86bool
87NetAddress::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
139status_t
140NetAddress::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
158uint32
159NetAddress::GetHashCode() const
160{
161	return (fAddress.sin_addr.s_addr * 31 + fAddress.sin_port);
162}
163
164// =
165NetAddress&
166NetAddress::operator=(const NetAddress& address)
167{
168	fAddress = address.fAddress;
169	return *this;
170}
171
172// ==
173bool
174NetAddress::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// !=
181bool
182NetAddress::operator!=(const NetAddress& address) const
183{
184	return !(*this == address);
185}
186
187
188// #pragma mark -
189
190// Resolver
191class NetAddressResolver::Resolver : public BReferenceable {
192public:
193	Resolver()
194		: BReferenceable(),
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
220protected:
221	virtual void LastReferenceReleased()
222	{
223		// don't delete
224	}
225
226private:
227	Locker	fLock;
228};
229
230// constructor
231NetAddressResolver::NetAddressResolver()
232{
233	_Lock();
234	// initialize static instance, if not done yet
235	if (sResolver) {
236		sResolver->AcquireReference();
237		fResolver = sResolver;
238	} else {
239		sResolver = new(std::nothrow) Resolver;
240		if (sResolver) {
241			if (sResolver->InitCheck() != B_OK) {
242				delete sResolver;
243				sResolver = NULL;
244			}
245		}
246		fResolver = sResolver;
247	}
248	_Unlock();
249}
250
251// destructor
252NetAddressResolver::~NetAddressResolver()
253{
254	if (fResolver) {
255		_Lock();
256		if (sResolver->ReleaseReference() == 1) {
257			delete sResolver;
258			sResolver = NULL;
259		}
260		_Unlock();
261	}
262}
263
264// InitCheck
265status_t
266NetAddressResolver::InitCheck() const
267{
268	return (fResolver ? B_OK : B_NO_INIT);
269}
270
271// GetAddress
272status_t
273NetAddressResolver::GetHostAddress(const char* hostName, NetAddress* address)
274{
275	if (!fResolver)
276		return B_NO_INIT;
277	if (!hostName || !address)
278		return B_BAD_VALUE;
279	return fResolver->GetHostAddress(hostName, address);
280}
281
282// _Lock
283void
284NetAddressResolver::_Lock()
285{
286	while (atomic_add(&sLockCounter, 1) > 0) {
287		atomic_add(&sLockCounter, -1);
288		snooze(10000);
289	}
290}
291
292// _Unlock
293void
294NetAddressResolver::_Unlock()
295{
296	atomic_add(&sLockCounter, -1);
297}
298
299
300// sResolver
301NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL;
302
303// sLockCounter
304vint32 NetAddressResolver::sLockCounter = 0;
305