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