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
33BNetAddress::BNetAddress(const char* hostname, unsigned short port)
34	:
35	fInit(B_NO_INIT)
36{
37	SetTo(hostname, port);
38}
39
40
41BNetAddress::BNetAddress(const struct sockaddr_in& addr)
42	:
43	fInit(B_NO_INIT)
44{
45	SetTo(addr);
46}
47
48
49BNetAddress::BNetAddress(in_addr addr, int port)
50	:
51	fInit(B_NO_INIT)
52{
53	SetTo(addr, port);
54}
55
56
57BNetAddress::BNetAddress(uint32 addr, int port)
58	:
59	fInit(B_NO_INIT)
60{
61	SetTo(addr, port);
62}
63
64
65BNetAddress::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
74BNetAddress::BNetAddress(const BNetAddress& other)
75{
76	*this = other;
77}
78
79
80BNetAddress::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
100BNetAddress::~BNetAddress()
101{
102}
103
104
105BNetAddress&
106BNetAddress::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 */
148status_t
149BNetAddress::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 */
187status_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 */
223status_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 */
245status_t BNetAddress::InitCheck() const
246{
247	return fInit == B_OK ? B_OK : B_ERROR;
248}
249
250
251status_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 */
272status_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 */
302BArchivable*
303BNetAddress::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 */
337status_t
338BNetAddress::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 == (in_addr_t)-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*/
372status_t
373BNetAddress::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*/
399status_t
400BNetAddress::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*/
418status_t
419BNetAddress::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 */
455status_t
456BNetAddress::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
470void BNetAddress::_ReservedBNetAddressFBCCruft1() {}
471void BNetAddress::_ReservedBNetAddressFBCCruft2() {}
472void BNetAddress::_ReservedBNetAddressFBCCruft3() {}
473void BNetAddress::_ReservedBNetAddressFBCCruft4() {}
474void BNetAddress::_ReservedBNetAddressFBCCruft5() {}
475void BNetAddress::_ReservedBNetAddressFBCCruft6() {}
476