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