Skip to content

Commit

Permalink
Set user timeout for tcp connection
Browse files Browse the repository at this point in the history
This commit sets TCP_USER_TIMEOUT socket option for tcp connection
so that channel write doesn't block indefinitely on network disconnect.

Signed-off-by: Periyasamy Palanisamy <[email protected]>
  • Loading branch information
pperiyasamy committed Nov 9, 2023
1 parent 06c1f43 commit 304a102
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
8 changes: 8 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/go-logr/logr"
"github.com/go-logr/stdr"
"github.com/ovn-org/libovsdb/cache"
syscall "github.com/ovn-org/libovsdb/internal"
"github.com/ovn-org/libovsdb/mapper"
"github.com/ovn-org/libovsdb/model"
"github.com/ovn-org/libovsdb/ovsdb"
Expand Down Expand Up @@ -429,6 +430,13 @@ func (o *ovsdbClient) createRPC2Client(conn net.Conn) {
o.trafficSeen = make(chan struct{})
}
o.conn = conn
// set TCP_USER_TIMEOUT socket option for connection so that
// channel write doesn't block indefinitely on network disconnect.
if o.options.timeout > 0 {
syscall.SetTCPUserTimeout(conn, o.options.timeout*3)

Check failure on line 436 in client/client.go

View workflow job for this annotation

GitHub Actions / Build & Unit Test

Error return value of `syscall.SetTCPUserTimeout` is not checked (errcheck)
} else {
syscall.SetTCPUserTimeout(conn, defaultTimeOut)

Check failure on line 438 in client/client.go

View workflow job for this annotation

GitHub Actions / Build & Unit Test

Error return value of `syscall.SetTCPUserTimeout` is not checked (errcheck)
}
o.rpcClient = rpc2.NewClientWithCodec(jsonrpc.NewJSONCodec(conn))
o.rpcClient.SetBlocking(true)
o.rpcClient.Handle("echo", func(_ *rpc2.Client, args []interface{}, reply *[]interface{}) error {
Expand Down
1 change: 1 addition & 0 deletions client/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const (
defaultTCPEndpoint = "tcp:127.0.0.1:6640"
defaultSSLEndpoint = "ssl:127.0.0.1:6640"
defaultUnixEndpoint = "unix:/var/run/openvswitch/ovsdb.sock"
defaultTimeOut = 60 * time.Second
)

type options struct {
Expand Down
31 changes: 31 additions & 0 deletions internal/syscall_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package internal

import (
"fmt"
"net"
"syscall"
"time"

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

// SetTCPUserTimeout sets the TCP user timeout on a connection's socket
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
tcpconn, ok := conn.(*net.TCPConn)
if !ok {
// not a TCP connection. exit early
return nil
}
rawConn, err := tcpconn.SyscallConn()
if err != nil {
return fmt.Errorf("error getting raw connection: %v", err)
}
err = rawConn.Control(func(fd uintptr) {
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
})
if err != nil {
return fmt.Errorf("error setting option on socket: %v", err)
}

return nil
}
14 changes: 14 additions & 0 deletions internal/syscall_nonlinux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build !linux
// +build !linux

package internal

import (
"net"
"time"
)

// SetTCPUserTimeout is a no-op function under non-linux environments.
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
return nil
}

0 comments on commit 304a102

Please sign in to comment.