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