xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/NetAddress.cpp (revision ed24eb5ff12640d052171c6a7feba37fab8a75d1)
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
25 NetAddress::NetAddress()
26 {
27 	fAddress.sin_family = AF_INET;
28 	fAddress.sin_addr.s_addr = 0;
29 	fAddress.sin_port = 0;
30 }
31 
32 // constructor
33 NetAddress::NetAddress(const sockaddr_in& address)
34 {
35 	fAddress = address;
36 }
37 
38 // copy constructor
39 NetAddress::NetAddress(const NetAddress& address)
40 {
41 	fAddress = address.fAddress;
42 }
43 
44 // SetIP
45 void
46 NetAddress::SetIP(int32 address)
47 {
48 	fAddress.sin_addr.s_addr = B_HOST_TO_BENDIAN_INT32(address);
49 }
50 
51 // GetIP
52 int32
53 NetAddress::GetIP() const
54 {
55 	return B_BENDIAN_TO_HOST_INT32(fAddress.sin_addr.s_addr);
56 }
57 
58 // SetPort
59 void
60 NetAddress::SetPort(uint16 port)
61 {
62 	fAddress.sin_port = B_HOST_TO_BENDIAN_INT32(port);
63 }
64 
65 // GetPort
66 uint16
67 NetAddress::GetPort() const
68 {
69 	return B_BENDIAN_TO_HOST_INT16(fAddress.sin_port);
70 }
71 
72 // SetAddress
73 void
74 NetAddress::SetAddress(const sockaddr_in& address)
75 {
76 	fAddress = address;
77 }
78 
79 // GetAddress
80 const sockaddr_in&
81 NetAddress::GetAddress() const
82 {
83 	return fAddress;
84 }
85 
86 // IsLocal
87 bool
88 NetAddress::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
140 status_t
141 NetAddress::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
159 uint32
160 NetAddress::GetHashCode() const
161 {
162 	return (fAddress.sin_addr.s_addr * 31 + fAddress.sin_port);
163 }
164 
165 // =
166 NetAddress&
167 NetAddress::operator=(const NetAddress& address)
168 {
169 	fAddress = address.fAddress;
170 	return *this;
171 }
172 
173 // ==
174 bool
175 NetAddress::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 // !=
182 bool
183 NetAddress::operator!=(const NetAddress& address) const
184 {
185 	return !(*this == address);
186 }
187 
188 
189 // #pragma mark -
190 
191 // Resolver
192 class NetAddressResolver::Resolver : public BReferenceable {
193 public:
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 
221 protected:
222 	virtual void LastReferenceReleased()
223 	{
224 		// don't delete
225 	}
226 
227 private:
228 	Locker	fLock;
229 };
230 
231 // constructor
232 NetAddressResolver::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
253 NetAddressResolver::~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
266 status_t
267 NetAddressResolver::InitCheck() const
268 {
269 	return (fResolver ? B_OK : B_NO_INIT);
270 }
271 
272 // GetAddress
273 status_t
274 NetAddressResolver::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
284 void
285 NetAddressResolver::_Lock()
286 {
287 	while (atomic_add(&sLockCounter, 1) > 0) {
288 		atomic_add(&sLockCounter, -1);
289 		snooze(10000);
290 	}
291 }
292 
293 // _Unlock
294 void
295 NetAddressResolver::_Unlock()
296 {
297 	atomic_add(&sLockCounter, -1);
298 }
299 
300 
301 // sResolver
302 NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL;
303 
304 // sLockCounter
305 int32 NetAddressResolver::sLockCounter = 0;
306