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 }