xref: /haiku/src/kits/network/libnetapi/NetAddress.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 /*=--------------------------------------------------------------------------=*
2  * NetAddress.cpp -- Implementation of the BNetAddress class.
3  *
4  * Written by S.T. Mansfield (thephantom@mac.com)
5  *
6  * Remarks:
7  *     * In all accessors, address and port are converted from network to
8  *       host byte order.
9  *     * In all mutators, address and port are converted from host to
10  *       network byte order.
11  *     * No trouts were harmed during the development of this class.
12  *=--------------------------------------------------------------------------=*
13  * Copyright (c) 2002, The OpenBeOS project.
14  *
15  * Permission is hereby granted, free of charge, to any person obtaining a
16  * copy of this software and associated documentation files (the "Software"),
17  * to deal in the Software without restriction, including without limitation
18  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19  * and/or sell copies of the Software, and to permit persons to whom the
20  * Software is furnished to do so, subject to the following conditions:
21  *
22  * The above copyright notice and this permission notice shall be included in
23  * all copies or substantial portions of the Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  *=--------------------------------------------------------------------------=*
33  */
34 
35 
36 #include <string.h>
37 #include <netdb.h>
38 #include <arpa/inet.h>
39 #include <netinet/in.h>
40 #include <Message.h>
41 
42 #include <ByteOrder.h>
43 #include <NetAddress.h>
44 
45 /*
46  * AF_INET is 2 or 0 depending on whether or not you use the POSIX
47  * headers.  Never never never compare by value, always use the
48  * #defined token.
49  */
50 #define CTOR_INIT_LIST \
51     BArchivable( ), \
52     m_init( B_NO_INIT ), \
53     fFamily( AF_INET ), \
54     fPort( 0 ), \
55     fAddress( INADDR_ANY )
56 
57 
58 /* BNetAddress
59  *=--------------------------------------------------------------------------=*
60  * Purpose:
61  *     Class constructors that have a direct compliment with one of the SetTo
62  *     methods.
63  *
64  * Input parameters:
65  *     Varies, see the method signature description for the corresponding
66  *     SetTo() method descriptor.
67  */
68 
69 // This bad boy doubles up as the defalt ctor.
70 BNetAddress::BNetAddress( const char* hostname, unsigned short port )
71             : CTOR_INIT_LIST
72 {
73     m_init = SetTo( hostname, port );
74 }
75 
76 BNetAddress::BNetAddress( const struct sockaddr_in& sa )
77             : CTOR_INIT_LIST
78 {
79     m_init = SetTo( sa );
80 }
81 
82 BNetAddress::BNetAddress( in_addr addr, int port )
83             : CTOR_INIT_LIST
84 {
85     m_init = SetTo( addr, port );
86 }
87 
88 BNetAddress::BNetAddress( uint32 addr, int port )
89             : CTOR_INIT_LIST
90 {
91     m_init = SetTo( addr, port );
92 }
93 
94 BNetAddress::BNetAddress( const char* hostname, const char* protocol,
95                           const char* service )
96             : CTOR_INIT_LIST
97 {
98     m_init = SetTo( hostname, protocol, service );
99 }
100 
101 
102 /* BNetAddress
103  *=--------------------------------------------------------------------------=*
104  * Purpose:
105  *     Class copy ctor.
106  *
107  * Input parameter:
108  *     refparam: Instance to copy.
109  */
110 BNetAddress::BNetAddress( const BNetAddress& refparam )
111             : CTOR_INIT_LIST
112 {
113     m_init = clone( refparam );
114 }
115 
116 
117 /* BNetAddress
118  *=--------------------------------------------------------------------------=*
119  * Purpose:
120  *     Ctor to instantiate from serialized data (BMessage).
121  *
122  * Input parameter:
123  *     archive      : Serialized object to instantiate from.
124  */
125 BNetAddress::BNetAddress( BMessage* archive )
126             : CTOR_INIT_LIST
127 {
128     int8 int8_val;
129     int32 int32_val;
130 
131     if ( archive->FindInt8( "bnaddr_family", &int8_val ) != B_OK )
132     {
133         return;
134     }
135     fFamily = int8_val;
136 
137     if ( archive->FindInt8( "bnaddr_port", &int8_val ) != B_OK )
138     {
139         return;
140     }
141     fPort = int8_val;
142 
143     if ( archive->FindInt32( "bnaddr_addr", &int32_val ) != B_OK )
144     {
145         return;
146     }
147     fAddress = int32_val;
148 
149     m_init = B_OK;
150 }
151 
152 
153 /* operator=
154  *=--------------------------------------------------------------------------=*
155  * Purpose:
156  *     Class' assignment operator.
157  *
158  * Input parameter:
159  *     refparam     : Instance to assign from.
160  */
161 BNetAddress& BNetAddress::operator=( const BNetAddress& refparam )
162 {
163     if ( clone( refparam ) == B_OK )
164     {
165         return *this;
166     }
167 }
168 
169 
170 /* ~BNetAddress
171  *=--------------------------------------------------------------------------=*
172  * Purpose:
173  *     Class dtor.
174  */
175 BNetAddress::~BNetAddress( void )
176 {
177     fFamily = fPort = fAddress = 0;
178     m_init = B_NO_INIT;
179 }
180 
181 
182 /* GetAddr
183  *=--------------------------------------------------------------------------=*
184  * Purpose:
185  *     Class accessor.
186  *
187  * Output parameters:
188  *     hostname     : Host name associated with this instance (default: NULL).
189  *                    In this particular implementation, hostname will be an
190  *                    ASCII-fied representation of an IP address.
191  *     port         : Port number associated with this instance
192  *                    (default: NULL).  Will be converted to host byte order
193  *                    here, so it is not necessary to call ntohs() after
194  *                    calling this method.
195  *
196  * Returns:
197  *     B_OK for success, B_NO_INIT if instance was not properly constructed.
198  *
199  * Remarks:
200  *     Hostname and/or port can be NULL; although having them both NULL would
201  *     be a pointless waste of CPU cycles.  ;-)
202  *
203  *     The hostname output parameter can be a variety of things, but in this
204  *     method we convert the IP address to a string.  See the relevant
205  *     documentation about inet_ntoa() for details.
206  *
207  *     Make sure hostname is large enough or you will step on someone
208  *     else's toes.  (Can you say "buffer overflow exploit" boys and girls?)
209  *     You can generally be safe using the MAXHOSTNAMELEN define, which
210  *     defaults to 64 bytes--don't forget to leave room for the NULL!
211  */
212 status_t BNetAddress::GetAddr( char* hostname, unsigned short* port ) const
213 {
214     if ( m_init != B_OK )
215     {
216         return B_NO_INIT;
217     }
218 
219     char* hnBuff;
220     struct in_addr ia;
221 
222     ia.s_addr = fAddress;
223 
224     if ( port != NULL )
225     {
226         *port = ( unsigned short )ntohs( fPort );
227     }
228 
229     if ( hostname != NULL )
230     {
231         hnBuff = inet_ntoa( ia );
232         if ( hnBuff != NULL )
233         {
234             strcpy( hostname, hnBuff );
235         }
236     }
237 
238     return B_OK;
239 }
240 
241 
242 /* GetAddr
243  *=--------------------------------------------------------------------------=*
244  * Purpose:
245  *     Class accessor.
246  *
247  * Output parameter:
248  *     sa           : sockaddr_in struct to be filled.
249  *
250  * Returns:
251  *     B_OK for success, B_NO_INIT if instance was not properly constructed.
252  *
253  * Remarks:
254  *     This method fills in the sin_addr, sin_family, and sin_port fields of
255  *     the output parameter, all other fields are untouched so we can work
256  *     with both POSIX and non-POSIX versions of said struct.  The port and
257  *     address values added to the output parameter are in network byte order.
258  */
259 status_t BNetAddress::GetAddr( struct sockaddr_in& sa ) const
260 {
261     if ( m_init != B_OK )
262     {
263         return B_NO_INIT;
264     }
265 
266     sa.sin_family = ( uint8 )fFamily;
267     sa.sin_port = ( uint8 )fPort;
268     sa.sin_addr.s_addr = ( in_addr_t )fAddress;
269 
270     return B_OK;
271 }
272 
273 
274 /* GetAddr
275  *=--------------------------------------------------------------------------=*
276  * Purpose:
277  *     Class accessor.
278  *
279  * Output parameters:
280  *     addr         : in_addr struct to fill.
281  *     port         : optional port number to fill.
282  *
283  * Returns:
284  *     B_OK for success, B_NO_INIT if instance was not properly constructed.
285  *
286  * Remarks:
287  *     Output parameters will be in network byte order, so it is not
288  *     necessary to call htons after calling this method.
289  */
290 status_t BNetAddress::GetAddr( in_addr& addr, unsigned short* port ) const
291 {
292     if ( m_init != B_OK )
293     {
294         return B_NO_INIT;
295     }
296 
297     addr.s_addr = fAddress;
298 
299     if ( port != NULL )
300     {
301         *port = fPort;
302     }
303 
304     return B_OK;
305 }
306 
307 
308 /* InitCheck
309  *=--------------------------------------------------------------------------=*
310  * Purpose:
311  *     Determine whether or not this instance is properly initialized.
312  *
313  * Returns:
314  *     B_OK if this instance is initialized, B_ERROR if not.
315  */
316 status_t BNetAddress::InitCheck( void )
317 {
318     return ( m_init == B_OK ) ? B_OK : B_ERROR;
319 }
320 
321 
322 /* Archive
323  *=--------------------------------------------------------------------------=*
324  * Purpose:
325  *     Serialize this instance into the passed BMessage parameter.
326  *
327  * Input parameter:
328  *     deep         : [ignored] default==true.
329  *
330  * Output parameter:
331  *     into         : BMessage object to serialize into.
332  *
333  * Returns:
334  *     B_OK/BERROR on success/failure.  Returns B_NO_INIT if instance not
335  *     properly initialized.
336  */
337 status_t BNetAddress::Archive( BMessage* into, bool deep ) const
338 {
339     if ( m_init != B_OK )
340     {
341         return B_NO_INIT;
342     }
343 
344     if ( into->AddInt8( "bnaddr_family", fFamily ) != B_OK )
345     {
346         return B_ERROR;
347     }
348 
349     if ( into->AddInt8( "bnaddr_port", fPort ) != B_OK )
350     {
351         return B_ERROR;
352     }
353 
354     if ( into->AddInt32( "bnaddr_addr", fAddress ) != B_OK )
355     {
356         return B_ERROR;
357     }
358 
359     return B_OK;
360 }
361 
362 
363 /* Instantiate
364  *=--------------------------------------------------------------------------=*
365  * Purpose:
366  *     Un-serialize and instantiate from the passed BMessage parameter.
367  *
368  * Input parameter:
369  *     archive      : Archived BMessage object for (de)serialization.
370  *
371  * Returns:
372  *     NULL if a BNetAddress instance can not be initialized, otherwise
373  *     a new BNetAddress object instantiated from the BMessage parameter.
374  */
375 BArchivable* BNetAddress::Instantiate( BMessage* archive )
376 {
377     if ( !validate_instantiation( archive, "BNetAddress" ) )
378     {
379         return NULL;
380     }
381 
382     BNetAddress* bna = new BNetAddress( archive );
383     if ( bna == NULL )
384     {
385         return NULL;
386     }
387 
388     if ( bna->InitCheck( ) != B_OK )
389     {
390         delete bna;
391         return NULL;
392     }
393 
394     return bna;
395 }
396 
397 
398 /* SetTo
399  *=--------------------------------------------------------------------------=*
400  * Purpose:
401  *     Set hostname and port network address data.
402  *
403  * Input parameters:
404  *     hostname     : Can be one of three things:
405  *                    1. An ASCII-string representation of an IP address.
406  *                    2. A canonical hostname.
407  *                    3. NULL.  If NULL, then by default the address will be
408  *                       set to INADDR_ANY (0.0.0.0).
409  *     port         : Duh.
410  *
411  * Returns:
412  *     B_OK/B_ERROR for success/failure.
413  */
414 status_t BNetAddress::SetTo( const char* hostname, unsigned short port )
415 {
416     struct hostent* HostEnt;
417     in_addr_t       ia;
418 
419     ia = INADDR_ANY;
420 
421     // Try like all git-out to set the address from the given hostname.
422     if ( hostname != NULL )
423     {
424         // See if the string is an ASCII-fied IP address.
425         ia = inet_addr( hostname );
426         if ( ia == INADDR_ANY || ia == ( unsigned long )-1 )
427         {
428             // See if we can resolve the hostname to an IP address.
429             HostEnt = gethostbyname( hostname );
430             if ( HostEnt != NULL )
431             {
432                 ia = *( int * )HostEnt->h_addr_list[0];
433             }
434             else
435             {
436                 return B_ERROR;
437             }
438         }
439     }
440 
441     fFamily  = AF_INET;
442     fPort    = htons( port );
443     fAddress = htonl( ia );
444 
445     return B_OK;
446 }
447 
448 
449 /* SetTo
450  *=--------------------------------------------------------------------------=*
451  * Purpose:
452  *     Set from passed in socket/address info, our preferred mutator.
453  *
454  * Input parameter:
455  *     sa           : Data specifying the host/client connection.
456  *
457  * Returns:
458  *     B_OK.
459  */
460 status_t BNetAddress::SetTo( const struct sockaddr_in& sa )
461 {
462     fFamily  = sa.sin_family;
463     fPort    = htons( sa.sin_port );
464     fAddress = htonl( sa.sin_addr.s_addr );
465 
466     return B_OK;
467 }
468 
469 
470 /* SetTo
471  *=--------------------------------------------------------------------------=*
472  * Purpose:
473  *     Set from passed in address and port.
474  *
475  * Input parameters:
476  *     addr         : IP address in network form.
477  *     port         : Optional port number.
478  *
479  * Returns:
480  *     B_OK.
481  */
482 status_t BNetAddress::SetTo( in_addr addr, int port )
483 {
484     fFamily  = AF_INET;
485     fPort    = htons( port );
486     fAddress = htonl( addr.s_addr );
487 
488     return B_OK;
489 }
490 
491 
492 /* SetTo
493  *=--------------------------------------------------------------------------=*
494  * Purpose:
495  *     Set from passed in address and port.
496  *
497  * Input parameters:
498  *     addr         : Optional IP address in network form.
499  *     port         : Optional port number.
500  *
501  * Returns:
502  *     B_OK.
503  */
504 status_t BNetAddress::SetTo( uint32 addr, int port )
505 {
506     fFamily  = AF_INET;
507     fPort    = htons( port );
508     fAddress = htonl( addr );
509 
510     return B_OK;
511 }
512 
513 
514 /* SetTo
515  *=--------------------------------------------------------------------------=*
516  * Purpose:
517  *     Set from passed in hostname and protocol/service information.
518  *
519  * Input parameters:
520  *     hostname     : Can be one of three things:
521  *                    1. An ASCII-string representation of an IP address.
522  *                    2. A canonical hostname.
523  *                    3. NULL.  If NULL, then by default the address will be
524  *                       set to INADDR_ANY (0.0.0.0).
525  *     protocol     : Datagram type, typically "TCP" or "UDP"
526  *     service      : The name of the service, such as http, ftp, et al.  This
527  *                    must be one of the official service names listed in
528  *                    /etc/services -- but you already knew that because
529  *                    you're doing network/sockets programming, RIIIGHT???.
530  *
531  * Returns:
532  *     B_OK/B_ERROR on success/failure.
533  *
534  * Remarks:
535  *     The protocol and service input parameters must be one of the official
536  *     types listed in /etc/services.  We use these two parameters to
537  *     determine the port number (see getservbyname(3)).  This method will
538  *     fail if the aforementioned precondition is not met.
539  */
540 status_t BNetAddress::SetTo( const char* hostname, const char* protocol,
541                              const char* service )
542 {
543     struct servent* ServiceEntry;
544 
545     ServiceEntry = getservbyname( service, protocol );
546     if ( ServiceEntry == NULL )
547     {
548         return B_ERROR;
549     }
550     // endservent( ); ???
551 
552     return SetTo( hostname, ServiceEntry->s_port );
553 }
554 
555 
556 /* clone
557  *=--------------------------------------------------------------------------=*
558  * Purpose:
559  *     Private copy helper method.
560  *
561  * Input parameter:
562  *     RefParam: Instance to clone.
563  *
564  * Returns:
565  *     B_OK for success, B_NO_INIT if RefParam was not properly constructed.
566  */
567 status_t BNetAddress::clone( const BNetAddress& RefParam )
568 {
569     if ( !RefParam.m_init )
570     {
571         return B_NO_INIT;
572     }
573 
574     fFamily  = RefParam.fFamily;
575     fPort    = RefParam.fPort;
576     fAddress = RefParam.fAddress;
577 
578     return B_OK;
579 }
580 
581 /* Reserved methods, for future evolution */
582 
583 void BNetAddress::_ReservedBNetAddressFBCCruft1()
584 {
585 }
586 
587 void BNetAddress::_ReservedBNetAddressFBCCruft2()
588 {
589 }
590 
591 void BNetAddress::_ReservedBNetAddressFBCCruft3()
592 {
593 }
594 
595 void BNetAddress::_ReservedBNetAddressFBCCruft4()
596 {
597 }
598 
599 void BNetAddress::_ReservedBNetAddressFBCCruft5()
600 {
601 }
602 
603 void BNetAddress::_ReservedBNetAddressFBCCruft6()
604 {
605 }
606 
607 /*=------------------------------------------------------------------- End -=*/
608