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 }