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