1 /****************************************************************************** 2 3 Transparent Linux IP sockets interface wrapper. 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.IPSocket; 17 18 19 import ocean.transition; 20 21 import ocean.stdc.posix.sys.socket; 22 23 import ocean.stdc.posix.netinet.in_: AF_INET, AF_INET6; 24 25 import core.sys.posix.unistd: close; 26 27 import ocean.stdc.posix.sys.types: ssize_t; 28 29 import ocean.io.device.Conduit: ISelectable; 30 31 import ocean.io.device.IODevice: InputDevice, IOutputDevice; 32 33 import ocean.sys.socket.InetAddress; 34 35 import ocean.core.TypeConvert; 36 37 import ocean.sys.socket.model.ISocket; 38 39 import ocean.text.convert.Formatter; 40 41 /****************************************************************************** 42 43 TCP option codes supported by getsockopt()/setsockopt() 44 (from <inet/netinet.h>). 45 46 ******************************************************************************/ 47 48 public enum TcpOptions 49 { 50 None, 51 TCP_NODELAY, /// 1: Don't delay send to coalesce packets 52 TCP_MAXSEG, /// 2: Set maximum segment size 53 TCP_CORK, /// 3: Control sending of partial frames 54 TCP_KEEPIDLE, /// 4: Start keeplives after this period 55 TCP_KEEPINTVL, /// 5: Interval between keepalives 56 TCP_KEEPCNT, /// 6: Number of keepalives before death 57 TCP_SYNCNT, /// 7: Number of SYN retransmits 58 TCP_LINGER2, /// 8: Life time of orphaned FIN-WAIT-2 state 59 TCP_DEFER_ACCEPT, /// 9: Wake up listener only when data arrive 60 TCP_WINDOW_CLAMP, /// 10: Bound advertised window 61 TCP_INFO, /// 11: Information about this connection. 62 TCP_QUICKACK, /// 12: Bock/reenable quick ACKs. 63 TCP_CONGESTION, /// 13: Congestion control algorithm. 64 TCP_MD5SIG, /// 14: TCP MD5 Signature (RFC2385) 65 66 } 67 68 69 /****************************************************************************** 70 71 IP socket base class 72 73 ******************************************************************************/ 74 75 abstract class IIPSocket : ISocket 76 { 77 import ocean.sys.CloseOnExec; 78 79 // add to overload set explicitly 80 alias ISocket.socket socket; 81 82 /************************************************************************** 83 84 Flags supported by accept4(). 85 86 **************************************************************************/ 87 88 alias .SocketFlags SocketFlags; 89 90 alias .TcpOptions TcpOptions; 91 92 93 /************************************************************************** 94 95 true for IPv6, false for IPv4. 96 97 **************************************************************************/ 98 99 public bool is_ipv6 ( ) 100 { 101 return this._is_ipv6; 102 } 103 104 private bool _is_ipv6; 105 106 /************************************************************************** 107 108 public const socklen_t in_addrlen; 109 Constructor. 110 111 Params: 112 is_ipv6 = true if this is an IPv6 socket or false if it is IPv4. 113 in_addrlen = internet address struct length 114 115 **************************************************************************/ 116 117 protected this ( bool is_ipv6, socklen_t in_addrlen ) 118 { 119 super(in_addrlen); 120 121 this._is_ipv6 = is_ipv6; 122 } 123 124 /************************************************************************** 125 126 Creates an IP socket endpoint for communication and sets this.fd to the 127 corresponding file descriptor. 128 129 Params: 130 type = desired socket type, which specifies the communication 131 semantics. Supported types are: 132 133 SOCK_STREAM Provides sequenced, reliable, two-way, connec‐ 134 tion-based byte streams. An out-of-band data 135 transmission mechanism may be supported. 136 137 SOCK_DGRAM Supports datagrams - connectionless, unreliable 138 messages of a fixed maximum length. 139 140 SOCK_SEQPACKET Provides a sequenced, reliable, two-way connec‐ 141 tion-based data transmission path for datagrams 142 of fixed maximum length; a consumer is required 143 to read an entire packet with each input system 144 call. 145 146 SOCK_RAW Provides raw network protocol access. 147 148 Some socket types may not be implemented by all protocol fami‐ 149 lies; for example, SOCK_SEQPACKET is not implemented for 150 AF_INET (IPv4). 151 152 Since Linux 2.6.27, the type argument serves a second purpose: 153 in addition to specifying a socket type, it may include the bit‐ 154 wise OR of any of the following values, to modify the behavior 155 of socket(): 156 157 SOCK_NONBLOCK Set the O_NONBLOCK file status flag on the new 158 open file description. Using this flag saves 159 extra calls to fcntl(2) to achieve the same 160 result. 161 162 SOCK_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the 163 new file descriptor. See the description of the 164 O_CLOEXEC flag in open(2) for reasons why this 165 may be useful. 166 167 protocol = desired protocol or 0 to use the default protocol for the 168 specified type (e.g. TCP for `type == SOCK_STREAM` or UDP for 169 `type == SOCK_DGRAM`). 170 171 The protocol specifies a particular protocol to be used with the 172 socket. Normally only a single protocol exists to support a 173 particular socket type within a given protocol family, in which 174 case protocol can be specified as 0. However, it is possible 175 that many protocols may exist, in which case a particular proto‐ 176 col must be specified in this manner. The protocol number to 177 use is specific to the “communication domain” in which communi‐ 178 cation is to take place; see protocols(5). See getprotoent(3) 179 on how to map protocol name strings to protocol numbers. 180 181 Sockets of type SOCK_STREAM are full-duplex byte streams, simi‐ 182 lar to pipes. They do not preserve record boundaries. A stream 183 socket must be in a connected state before any data may be sent 184 or received on it. A connection to another socket is created 185 with a connect(2) call. Once connected, data may be transferred 186 using read(2) and write(2) calls or some variant of the send(2) 187 and recv(2) calls. When a session has been completed a close(2) 188 may be performed. Out-of-band data may also be transmitted as 189 described in send(2) and received as described in recv(2). 190 191 192 Returns: 193 the socket file descriptor on success or -1 on failure. On failure 194 errno is set appropriately and this.fd is -1. 195 196 Errors: 197 EACCES Permission to create a socket of the specified type and/or 198 protocol is denied. 199 200 EAFNOSUPPORT 201 The implementation does not support the specified address 202 family. 203 204 EINVAL Unknown protocol, or protocol family not available. 205 206 EINVAL Invalid flags in type. 207 208 EMFILE Process file table overflow. 209 210 ENFILE The system limit on the total number of open files has been 211 reached. 212 213 ENOBUFS or ENOMEM 214 Insufficient memory is available. The socket cannot be cre‐ 215 ated until sufficient resources are freed. 216 217 EPROTONOSUPPORT 218 The protocol type or the specified protocol is not supported 219 within this domain. 220 221 Other errors may be generated by the underlying protocol modules. 222 223 **************************************************************************/ 224 225 public int socket ( int type, int protocol = 0 ) 226 { 227 return super.socket(this.is_ipv6? AF_INET6 : AF_INET, type, protocol); 228 } 229 230 /************************************************************************** 231 232 Calls socket() to create a TCP/IP socket, setting this.fd to the file 233 descriptor. 234 235 Params: 236 nonblocking = true: make the socket nonblocking, false: make it 237 blocking 238 239 Returns: 240 the socket file descriptor on success or -1 on failure. On failure 241 errno is set appropriately and this.fd is -1. 242 243 **************************************************************************/ 244 245 public int tcpSocket ( bool nonblocking = false ) 246 { 247 auto flags = SOCK_STREAM | (nonblocking ? SocketFlags.SOCK_NONBLOCK : 0); 248 249 return this.socket(flags, IPPROTO_TCP); 250 } 251 } 252 253 /****************************************************************************** 254 255 IP socket class, contains the IPv4/6 address specific parts. 256 257 Params: 258 IPv6 = true: use IPv6, false: use IPv4 259 260 ******************************************************************************/ 261 262 class IPSocket ( bool IPv6 = false ) : IIPSocket 263 { 264 alias .InetAddress!(IPv6) InetAddress; 265 266 /************************************************************************** 267 268 Type alias of the "sin" internet address struct type, sockaddr_in for 269 IPv4 or sockaddr_in6 for IPv6. 270 271 **************************************************************************/ 272 273 alias InetAddress.Addr InAddr; 274 275 /************************************************************************** 276 277 Constructor. 278 279 **************************************************************************/ 280 281 public this ( ) 282 { 283 super(IPv6, InAddr.sizeof); 284 } 285 286 /************************************************************************** 287 288 Assigns a local address to this socket. This socket needs to have been 289 created by socket(). 290 291 Params: 292 local_address = local address 293 294 Returns: 295 0 on success or -1 on failure. On failure errno is set 296 appropriately. 297 298 Errors: 299 EACCES The address is protected, and the user is not the superuser. 300 301 EADDRINUSE 302 The given address is already in use. 303 304 EBADF sockfd is not a valid descriptor. 305 306 EINVAL The socket is already bound to an address. 307 308 ENOTSOCK 309 The file descriptor is a descriptor for a file, not a socket. 310 311 **************************************************************************/ 312 313 public int bind ( InAddr local_address ) 314 { 315 return super.bind(cast (sockaddr*) &local_address); 316 } 317 318 /************************************************************************** 319 320 Assigns a local address and optionally a port to this socket. 321 This socket needs to have been created by socket(). 322 323 Params: 324 local_ip_address = local IP address 325 local_port = local port or 0 to use the wildcard "any" port 326 327 Returns: 328 0 on success or -1 on failure. On failure errno is set 329 appropriately. 330 331 Errors: 332 as above but also sets errno to EAFNOSUPPORT if the address does not 333 contain a valid IP address string. 334 335 **************************************************************************/ 336 337 public int bind ( cstring local_ip_address, ushort local_port = 0 ) 338 { 339 InetAddress in_address; 340 341 sockaddr* local_address = in_address(local_ip_address, local_port); 342 343 return local_address? super.bind(local_address) : -1; 344 } 345 346 /************************************************************************** 347 348 Assigns the wildcard "any" local address and optionally a port to this 349 socket. This socket needs to have been created by socket(). 350 351 Params: 352 local_port = local port or 0 to use the wildcard "any" port 353 354 Returns: 355 0 on success or -1 on failure. On failure errno is set 356 appropriately. 357 358 **************************************************************************/ 359 360 public int bind ( ushort local_port = 0 ) 361 { 362 InetAddress in_address; 363 364 return super.bind(in_address(local_port)); 365 } 366 367 /************************************************************************** 368 369 Overriding wrapper to satisfy overload-override rules of D. 370 371 **************************************************************************/ 372 373 public override int bind ( sockaddr* local_address ) 374 { 375 return super.bind(local_address); 376 } 377 378 /************************************************************************** 379 380 Accepts a connection from a listening socket and sets this.fd to the 381 accepted socket file descriptor. 382 383 The accept() system call is used with connection-based socket types 384 (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection request 385 on the queue of pending connections for the listening socket, creates 386 a new connected socket, and returns a new file descriptor referring to 387 that socket. The newly created socket is not in the listening state. 388 The original socket is unaffected by this call. 389 390 If no pending connections are present on the queue, and the socket is 391 not marked as nonblocking, accept() blocks the caller until a connection 392 is present. If the socket is marked nonblocking and no pending connec‐ 393 tions are present on the queue, accept() fails with the error EAGAIN or 394 EWOULDBLOCK. 395 396 In order to be notified of incoming connections on a socket, you can use 397 select(2) or poll(2). A readable event will be delivered when a new 398 connection is attempted and you may then call accept() to get a socket 399 for that connection. Alternatively, you can set the socket to deliver 400 SIGIO when activity occurs on a socket; see socket(7) for details. 401 402 Params: 403 listening_socket = the listening socket to accept the new connection 404 from 405 remote_address = filled in with the address of the peer socket, as 406 known to the communications layer 407 flags = 408 The following values can be bitwise ORed in flags: 409 410 SOCK_NONBLOCK Set the O_NONBLOCK file status flag on the new 411 open file description. Using this flag saves 412 extra calls to fcntl(2) to achieve the same 413 result. 414 415 SOCK_CLOEXEC Set the close-on-exec (FD_CLOEXEC) flag on the 416 new file descriptor. See the description of the 417 O_CLOEXEC flag in open(2) for reasons why this 418 may be useful. 419 420 421 422 Returns: 423 the file descriptor of the accepted socket on success or -1 on 424 failure. On failure errno is set appropriately. 425 426 Errors: 427 EAGAIN or EWOULDBLOCK 428 The socket is marked nonblocking and no connections are 429 present to be accepted. 430 431 EBADF The descriptor is invalid. 432 433 ECONNABORTED 434 A connection has been aborted. 435 436 EFAULT The addr argument is not in a writable part of the user 437 address space. 438 439 EINTR The system call was interrupted by a signal that was caught 440 before a valid connection arrived; see signal(7). 441 442 EINVAL Socket is not listening for connections, or addrlen is 443 invalid (e.g., is negative). 444 445 EINVAL invalid value in flags. 446 447 EMFILE The per-process limit of open file descriptors has been 448 reached. 449 450 ENFILE The system limit on the total number of open files has been 451 reached. 452 453 ENOBUFS, ENOMEM 454 Not enough free memory. This often means that the memory 455 allocation is limited by the socket buffer limits, not by the 456 system memory. 457 458 ENOTSOCK 459 The descriptor references a file, not a socket. 460 461 EOPNOTSUPP 462 The referenced socket is not of type SOCK_STREAM. 463 464 EPROTO Protocol error. 465 466 In addition, Linux accept() may fail if: 467 468 EPERM Firewall rules forbid connection. 469 470 In addition, network errors for the new socket and as defined for 471 the protocol may be returned. Various Linux kernels can return 472 other errors such as ENOSR, ESOCKTNOSUPPORT, EPROTONOSUPPORT, 473 ETIMEDOUT. The value ERESTARTSYS may be seen during a trace. 474 475 **************************************************************************/ 476 477 public int accept ( ISelectable listening_socket, 478 ref InAddr remote_address, SocketFlags flags = SocketFlags.None ) 479 { 480 socklen_t addrlen; 481 482 return super.accept(listening_socket, 483 cast (sockaddr*) &remote_address, addrlen, flags); 484 } 485 486 /************************************************************************** 487 488 Calls accept() to accept a connection from a listening socket, sets 489 this.fd to the accepted socket file descriptor. 490 491 Params: 492 listening_socket = the listening socket to accept the new connection 493 from 494 remote_address = filled in with the address of the peer socket, as 495 known to the communications layer 496 nonblocking = true: make the accepted socket nonblocking, 497 false: leave it blocking 498 499 Returns: 500 the file descriptor of the accepted socket on success or -1 on 501 failure. On failure errno is set appropriately. 502 503 **************************************************************************/ 504 505 public int accept ( ISelectable listening_socket, 506 ref InAddr remote_address, bool nonblocking ) 507 { 508 static immutable SocketFlags[2] flags = [SocketFlags.None, SocketFlags.SOCK_NONBLOCK]; 509 510 return this.accept(listening_socket, remote_address, flags[nonblocking]); 511 } 512 513 /************************************************************************** 514 515 Overriding wrapper to satisfy overload-override rules of D. 516 517 **************************************************************************/ 518 519 public override int accept ( ISelectable listening_socket, 520 sockaddr* remote_address, out socklen_t addrlen, 521 SocketFlags flags = SocketFlags.None ) 522 { 523 return super.accept(listening_socket, remote_address, addrlen, flags); 524 } 525 526 /************************************************************************** 527 528 Connects this socket the specified address. This socket needs to have 529 been created by socket(). 530 531 If this socket is of type SOCK_DGRAM then the address is the one to 532 which datagrams are sent by default, and the only address from which 533 datagrams are received. If the socket is of type SOCK_STREAM or 534 SOCK_SEQPACKET, this call attempts to make a connection to the socket 535 that is bound to the address specified by addr. 536 537 Generally, connection-based protocol sockets may successfully connect() 538 only once; connectionless protocol sockets may use connect() multiple 539 times to change their association. Connectionless sockets may dissolve 540 the association by connecting to an address with the sa_family member of 541 sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2). 542 543 Params: 544 remote_address = remote address 545 546 Returns: 547 0 on success or -1 on failure. On error failure is set 548 appropriately. 549 550 Errors: 551 The following are general socket errors only. There may be other 552 domain-specific error codes. 553 554 EACCES For Unix domain sockets, which are identified by pathname: 555 Write permission is denied on the socket file, or search per‐ 556 mission is denied for one of the directories in the path pre‐ 557 fix. (See also path_resolution(7).) 558 559 EACCES, EPERM 560 The user tried to connect to a broadcast address without hav‐ 561 ing the socket broadcast flag enabled or the connection 562 request failed because of a local firewall rule. 563 564 EADDRINUSE 565 Local address is already in use. 566 567 EAGAIN No more free local ports or insufficient entries in the rout‐ 568 ing cache. For AF_INET see the description of 569 /proc/sys/net/ipv4/ip_local_port_range ip(7) for information 570 on how to increase the number of local ports. 571 572 EALREADY 573 The socket is nonblocking and a previous connection attempt 574 has not yet been completed. 575 576 EBADF The file descriptor is not a valid index in the descriptor 577 table. 578 579 ECONNREFUSED 580 No-one listening on the remote address. 581 582 EFAULT The socket structure address is outside the user's address 583 space. 584 585 EINPROGRESS 586 The socket is nonblocking and the connection cannot be com‐ 587 pleted immediately. It is possible to select(2) or poll(2) 588 for completion by selecting the socket for writing. After 589 select(2) indicates writability, use getsockopt(2) to read 590 the SO_ERROR option at level SOL_SOCKET to determine whether 591 connect() completed successfully (SO_ERROR is zero) or unsuc‐ 592 cessfully (SO_ERROR is one of the usual error codes listed 593 here, explaining the reason for the failure). 594 595 EINTR The system call was interrupted by a signal that was caught; 596 see signal(7). 597 598 EISCONN 599 The socket is already connected. 600 601 ENETUNREACH 602 Network is unreachable. 603 604 ENOTSOCK 605 The file descriptor is not associated with a socket. 606 607 ETIMEDOUT 608 Timeout while attempting connection. The server may be too 609 busy to accept new connections. Note that for IP sockets the 610 timeout may be very long when syncookies are enabled on the 611 server. 612 613 **************************************************************************/ 614 615 public int connect ( InAddr remote_address ) 616 { 617 return super.connect(cast (sockaddr*) &remote_address); 618 } 619 620 /************************************************************************** 621 622 Connects this socket the specified address and port. This socket needs 623 to have been created by socket(). 624 625 Params: 626 remote_ip_address = remote IP address 627 remote_port = remote port 628 629 Returns: 630 0 on success or -1 on failure. On failure errno is set 631 appropriately. 632 633 Errors: 634 as above but also sets errno to EAFNOSUPPORT if the address does not 635 contain a valid IP address string. 636 637 **************************************************************************/ 638 639 public int connect ( cstring remote_ip_address, ushort remote_port ) 640 { 641 InetAddress in_address; 642 643 sockaddr* remote_address = in_address(remote_ip_address, remote_port); 644 645 return remote_address? super.connect(remote_address) : -1; 646 } 647 648 /************************************************************************** 649 650 Overriding wrapper to satisfy overload-override rules of D. 651 652 **************************************************************************/ 653 654 public override int connect ( sockaddr* remote_address ) 655 { 656 return super.connect(remote_address); 657 } 658 659 /************************************************************************** 660 661 Obtains the current address to which this socket is bound. 662 663 Params: 664 local_address = filled in with the address of the local socket, as 665 known to the communications layer, depending on the 666 IP version of this class 667 668 Returns: 669 0 success or -1 on failure. On failure errno is set appropriately. 670 671 Errors: 672 EBADF The argument sockfd is not a valid descriptor. 673 674 EFAULT The local_address argument points to memory not in a valid 675 part of the process address space. 676 677 ENOBUFS 678 Insufficient resources were available in the system to perform 679 the operation. 680 681 ENOTSOCK 682 this.fd is a file, not a socket. 683 684 **************************************************************************/ 685 686 public int getsockname ( out InAddr local_address ) 687 { 688 socklen_t addrlen; 689 690 return super.getsockname(cast (sockaddr*) &local_address, addrlen); 691 } 692 693 /************************************************************************** 694 695 Overriding wrapper to satisfy overload-override rules of D. 696 697 **************************************************************************/ 698 699 public override int getsockname ( sockaddr* local_address, out socklen_t addrlen ) 700 { 701 return super.getsockname(local_address, addrlen); 702 } 703 704 /************************************************************************** 705 706 Obtains the address of the peer connected to this socket. 707 708 Params: 709 remote_address = filled in with the address of the remote socket, as 710 known to the communications layer, depending on the 711 IP version of this class 712 713 Returns: 714 0 success or -1 on failure. On failure errno is set appropriately. 715 716 Errors: 717 EBADF this.fg is not a valid descriptor. 718 719 EFAULT The remote_address argument points to memory not in a valid 720 part of the process address space. 721 722 ENOBUFS 723 Insufficient resources were available in the system to perform 724 the operation. 725 726 ENOTSOCK 727 this.fd is a file, not a socket. 728 729 **************************************************************************/ 730 731 public int getpeername ( out InAddr remote_address ) 732 { 733 socklen_t addrlen; 734 735 return super.getpeername(cast (sockaddr*) &remote_address, addrlen); 736 } 737 738 /************************************************************************** 739 740 Overriding wrapper to satisfy overload-override rules of D. 741 742 **************************************************************************/ 743 744 public override int getpeername ( sockaddr* remote_address, out socklen_t addrlen ) 745 { 746 return super.getpeername(remote_address, addrlen); 747 } 748 749 /************************************************************************** 750 751 Formats information about the socket into the provided buffer. 752 753 Params: 754 buf = buffer to format into 755 io_error = true if an I/O error has been reported 756 757 **************************************************************************/ 758 759 override public void formatInfo ( ref char[] buf, bool io_error ) 760 { 761 InetAddress in_address; 762 char[in_address.addrstrlen] ip_address_; 763 this.getpeername(in_address.addr); 764 size_t ip_address_len = in_address.inet_ntop(ip_address_).length; 765 766 sformat(buf, "fd={}, remote={}:{}, ioerr={}", 767 this.fileHandle, ip_address_[0 .. ip_address_len], 768 in_address.port, io_error); 769 } 770 } 771 772 773 /******************************************************************************/ 774 775 version (UnitTest) 776 { 777 import ocean.core.Test; 778 } 779 780 unittest 781 { 782 auto socket = new IPSocket!(); 783 socket.tcpSocket(); 784 socket.setsockoptVal(SOL_SOCKET, SO_KEEPALIVE, true); 785 socket.setsockoptVal(IPPROTO_TCP, socket.TcpOptions.TCP_KEEPIDLE, 5); 786 socket.setsockoptVal(IPPROTO_TCP, socket.TcpOptions.TCP_KEEPCNT, 3); 787 socket.setsockoptVal(IPPROTO_TCP, socket.TcpOptions.TCP_KEEPINTVL, 3); 788 }