1
0
mirror of https://github.com/google/gops.git synced 2024-11-19 20:31:58 +02:00

agent: allow to set SO_REUSEPORT on listening socket

Introduce Option.SocketReuseAddrAndPort which, if set, will lead to the
SO_REUSEPORT socket option being set on the listening socket on
Unix-like OSes. This also sets SO_REUSEADDR which is already the default
in net.Listen (see net.setDefaultSockopts).

Setting these options increases the chance to re-bind() to the same
address and port upon agent restart if Options.Addr is set.

Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
This commit is contained in:
Tobias Klauser 2020-12-09 16:44:54 +01:00 committed by Tobias Klauser
parent b55933ebc4
commit 268f11e4fc
6 changed files with 76 additions and 5 deletions

View File

@ -8,6 +8,7 @@ package agent
import (
"bufio"
"context"
"encoding/binary"
"fmt"
"io"
@ -55,6 +56,13 @@ type Options struct {
// can call Close before shutting down.
// Optional.
ShutdownCleanup bool
// ReuseSocketAddrAndPort determines whether the SO_REUSEADDR and
// SO_REUSEADDR socket options should be set on the listening socket of
// the agent. This option is only effective on unix-like OSes and if
// Addr is set to a fixed host:port.
// Optional.
ReuseSocketAddrAndPort bool
}
// Listen starts the gops agent on a host process. Once agent started, users
@ -96,11 +104,14 @@ func Listen(opts Options) error {
if addr == "" {
addr = defaultAddr
}
ln, err := net.Listen("tcp", addr)
var lc net.ListenConfig
if opts.ReuseSocketAddrAndPort {
lc.Control = setsockoptReuseAddrAndPort
}
listener, err = lc.Listen(context.Background(), "tcp", addr)
if err != nil {
return err
}
listener = ln
port := listener.Addr().(*net.TCPAddr).Port
portfile = fmt.Sprintf("%s/%d", gopsdir, os.Getpid())
err = ioutil.WriteFile(portfile, []byte(strconv.Itoa(port)), os.ModePerm)

View File

@ -54,6 +54,17 @@ func TestAgentListenMultipleClose(t *testing.T) {
Close()
}
func TestAgentListenReuseAddrAndPort(t *testing.T) {
err := Listen(Options{
Addr: "127.0.0.1:50000",
ReuseSocketAddrAndPort: true,
})
if err != nil {
t.Fatal(err)
}
Close()
}
func TestFormatBytes(t *testing.T) {
tests := []struct {
val uint64

36
agent/sockopt_unix.go Normal file
View File

@ -0,0 +1,36 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build !js,!plan9,!windows
package agent
import (
"syscall"
"golang.org/x/sys/unix"
)
// setsockoptReuseAddrAndPort sets the SO_REUSEADDR and SO_REUSEPORT socket
// options on c's underlying socket in order to increase the chance to re-bind()
// to the same address and port upon agent restart.
func setsockoptReuseAddrAndPort(network, address string, c syscall.RawConn) error {
var soerr error
if err := c.Control(func(su uintptr) {
sock := int(su)
// Allow reuse of recently-used addresses. This socket option is
// set by default on listeners in Go's net package, see
// net.setDefaultSockopts.
soerr = unix.SetsockoptInt(sock, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
if soerr != nil {
return
}
// Allow reuse of recently-used ports. This gives the agent a
// better chance to re-bind upon restarts.
soerr = unix.SetsockoptInt(sock, unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
}); err != nil {
return err
}
return soerr
}

View File

@ -0,0 +1,13 @@
// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build js,wasm plan9 windows
package agent
import "syscall"
func setsockoptReuseAddrAndPort(network, address string, c syscall.RawConn) error {
return nil
}

2
go.mod
View File

@ -9,6 +9,6 @@ require (
github.com/shirou/gopsutil v2.20.4+incompatible
github.com/stretchr/testify v1.3.0 // indirect
github.com/xlab/treeprint v1.0.0
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 // indirect
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d
rsc.io/goversion v1.2.0
)

4
go.sum
View File

@ -15,7 +15,7 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/xlab/treeprint v1.0.0 h1:J0TkWtiuYgtdlrkkrDLISYBQ92M+X5m4LrIIMKrbDTs=
github.com/xlab/treeprint v1.0.0/go.mod h1:IoImgRak9i3zJyuxOKUP1v4UZd1tMoKkq/Cimt1uhCg=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9 h1:YTzHMGlqJu67/uEo1lBv0n3wBXhXNeUbB1XfN2vmTm0=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d h1:MiWWjyhUzZ+jvhZvloX6ZrUsdEghn8a64Upd8EMHglE=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
rsc.io/goversion v1.2.0 h1:SPn+NLTiAG7w30IRK/DKp1BjvpWabYgxlLp/+kx5J8w=
rsc.io/goversion v1.2.0/go.mod h1:Eih9y/uIBS3ulggl7KNJ09xGSLcuNaLgmvvqa07sgfo=