Skip to content

Commit

Permalink
dial: use OS defaults for TCP keepalive params
Browse files Browse the repository at this point in the history
Fixes #605
  • Loading branch information
mmatczuk committed Dec 15, 2023
1 parent 7041bdd commit a69792a
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 16 deletions.
33 changes: 17 additions & 16 deletions dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,15 @@ type DialConfig struct {
// often around 3 minutes.
DialTimeout time.Duration

// KeepAlive specifies the interval between keep-alive
// probes for an active network connection.
// If zero, keep-alive probes are sent with a default value
// (currently 15 seconds), if supported by the protocol and operating
// system. Network protocols or operating systems that do
// not support keep-alives ignore this field.
// If negative, keep-alive probes are disabled.
KeepAlive time.Duration
// KeepAlive enables TCP keep-alive probes for an active network connection.
// The keep-alive probes are sent with OS specific intervals.
KeepAlive bool
}

func DefaultDialConfig() *DialConfig {
return &DialConfig{
DialTimeout: 10 * time.Second,
KeepAlive: 30 * time.Second,
KeepAlive: true,
}
}

Expand All @@ -43,15 +38,21 @@ type Dialer struct {
}

func NewDialer(cfg *DialConfig) *Dialer {
return &Dialer{
net.Dialer{
Timeout: cfg.DialTimeout,
KeepAlive: cfg.KeepAlive,
Resolver: &net.Resolver{
PreferGo: true,
},
nd := net.Dialer{
Timeout: cfg.DialTimeout,
KeepAlive: -1,
Resolver: &net.Resolver{
PreferGo: true,
},
}

if cfg.KeepAlive {
enableTCPKeepAlive(&nd)
}

return &Dialer{
nd: nd,
}
}

func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
Expand Down
27 changes: 27 additions & 0 deletions dial_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright 2023 Sauce Labs Inc., all rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//go:build unix

package forwarder

import (
"fmt"
"net"
"os"
"syscall"
)

func enableTCPKeepAlive(d *net.Dialer) {
d.KeepAlive = -1
d.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
if err := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_KEEPALIVE, 1); err != nil {
fmt.Fprintf(os.Stderr, "failed to set SO_KEEPALIVE: %v\n", err)
}
})
}
}
31 changes: 31 additions & 0 deletions dial_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2023 Sauce Labs Inc., all rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

//go:build windows

package forwarder

import (
"fmt"
"net"
"os"
"syscall"
"unsafe"

"golang.org/x/sys/windows"
)

func enableTCPKeepAlive(d *net.Dialer) {
d.KeepAlive = -1
d.Control = func(network, address string, c syscall.RawConn) error {
return c.Control(func(fd uintptr) {
optval := (*byte)(unsafe.Pointer(&[4]byte{1}))
if err := windows.Setsockopt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_KEEPALIVE, optval, 1); err != nil {
fmt.Fprintf(os.Stderr, "failed to set SO_KEEPALIVE: %v\n", err)
}
})
}
}

0 comments on commit a69792a

Please sign in to comment.