1 /******************************************************************************* 2 3 Declaration of and wrappers for the addrinfo address lookup API. 4 5 Copyright: 6 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *******************************************************************************/ 15 16 module ocean.sys.socket.AddrInfo; 17 18 19 import ocean.transition; 20 21 import ocean.stdc.posix.netinet.in_: sockaddr, socklen_t, 22 sockaddr_in, AF_INET, INET_ADDRSTRLEN, 23 sockaddr_in6, AF_INET6, INET6_ADDRSTRLEN, 24 SOCK_STREAM, IPPROTO_TCP; 25 26 import ocean.stdc.posix.arpa.inet: inet_ntop, inet_pton, ntohs, htons, htonl; 27 28 import core.stdc.errno: errno, EAFNOSUPPORT; 29 30 import core.stdc.string: strlen; 31 32 import ocean.core.Array: concat; 33 34 import ocean.core.TypeConvert; 35 36 import ocean.core.Verify; 37 38 /******************************************************************************* 39 40 Address information struct as returned by getaddrinfo(). 41 42 *******************************************************************************/ 43 44 struct addrinfo 45 { 46 /*************************************************************************** 47 48 getaddrinfo() flags. 49 50 ***************************************************************************/ 51 52 enum Flags 53 { 54 None = 0, 55 AI_PASSIVE = 1 << 0, /// Socket address is intended for `bind`. 56 AI_CANONNAME = 1 << 1, /// Request for canonical name. 57 AI_NUMERICHOST = 1 << 2, /// Don't use name resolution. 58 AI_V4MAPPED = 1 << 3, /// IPv4 mapped addresses are acceptable. 59 AI_ALL = 1 << 4, /// Return IPv4 mapped and IPv6 addresses. 60 AI_ADDRCONFIG = 1 << 5, /// Use configuration of this host to choose returned address type. 61 AI_IDN = 1 << 6, /// IDN encode input (assuming it is encoded in the current locale's character set) before looking it up. 62 AI_CANONIDN = 1 << 7, /// Translate canonical name from IDN format. 63 AI_IDN_ALLOW_UNASSIGNED = 1 << 8, /// Don't reject unassigned Unicode code points. 64 AI_IDN_USE_STD3_ASCII_RULES = 1 << 9 /// Validate strings according to STD3 rules. 65 66 } 67 68 /*************************************************************************** 69 70 Error codes returned by getaddrinfo() (not passed via errno). 71 72 ***************************************************************************/ 73 74 enum ErrorCode 75 { 76 Success = 0, 77 EAI_BADFLAGS = -1, /// Invalid value for ai_flags field. 78 EAI_NONAME = -2, /// NAME or SERVICE is unknown. 79 EAI_AGAIN = -3, /// Temporary failure in name resolution. 80 EAI_FAIL = -4, /// Non-recoverable failure in name res. 81 EAI_FAMILY = -6, /// `ai_family` not supported. 82 EAI_SOCKTYPE = -7, /// `ai_socktype` not supported. 83 EAI_SERVICE = -8, /// SERVICE not supported for `ai_socktype`. 84 EAI_MEMORY = -10, /// Memory allocation failure. 85 EAI_SYSTEM = -11, /// System error returned in `errno`. 86 EAI_OVERFLOW = -12, /// Argument buffer overflow. 87 EAI_NODATA = -5, /// No address associated with NAME. 88 EAI_ADDRFAMILY = -9, /// Address family for NAME not supported. 89 EAI_INPROGRESS = -100, /// Processing request in progress. 90 EAI_CANCELED = -101, /// Request canceled. 91 EAI_NOTCANCELED = -102, /// Request not canceled. 92 EAI_ALLDONE = -103, /// All requests done. 93 EAI_INTR = -104, /// Interrupted by a signal. 94 EAI_IDN_ENCODE = -105, /// IDN encoding failed. 95 } 96 97 /*************************************************************************** 98 99 Data fields. 100 101 ***************************************************************************/ 102 103 Flags ai_flags; 104 int ai_family, 105 ai_socktype, 106 ai_protocol; 107 socklen_t ai_addrlen; // The manpage says size_t: WRONG! 108 sockaddr* ai_addr; 109 char* ai_canonname; 110 typeof ((&this)) ai_next; 111 112 alias .INET6_ADDRSTRLEN INET6_ADDRSTRLEN; 113 alias .INET_ADDRSTRLEN INET_ADDRSTRLEN; 114 115 /*************************************************************************** 116 117 Obtains the current IP address in standard notation. 118 119 Params: 120 dst = destination buffer 121 122 Returns: 123 a slice to the resulting IP address string in dst on success or null 124 on error. On error errno is set appropriately. 125 126 Errors: 127 EAFNOSUPPORT: The address family is not supported (AF_INET/IPv4 or 128 AF_INET6/IPv6). 129 130 In: 131 - this.ai_addr must not be null: this instance should have been 132 obtained by getaddrinfo() or manually initialised. 133 - dst.length must be at least the required address length for the 134 address family, INET_ADDRSTRLEN for IPv4 or INET6_ADDRSTRLEN for 135 IPv6. 136 137 Out: 138 If the resulting slice is not null, it slices dst from the 139 beginning. 140 141 ***************************************************************************/ 142 143 mstring ipAddress ( mstring dst ) 144 out (result) 145 { 146 if (result.length) assert (result.ptr is dst.ptr); 147 } 148 body 149 { 150 void sanity_check ( ) 151 { 152 verify((&this).ai_addr !is null); 153 154 switch ((&this).ai_family) 155 { 156 case AF_INET: 157 verify( 158 dst.length >= INET_ADDRSTRLEN, 159 "dst.length expected to be at least " 160 ~ INET_ADDRSTRLEN.stringof 161 ); 162 break; 163 164 case AF_INET6: 165 verify( 166 dst.length >= INET6_ADDRSTRLEN, 167 "dst.length expected to be at least " 168 ~ INET6_ADDRSTRLEN.stringof 169 ); 170 break; 171 172 default: // will fail with EAFNOSUPPORT anyway 173 } 174 } 175 176 sanity_check(); 177 178 void* addr; 179 180 switch ((&this).ai_family) 181 { 182 case AF_INET: 183 addr = &(*cast (sockaddr_in*) (&this).ai_addr).sin_addr; 184 break; 185 186 case AF_INET6: 187 addr = &(*cast (sockaddr_in6*) (&this).ai_addr).sin6_addr; 188 break; 189 190 default: 191 .errno = EAFNOSUPPORT; // inet_ntop() would do the same 192 return null; 193 } 194 195 auto address_p = .inet_ntop((&this).ai_family, addr, dst.ptr, 196 castFrom!(size_t).to!(int)(dst.length)); 197 // inet_ntop returns const pointer even if spec says it will always 198 // use `dst` memory. Using `dst` directly to avoid casts. 199 return address_p ? dst.ptr[0 .. strlen(dst.ptr)] : null; 200 } 201 202 /************************************************************************** 203 204 Obtains the current port number. 205 206 Returns: 207 the current port number. 208 209 Errors: 210 EAFNOSUPPORT: The address family is not supported (AF_INET/IPv4 or 211 AF_INET6/IPv6). 212 213 In: 214 this.ai_addr must not be null: this instance should have been 215 obtained by getaddrinfo() or manually initialised. 216 217 **************************************************************************/ 218 219 ushort port ( ) 220 { 221 verify((&this).ai_addr !is null); 222 .errno = 0; 223 224 switch ((&this).ai_family) 225 { 226 case AF_INET: 227 return .ntohs((cast (sockaddr_in*) (&this).ai_addr).sin_port); 228 229 case AF_INET6: 230 return .ntohs((cast (sockaddr_in6*) (&this).ai_addr).sin6_port); 231 232 default: 233 .errno = EAFNOSUPPORT; 234 return 0; 235 } 236 } 237 238 /************************************************************************** 239 240 Obtains the current canonical name. 241 242 Returns: 243 the current canonical name or null. 244 245 **************************************************************************/ 246 247 char[] canonname ( ) 248 { 249 return (&this).ai_canonname? (&this).ai_canonname[0 .. strlen((&this).ai_canonname)] : null; 250 } 251 252 /************************************************************************** 253 254 'foreach' iteration over the linked list of instances of this struct; 255 starting with this instance. 256 257 Do not change any of the pointer struct members. 258 259 **************************************************************************/ 260 261 int opApply ( scope int delegate ( ref typeof (this) info ) dg ) 262 { 263 int result = 0; 264 265 for (typeof ((&this)) info = (&this); info && !result; info = info.ai_next) 266 { 267 result = dg(*info); 268 } 269 270 return result; 271 } 272 } 273 274 extern (C) 275 { 276 /************************************************************************** 277 278 Obtains the error message for errcode. 279 280 Params: 281 errcode = error code returned by getaddrinfo() 282 283 Returns: 284 the error message for errcode. 285 286 **************************************************************************/ 287 288 public char* gai_strerror(addrinfo.ErrorCode errcode); 289 290 /************************************************************************** 291 292 Given node and service, which identify an Internet host and a service, 293 getaddrinfo() returns one or more addrinfo structures, each of which 294 contains an Internet address that can be specified in a call to bind(2) 295 or connect(2). The getaddrinfo() function combines the functionality 296 provided by the getservbyname(3) and getservbyport(3) functions into a 297 single interface, but unlike the latter functions, getaddrinfo() is 298 reentrant and allows programs to eliminate IPv4-versus-IPv6 dependen‐ 299 cies. 300 301 The addrinfo structure used by getaddrinfo() contains the following 302 fields: 303 304 struct addrinfo { 305 int ai_flags; 306 int ai_family; 307 int ai_socktype; 308 int ai_protocol; 309 size_t ai_addrlen; 310 struct sockaddr *ai_addr; 311 char *ai_canonname; 312 struct addrinfo *ai_next; 313 }; 314 315 The hints argument points to an addrinfo structure that specifies crite‐ 316 ria for selecting the socket address structures returned in the list 317 pointed to by res. If hints is not NULL it points to an addrinfo struc‐ 318 ture whose ai_family, ai_socktype, and ai_protocol specify criteria that 319 limit the set of socket addresses returned by getaddrinfo(), as follows: 320 321 ai_family This field specifies the desired address family for the 322 returned addresses. Valid values for this field include 323 AF_INET and AF_INET6. The value AF_UNSPEC indicates that 324 getaddrinfo() should return socket addresses for any address 325 family (either IPv4 or IPv6, for example) that can be used 326 with node and service. 327 328 ai_socktype This field specifies the preferred socket type, for example 329 SOCK_STREAM or SOCK_DGRAM. Specifying 0 in this field indi‐ 330 cates that socket addresses of any type can be returned by 331 getaddrinfo(). 332 333 ai_protocol This field specifies the protocol for the returned socket 334 addresses. Specifying 0 in this field indicates that socket 335 addresses with any protocol can be returned by getad‐ 336 drinfo(). 337 338 ai_flags This field specifies additional options, described below. 339 Multiple flags are specified by bitwise OR-ing them 340 together. 341 342 All the other fields in the structure pointed to by hints must contain 343 either 0 or a null pointer, as appropriate. Specifying hints as NULL is 344 equivalent to setting ai_socktype and ai_protocol to 0; ai_family to 345 AF_UNSPEC; and ai_flags to (AI_V4MAPPED | AI_ADDRCONFIG). 346 347 node specifies either a numerical network address (for IPv4, numbers- 348 and-dots notation as supported by inet_aton(3); for IPv6, hexadecimal 349 string format as supported by inet_pton(3)), or a network hostname, 350 contains the AI_NUMERICHOST flag then node must be a numerical network 351 address. The AI_NUMERICHOST flag suppresses any potentially lengthy 352 network host address lookups. 353 354 If the AI_PASSIVE flag is specified in hints.ai_flags, and node is NULL, 355 then the returned socket addresses will be suitable for bind(2)ing a 356 socket that will accept(2) connections. The returned socket address 357 will contain the "wildcard address" (INADDR_ANY for IPv4 addresses, 358 IN6ADDR_ANY_INIT for IPv6 address). The wildcard address is used by 359 applications (typically servers) that intend to accept connections on 360 any of the hosts's network addresses. If node is not NULL, then the 361 AI_PASSIVE flag is ignored. 362 363 If the AI_PASSIVE flag is not set in hints.ai_flags, then the returned 364 socket addresses will be suitable for use with connect(2), sendto(2), or 365 sendmsg(2). If node is NULL, then the network address will be set to 366 the loopback interface address (INADDR_LOOPBACK for IPv4 addresses, 367 IN6ADDR_LOOPBACK_INIT for IPv6 address); this is used by applications 368 that intend to communicate with peers running on the same host. 369 370 service sets the port in each returned address structure. If this argu‐ 371 ment is a service name (see services(5)), it is translated to the corre‐ 372 sponding port number. This argument can also be specified as a decimal 373 number, which is simply converted to binary. If service is NULL, then 374 the port number of the returned socket addresses will be left uninitial‐ 375 ized. If AI_NUMERICSERV is specified in hints.ai_flags and service is 376 not NULL, then service must point to a string containing a numeric port 377 number. This flag is used to inhibit the invocation of a name resolu‐ 378 tion service in cases where it is known not to be required. 379 380 Either node or service, but not both, may be NULL. 381 382 The getaddrinfo() function allocates and initializes a linked list of 383 addrinfo structures, one for each network address that matches node and 384 service, subject to any restrictions imposed by hints, and returns a 385 pointer to the start of the list in res. The items in the linked list 386 are linked by the ai_next field. 387 388 There are several reasons why the linked list may have more than one 389 addrinfo structure, including: the network host is multihomed, accessi‐ 390 ble over multiple protocols (e.g. both AF_INET and AF_INET6); or the 391 same service is available from multiple socket types (one SOCK_STREAM 392 address and another SOCK_DGRAM address, for example). Normally, the 393 application should try using the addresses in the order in which they 394 are returned. The sorting function used within getaddrinfo() is defined 395 in RFC 3484; the order can be tweaked for a particular system by editing 396 /etc/gai.conf (available since glibc 2.5). 397 398 If hints.ai_flags includes the AI_CANONNAME flag, then the ai_canonname 399 field of the first of the addrinfo structures in the returned list is 400 set to point to the official name of the host. 401 402 The remaining fields of each returned addrinfo structure are initialized 403 as follows: 404 405 * The ai_family, ai_socktype, and ai_protocol fields return the socket 406 creation parameters (i.e., these fields have the same meaning as the 407 corresponding arguments of socket(2)). For example, ai_family might 408 return AF_INET or AF_INET6; ai_socktype might return SOCK_DGRAM or 409 SOCK_STREAM; and ai_protocol returns the protocol for the socket. 410 411 * A pointer to the socket address is placed in the ai_addr field, and 412 the length of the socket address, in bytes, is placed in the 413 ai_addrlen field. 414 415 If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4 addresses 416 are returned in the list pointed to by res only if the local system has 417 at least one IPv4 address configured, and IPv6 addresses are only 418 returned if the local system has at least one IPv6 address configured. 419 420 If hint.ai_flags specifies the AI_V4MAPPED flag, and hints.ai_family was 421 specified as AF_INET6, and no matching IPv6 addresses could be found, 422 then return IPv4-mapped IPv6 addresses in the list pointed to by res. 423 If both AI_V4MAPPED and AI_ALL are specified in hints.ai_flags, then 424 return both IPv6 and IPv4-mapped IPv6 addresses in the list pointed to 425 by res. AI_ALL is ignored if AI_V4MAPPED is not also specified. 426 427 The freeaddrinfo() function frees the memory that was allocated for the 428 dynamically allocated linked list res. 429 430 Extensions to getaddrinfo() for Internationalized Domain Names 431 Starting with glibc 2.3.4, getaddrinfo() has been extended to selec‐ 432 tively allow the incoming and outgoing hostnames to be transparently 433 converted to and from the Internationalized Domain Name (IDN) format 434 (see RFC 3490, Internationalizing Domain Names in Applications (IDNA)). 435 Four new flags are defined: 436 437 AI_IDN If this flag is specified, then the node name given in node is 438 converted to IDN format if necessary. The source encoding is 439 that of the current locale. 440 441 If the input name contains non-ASCII characters, then the IDN 442 encoding is used. Those parts of the node name (delimited by 443 dots) that contain non-ASCII characters are encoded using ASCII 444 Compatible Encoding (ACE) before being passed to the name resolu‐ 445 tion functions. 446 447 AI_CANONIDN 448 After a successful name lookup, and if the AI_CANONNAME flag was 449 specified, getaddrinfo() will return the canonical name of the 450 node corresponding to the addrinfo structure value passed back. 451 The return value is an exact copy of the value returned by the 452 name resolution function. 453 454 If the name is encoded using ACE, then it will contain the xn-- 455 prefix for one or more components of the name. To convert these 456 components into a readable form the AI_CANONIDN flag can be 457 passed in addition to AI_CANONNAME. The resulting string is 458 encoded using the current locale's encoding. 459 460 AI_IDN_ALLOW_UNASSIGNED, AI_IDN_USE_STD3_ASCII_RULES 461 Setting these flags will enable the IDNA_ALLOW_UNASSIGNED (allow 462 unassigned Unicode code points) and IDNA_USE_STD3_ASCII_RULES 463 (check output to make sure it is a STD3 conforming hostname) 464 flags respectively to be used in the IDNA handling. 465 466 467 getaddrinfo() returns 0 if it succeeds, or one of the following nonzero 468 error codes: 469 470 EAI_ADDRFAMILY 471 The specified network host does not have any network addresses in 472 the requested address family. 473 474 EAI_AGAIN 475 The name server returned a temporary failure indication. Try 476 again later. 477 478 EAI_BADFLAGS 479 hints.ai_flags contains invalid flags; or, hints.ai_flags 480 included AI_CANONNAME and name was NULL. 481 482 EAI_FAIL 483 The name server returned a permanent failure indication. 484 485 EAI_FAMILY 486 The requested address family is not supported. 487 488 EAI_MEMORY 489 Out of memory. 490 491 EAI_NODATA 492 The specified network host exists, but does not have any network 493 addresses defined. 494 495 EAI_NONAME 496 The node or service is not known; or both node and service are 497 NULL; or AI_NUMERICSERV was specified in hints.ai_flags and ser‐ 498 vice was not a numeric port-number string. 499 500 EAI_SERVICE 501 The requested service is not available for the requested socket 502 type. It may be available through another socket type. For 503 example, this error could occur if service was "shell" (a service 504 only available on stream sockets), and either hints.ai_protocol 505 was IPPROTO_UDP, or hints.ai_socktype was SOCK_DGRAM; or the 506 error could occur if service was not NULL, and hints.ai_socktype 507 was SOCK_RAW (a socket type that does not support the concept of 508 services). 509 510 EAI_SOCKTYPE 511 The requested socket type is not supported. This could occur, 512 for example, if hints.ai_socktype and hints.ai_protocol are 513 inconsistent (e.g., SOCK_DGRAM and IPPROTO_TCP, respectively). 514 515 EAI_SYSTEM 516 Other system error, check errno for details. 517 518 The gai_strerror() function translates these error codes to a human 519 readable string, suitable for error reporting. 520 521 **************************************************************************/ 522 523 private addrinfo.ErrorCode getaddrinfo(char* node, char* service, 524 addrinfo* hints, addrinfo** res); 525 526 private void freeaddrinfo(addrinfo* res); 527 528 } 529 530 /****************************************************************************** 531 532 Wraps getaddrinfo()/freeaddrinfo() and manages an addrinfo instance. 533 534 ******************************************************************************/ 535 536 class AddrInfo : AddrInfoC 537 { 538 /************************************************************************** 539 540 String nul-termination buffers. 541 542 **************************************************************************/ 543 544 private mstring node, service; 545 546 /************************************************************************** 547 548 Returns: 549 the current address info as most recently obtained. 550 551 **************************************************************************/ 552 553 public override addrinfo* info ( ) 554 { 555 return this.info_; 556 } 557 558 /************************************************************************** 559 560 Gets the address info for a TCP/IP node and/or service. 561 562 Params: 563 node = node name (may be null) 564 service = service name (may be null) 565 ipv6 = false: get the IPv4, true: get the IPv6 address 566 flags = getaddrinfo() flags 567 568 Returns: 569 0 on success or an error code on failure, see addrinfo.ErrorCode. 570 571 **************************************************************************/ 572 573 public ErrorCode getTcpIp ( cstring node, cstring service, bool ipv6, 574 addrinfo.Flags flags = addrinfo.Flags.None ) 575 { 576 return super.getTcpIp(this.node.toCstr(node), 577 this.service.toCstr(service), ipv6, flags); 578 } 579 580 /************************************************************************** 581 582 Gets the address info for an IP node and/or service. 583 584 Params: 585 node = node name (may be null) 586 service = service name (may be null) 587 ipv6 = false: get the IPv4, true: get the IPv6 address 588 type = socket type (0 for any type) 589 protocol = socket protocol (0 for any protocol) 590 flags = getaddrinfo() flags 591 592 Returns: 593 0 on success or an error code on failure, see addrinfo.ErrorCode. 594 595 **************************************************************************/ 596 597 public ErrorCode getIp ( cstring node, cstring service, 598 bool ipv6, int type, int protocol, 599 addrinfo.Flags flags = addrinfo.Flags.None ) 600 { 601 return super.getIp(this.node.toCstr(node), this.service.toCstr(service), 602 ipv6, type, protocol, flags); 603 } 604 605 /************************************************************************** 606 607 Gets the address info for a node and/or service. 608 609 Params: 610 node = node name (may be null) 611 service = service name (may be null) 612 family = socket family (0 for any family) 613 type = socket type (0 for any type) 614 protocol = socket protocol (0 for any protocol) 615 flags = getaddrinfo() flags 616 617 Returns: 618 0 on success or an error code on failure, see addrinfo.ErrorCode. 619 620 **************************************************************************/ 621 622 public ErrorCode get ( cstring node, cstring service, 623 int family, int type, int protocol, 624 addrinfo.Flags flags = addrinfo.Flags.None ) 625 { 626 return super.get(this.node.toCstr(node), this.service.toCstr(service), 627 family, type, protocol, flags); 628 } 629 630 /************************************************************************** 631 632 Gets the address info for a node and/or service. 633 634 Params: 635 node = node name (may be null) 636 service = service name (may be null) 637 hints = addrinfo instance specifying the socket family, type, 638 protocol and flags or null to get all available addresses 639 640 Returns: 641 0 on success or an error code on failure, see addrinfo.ErrorCode. 642 643 **************************************************************************/ 644 645 public ErrorCode get ( cstring node, cstring service, addrinfo* hints = null ) 646 { 647 return super.get(this.node.toCstr(node), this.service.toCstr(service), 648 hints); 649 } 650 } 651 652 /************************************************************************** 653 654 Appends a nul-terminator to src, storing the result in dst. 655 656 Params: 657 dst = destination string buffer 658 src = string to nul-terminate 659 660 Returns: 661 dst.ptr or null if src is empty. 662 663 **************************************************************************/ 664 665 private char* toCstr ( ref mstring dst, cstring src ) 666 { 667 return src.length? dst.concat(src, "\0"[]).ptr : null; 668 } 669 670 /****************************************************************************** 671 672 Wraps getaddrinfo()/freeaddrinfo() and manages an addrinfo instance; uses 673 C strings as arguments. This class is memory-friendly when used with 'scope' 674 instances. 675 676 ******************************************************************************/ 677 678 class AddrInfoC 679 { 680 alias addrinfo.Flags Flags; 681 alias addrinfo.ErrorCode ErrorCode; 682 683 /************************************************************************** 684 685 addrinfo instance. 686 687 **************************************************************************/ 688 689 private addrinfo* info_ = null; 690 691 /************************************************************************** 692 693 IP address conversion buffer 694 695 **************************************************************************/ 696 697 static assert (INET6_ADDRSTRLEN > INET_ADDRSTRLEN); 698 699 char[INET6_ADDRSTRLEN] ip_address_buf; 700 701 /************************************************************************** 702 703 Destructor. 704 705 **************************************************************************/ 706 707 ~this ( ) 708 { 709 if (this.info_) 710 { 711 freeaddrinfo(this.info_); 712 } 713 } 714 715 /************************************************************************** 716 717 Gets the address info for a TCP/IP node and/or service. 718 719 Params: 720 node = node name (may be null) 721 service = service name (may be null) 722 ipv6 = false: get the IPv4, true: get the IPv6 address 723 flags = getaddrinfo() flags 724 725 Returns: 726 0 on success or an error code on failure, see addrinfo.ErrorCode. 727 728 **************************************************************************/ 729 730 public ErrorCode getTcpIp ( char* node, char* service, bool ipv6, 731 addrinfo.Flags flags = addrinfo.Flags.None ) 732 { 733 return this.getIp(node, service, ipv6, SOCK_STREAM, IPPROTO_TCP, flags); 734 } 735 736 /************************************************************************** 737 738 Gets the address info for an IP node and/or service. 739 740 Params: 741 node = node name (may be null) 742 service = service name (may be null) 743 ipv6 = false: get the IPv4, true: get the IPv6 address 744 type = socket type (0 for any type) 745 protocol = socket protocol (0 for any protocol) 746 flags = getaddrinfo() flags 747 748 Returns: 749 0 on success or an error code on failure, see addrinfo.ErrorCode. 750 751 **************************************************************************/ 752 753 public ErrorCode getIp ( char* node, char* service, 754 bool ipv6, int type, int protocol, 755 addrinfo.Flags flags = addrinfo.Flags.None ) 756 { 757 return this.get(node, service, ipv6? AF_INET6 : AF_INET, type, protocol); 758 } 759 760 761 /************************************************************************** 762 763 Gets the address info for a node and/or service. 764 765 Params: 766 node = node name (may be null) 767 service = service name (may be null) 768 family = socket family (0 for any family) 769 type = socket type (0 for any type) 770 protocol = socket protocol (0 for any protocol) 771 flags = getaddrinfo() flags 772 773 Returns: 774 0 on success or an error code on failure, see addrinfo.ErrorCode. 775 776 **************************************************************************/ 777 778 public ErrorCode get ( char* node, char* service, 779 int family, int type, int protocol, 780 addrinfo.Flags flags = addrinfo.Flags.None ) 781 { 782 auto hints = addrinfo(flags, family, type, protocol); 783 784 return this.get(node, service, &hints); 785 } 786 787 /************************************************************************** 788 789 Gets the address info for a node and/or service. 790 791 Params: 792 node = node name (may be null) 793 service = service name (may be null) 794 hints = addrinfo instance specifying the socket family, type, 795 protocol and flags or null to get all available addresses 796 797 Returns: 798 0 on success or an error code on failure, see addrinfo.ErrorCode. 799 800 **************************************************************************/ 801 802 public ErrorCode get ( char* node, char* service, addrinfo* hints = null ) 803 { 804 if (this.info_) 805 { 806 freeaddrinfo(this.info_); 807 808 this.info_ = null; 809 } 810 811 return .getaddrinfo(node, service, hints, &this.info_); 812 } 813 814 /************************************************************************** 815 816 Returns: 817 the current address info as most recently obtained or null if the 818 last get() failed or get() has not been called yet. 819 820 **************************************************************************/ 821 822 public addrinfo* info ( ) 823 { 824 return this.info_; 825 } 826 827 /*************************************************************************** 828 829 Obtains the current IP address in standard notation. 830 831 Returns: 832 a slice to the resulting IP address string in dst on success or null 833 either on error or if the last get() failed or get() has not been 834 called yet; errno is then 0. On success a nul-terminator follows the 835 sliced string so its .ptr is a C string. On error errno is set 836 appropriately. 837 838 Errors: 839 EAFNOSUPPORT: The address family is not supported (AF_INET/IPv4 or 840 AF_INET6/IPv6). 841 842 ***************************************************************************/ 843 844 public char[] ip_address ( ) 845 { 846 .errno = 0; 847 848 return this.info_? this.info_.ipAddress(this.ip_address_buf) : null; 849 } 850 851 /*************************************************************************** 852 853 Returns: 854 the current port or 0 if the last get() failed or get() has not been 855 called yet. 856 857 ***************************************************************************/ 858 859 public ushort port ( ) 860 { 861 return this.info_? this.info_.port : cast(ushort) 0; 862 } 863 864 /*************************************************************************** 865 866 Returns: 867 the official host name or null if the last get() failed or get() has 868 not been called yet with Flags.AI_CANONNAME set. On success a 869 nul-terminator follows the sliced string so its .ptr is a C string. 870 871 ***************************************************************************/ 872 873 public char[] canonname ( ) 874 { 875 return this.info_? this.info_.canonname : null; 876 } 877 878 /*************************************************************************** 879 880 Returns: 881 the official host name as a nul-terminated C string or null if the 882 last get() failed or get() has not been called yet with 883 Flags.AI_CANONNAME set. 884 885 ***************************************************************************/ 886 887 public char* canonname_c ( ) 888 { 889 return this.info_? this.info_.ai_canonname : null; 890 } 891 }