xref: /haiku/src/kits/network/libnetapi/NetAddress.cpp (revision 239222b2369c39dc52df52b0a7cdd6cc0a91bc92)
1 /*
2  * Copyright 2002-2006,2008, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Scott T. Mansfield, thephantom@mac.com
7  *		Oliver Tappe, zooey@hirschkaefer.de
8  */
9 
10 /*!
11 	NetAddress.cpp -- Implementation of the BNetAddress class.
12 	Remarks:
13 	 * In all accessors, non-struct output values are converted from network to
14 	   host byte order.
15 	 * In all mutators, non-struct input values are converted from host to
16 	   network byte order.
17 	 * No trouts were harmed during the development of this class.
18 */
19 
20 #include <r5_compatibility.h>
21 
22 #include <ByteOrder.h>
23 #include <NetAddress.h>
24 #include <Message.h>
25 
26 #include <arpa/inet.h>
27 #include <netdb.h>
28 #include <netinet/in.h>
29 #include <new>
30 #include <string.h>
31 
32 
33 BNetAddress::BNetAddress(const char* hostname, unsigned short port)
34 	:
35 	fInit(B_NO_INIT)
36 {
37 	SetTo(hostname, port);
38 }
39 
40 
41 BNetAddress::BNetAddress(const struct sockaddr_in& addr)
42 	:
43 	fInit(B_NO_INIT)
44 {
45 	SetTo(addr);
46 }
47 
48 
49 BNetAddress::BNetAddress(in_addr addr, int port)
50 	:
51 	fInit(B_NO_INIT)
52 {
53 	SetTo(addr, port);
54 }
55 
56 
57 BNetAddress::BNetAddress(uint32 addr, int port)
58 	:
59 	fInit(B_NO_INIT)
60 {
61 	SetTo(addr, port);
62 }
63 
64 
65 BNetAddress::BNetAddress(const char* hostname, const char* protocol,
66 	const char* service)
67 	:
68 	fInit(B_NO_INIT)
69 {
70 	SetTo(hostname, protocol, service);
71 }
72 
73 
74 BNetAddress::BNetAddress(const BNetAddress& other)
75 {
76 	*this = other;
77 }
78 
79 
80 BNetAddress::BNetAddress(BMessage* archive)
81 {
82 	int16 int16value;
83 	if (archive->FindInt16("bnaddr_family", &int16value) != B_OK)
84 		return;
85 
86 	fFamily = int16value;
87 
88 	if (archive->FindInt16("bnaddr_port", &int16value) != B_OK)
89 		return;
90 
91 	fPort = int16value;
92 
93 	if (archive->FindInt32("bnaddr_addr", &fAddress) != B_OK)
94 		return;
95 
96 	fInit = B_OK;
97 }
98 
99 
100 BNetAddress::~BNetAddress()
101 {
102 }
103 
104 
105 BNetAddress&
106 BNetAddress::operator=(const BNetAddress& other)
107 {
108 	fInit = other.fInit;
109 	fFamily = other.fFamily;
110 	fPort = other.fPort;
111 	fAddress = other.fAddress;
112 
113 	return *this;
114 }
115 
116 
117 /* GetAddr
118  *=--------------------------------------------------------------------------=*
119  * Purpose:
120  *		Class accessor.
121  *
122  * Output parameters:
123  *		hostname:		Host name associated with this instance (default: NULL).
124  *						In this particular implementation, hostname will be an
125  *						ASCII-fied representation of an IP address.
126  *
127  *		port:			Port number associated with this instance
128  *						(default: NULL).  Will be converted to host byte order
129  *						here, so it is not necessary to call ntohs() after
130  *						calling this method.
131  *
132  * Returns:
133  *	B_OK for success, B_NO_INIT if instance was not properly constructed.
134  *
135  * Remarks:
136  *		Hostname and/or port can be NULL; although having them both NULL would
137  *		be a pointless waste of CPU cycles.  ;-)
138  *
139  *		The hostname output parameter can be a variety of things, but in this
140  *		method we convert the IP address to a string.  See the relevant
141  *		documentation about inet_ntoa() for details.
142  *
143  *		Make sure hostname is large enough or you will step on someone
144  *		else's toes.  (Can you say "buffer overflow exploit" boys and girls?)
145  *		You can generally be safe using the MAXHOSTNAMELEN define, which
146  *		defaults to 64 bytes--don't forget to leave room for the NULL!
147  */
148 status_t
149 BNetAddress::GetAddr(char* hostname, unsigned short* port) const
150 {
151 	if (fInit != B_OK)
152 		return B_NO_INIT;
153 
154 	if (port != NULL)
155 		*port = ntohs(fPort);
156 
157 	if (hostname != NULL) {
158 		struct in_addr addr;
159 		addr.s_addr = fAddress;
160 
161 		char* text = inet_ntoa(addr);
162 		if (text != NULL)
163 			strcpy(hostname, text);
164 	}
165 
166 	return B_OK;
167 }
168 
169 
170 /* GetAddr
171  *=--------------------------------------------------------------------------=*
172  * Purpose:
173  *		Class accessor.
174  *
175  * Output parameter:
176  *		sa:					sockaddr_in struct to be filled.
177  *
178  * Returns:
179  *		B_OK for success, B_NO_INIT if instance was not properly constructed.
180  *
181  * Remarks:
182  *		This method fills in the sin_addr, sin_family, and sin_port fields of
183  *		the output parameter, all other fields are untouched so we can work
184  *		with both POSIX and non-POSIX versions of said struct.  The port and
185  *		address values added to the output parameter are in network byte order.
186  */
187 status_t BNetAddress::GetAddr(struct sockaddr_in& sa) const
188 {
189 	if (fInit != B_OK)
190 		return B_NO_INIT;
191 
192 	sa.sin_port = fPort;
193 	sa.sin_addr.s_addr = fAddress;
194 	if (check_r5_compatibility()) {
195 		r5_sockaddr_in* r5Addr = (r5_sockaddr_in*)&sa;
196 		if (fFamily == AF_INET)
197 			r5Addr->sin_family = R5_AF_INET;
198 		else
199 			r5Addr->sin_family = fFamily;
200 	} else
201 		sa.sin_family = fFamily;
202 
203 	return B_OK;
204 }
205 
206 
207 /* GetAddr
208  *=--------------------------------------------------------------------------=*
209  * Purpose:
210  *		Class accessor.
211  *
212  * Output parameters:
213  *		addr:			in_addr struct to fill.
214  *		port:			optional port number to fill.
215  *
216  * Returns:
217  *		B_OK for success, B_NO_INIT if instance was not properly constructed.
218  *
219  * Remarks:
220  *		Output port will be in host byte order, but addr will be in the usual
221  *		network byte order (ready to be used by other network functions).
222  */
223 status_t BNetAddress::GetAddr(in_addr& addr, unsigned short* port) const
224 {
225 	if (fInit != B_OK)
226 		return B_NO_INIT;
227 
228 	addr.s_addr = fAddress;
229 
230 	if (port != NULL)
231 		*port = ntohs(fPort);
232 
233 	return B_OK;
234 }
235 
236 
237 /* InitCheck
238  *=--------------------------------------------------------------------------=*
239  * Purpose:
240  *		Determine whether or not this instance is properly initialized.
241  *
242  * Returns:
243  *		B_OK if this instance is initialized, B_ERROR if not.
244  */
245 status_t BNetAddress::InitCheck() const
246 {
247 	return fInit == B_OK ? B_OK : B_ERROR;
248 }
249 
250 
251 status_t BNetAddress::InitCheck()
252 {
253 	return const_cast<const BNetAddress*>(this)->InitCheck();
254 }
255 
256 
257 /* Archive
258  *=--------------------------------------------------------------------------=*
259  * Purpose:
260  *		Serialize this instance into the passed BMessage parameter.
261  *
262  * Input parameter:
263  *		deep:			[ignored] default==true.
264  *
265  * Output parameter:
266  *		into:			BMessage object to serialize into.
267  *
268  * Returns:
269  *		B_OK/BERROR on success/failure.  Returns B_NO_INIT if instance not
270  *		properly initialized.
271  */
272 status_t BNetAddress::Archive(BMessage* into, bool deep) const
273 {
274 	if (fInit != B_OK)
275 		return B_NO_INIT;
276 
277 	if (into->AddInt16("bnaddr_family", fFamily) != B_OK)
278 		return B_ERROR;
279 
280 	if (into->AddInt16("bnaddr_port", fPort) != B_OK)
281 		return B_ERROR;
282 
283 	if (into->AddInt32("bnaddr_addr", fAddress) != B_OK)
284 		return B_ERROR;
285 
286 	return B_OK;
287 }
288 
289 
290 /* Instantiate
291  *=--------------------------------------------------------------------------=*
292  * Purpose:
293  *		Un-serialize and instantiate from the passed BMessage parameter.
294  *
295  * Input parameter:
296  *		archive:		Archived BMessage object for (de)serialization.
297  *
298  * Returns:
299  *		NULL if a BNetAddress instance can not be initialized, otherwise
300  *		a new BNetAddress object instantiated from the BMessage parameter.
301  */
302 BArchivable*
303 BNetAddress::Instantiate(BMessage* archive)
304 {
305 	if (!validate_instantiation(archive, "BNetAddress"))
306 		return NULL;
307 
308 	BNetAddress* address = new (std::nothrow) BNetAddress(archive);
309 	if (address == NULL)
310 		return NULL;
311 
312 	if (address->InitCheck() != B_OK) {
313 		delete address;
314 		return NULL;
315 	}
316 
317 	return address;
318 }
319 
320 
321 /* SetTo
322  *=--------------------------------------------------------------------------=*
323  * Purpose:
324  *	 Set hostname and port network address data.
325  *
326  * Input parameters:
327  *		hostname:		Can be one of three things:
328  *						1. An ASCII-string representation of an IP address.
329  *						2. A canonical hostname.
330  *						3. NULL.  If NULL, then by default the address will be
331  *							set to INADDR_ANY (0.0.0.0).
332  *		port:			Duh.
333  *
334  * Returns:
335  *		B_OK/B_ERROR for success/failure.
336  */
337 status_t
338 BNetAddress::SetTo(const char* hostname, unsigned short port)
339 {
340 	if (hostname == NULL)
341 		return B_ERROR;
342 
343 	in_addr_t addr = INADDR_ANY;
344 
345 	// Try like all git-out to set the address from the given hostname.
346 
347 	// See if the string is an ASCII-fied IP address.
348 	addr = inet_addr(hostname);
349 	if (addr == INADDR_ANY || addr == (unsigned long)-1) {
350 		// See if we can resolve the hostname to an IP address.
351 		struct hostent* host = gethostbyname(hostname);
352 		if (host != NULL)
353 			addr = *(int*)host->h_addr_list[0];
354 		else
355 			return B_ERROR;
356 	}
357 
358 	fFamily = AF_INET;
359 	fPort = htons(port);
360 	fAddress = addr;
361 
362 	return fInit = B_OK;
363 }
364 
365 
366 /*!
367 	Set from passed in sockaddr_in address.
368 
369 	\param addr address
370 	\return B_OK.
371 */
372 status_t
373 BNetAddress::SetTo(const struct sockaddr_in& addr)
374 {
375 	fPort = addr.sin_port;
376 	fAddress = addr.sin_addr.s_addr;
377 
378 	if (check_r5_compatibility()) {
379 		const r5_sockaddr_in* r5Addr = (const r5_sockaddr_in*)&addr;
380 		if (r5Addr->sin_family == R5_AF_INET)
381 			fFamily = AF_INET;
382 		else
383 			fFamily = r5Addr->sin_family;
384 	} else
385 		fFamily = addr.sin_family;
386 
387 	return fInit = B_OK;
388 }
389 
390 
391 /*!
392 	Set from passed in address and port.
393 
394 	\param addr IP address in network form.
395 	\param port Optional port number.
396 
397 	\return B_OK.
398 */
399 status_t
400 BNetAddress::SetTo(in_addr addr, int port)
401 {
402 	fFamily = AF_INET;
403 	fPort = htons((short)port);
404 	fAddress = addr.s_addr;
405 
406 	return fInit = B_OK;
407 }
408 
409 
410 /*!
411 	Set from passed in address and port.
412 
413 	\param addr IP address in network form.
414 	\param port Optional port number.
415 
416 	\return B_OK.
417 */
418 status_t
419 BNetAddress::SetTo(uint32 addr, int port)
420 {
421 	fFamily = AF_INET;
422 	fPort = htons((short)port);
423 	fAddress = addr;
424 
425 	return fInit = B_OK;
426 }
427 
428 
429 /* SetTo
430  *=--------------------------------------------------------------------------=*
431  * Purpose:
432  *		Set from passed in hostname and protocol/service information.
433  *
434  * Input parameters:
435  *		hostname:		Can be one of three things:
436  *						1. An ASCII-string representation of an IP address.
437  *						2. A canonical hostname.
438  *						3. NULL.  If NULL, then by default the address will be
439  *							set to INADDR_ANY (0.0.0.0).
440  *		protocol:		Datagram type, typically "TCP" or "UDP"
441  *		service:		The name of the service, such as http, ftp, et al. This
442  *						must be one of the official service names listed in
443  *						/etc/services -- but you already knew that because
444  *						you're doing network/sockets programming, RIIIGHT???.
445  *
446  * Returns:
447  *		B_OK/B_ERROR on success/failure.
448  *
449  * Remarks:
450  *		The protocol and service input parameters must be one of the official
451  *		types listed in /etc/services.  We use these two parameters to
452  *		determine the port number (see getservbyname(3)).  This method will
453  *		fail if the aforementioned precondition is not met.
454  */
455 status_t
456 BNetAddress::SetTo(const char* hostname, const char* protocol,
457 	const char* service)
458 {
459 	struct servent* serviceEntry = getservbyname(service, protocol);
460 	if (serviceEntry == NULL)
461 		return B_ERROR;
462 
463 	return SetTo(hostname, serviceEntry->s_port);
464 }
465 
466 
467 //	#pragma mark - FBC
468 
469 
470 void BNetAddress::_ReservedBNetAddressFBCCruft1() {}
471 void BNetAddress::_ReservedBNetAddressFBCCruft2() {}
472 void BNetAddress::_ReservedBNetAddressFBCCruft3() {}
473 void BNetAddress::_ReservedBNetAddressFBCCruft4() {}
474 void BNetAddress::_ReservedBNetAddressFBCCruft5() {}
475 void BNetAddress::_ReservedBNetAddressFBCCruft6() {}
476