xref: /haiku/src/add-ons/kernel/file_systems/netfs/shared/NetAddress.cpp (revision 81ec973846ea4816c53ed8901822e43c8b06878d)
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, "%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32
148 			":%hu", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff,
149 			GetPort());
150 	} else {
151 		sprintf(buffer, "%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32 ".%" B_PRIu32,
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(),
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 protected:
221 	virtual void LastReferenceReleased()
222 	{
223 		// don't delete
224 	}
225 
226 private:
227 	Locker	fLock;
228 };
229 
230 // constructor
231 NetAddressResolver::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
252 NetAddressResolver::~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
265 status_t
266 NetAddressResolver::InitCheck() const
267 {
268 	return (fResolver ? B_OK : B_NO_INIT);
269 }
270 
271 // GetAddress
272 status_t
273 NetAddressResolver::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
283 void
284 NetAddressResolver::_Lock()
285 {
286 	while (atomic_add(&sLockCounter, 1) > 0) {
287 		atomic_add(&sLockCounter, -1);
288 		snooze(10000);
289 	}
290 }
291 
292 // _Unlock
293 void
294 NetAddressResolver::_Unlock()
295 {
296 	atomic_add(&sLockCounter, -1);
297 }
298 
299 
300 // sResolver
301 NetAddressResolver::Resolver* volatile NetAddressResolver::sResolver = NULL;
302 
303 // sLockCounter
304 int32 NetAddressResolver::sLockCounter = 0;
305