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