Skip to content

Commit 304a102

Browse files
committed
Set user timeout for tcp connection
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]>
1 parent 06c1f43 commit 304a102

File tree

4 files changed

+54
-0
lines changed

4 files changed

+54
-0
lines changed

client/client.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/go-logr/logr"
2222
"github.com/go-logr/stdr"
2323
"github.com/ovn-org/libovsdb/cache"
24+
syscall "github.com/ovn-org/libovsdb/internal"
2425
"github.com/ovn-org/libovsdb/mapper"
2526
"github.com/ovn-org/libovsdb/model"
2627
"github.com/ovn-org/libovsdb/ovsdb"
@@ -429,6 +430,13 @@ func (o *ovsdbClient) createRPC2Client(conn net.Conn) {
429430
o.trafficSeen = make(chan struct{})
430431
}
431432
o.conn = conn
433+
// set TCP_USER_TIMEOUT socket option for connection so that
434+
// channel write doesn't block indefinitely on network disconnect.
435+
if o.options.timeout > 0 {
436+
syscall.SetTCPUserTimeout(conn, o.options.timeout*3)
437+
} else {
438+
syscall.SetTCPUserTimeout(conn, defaultTimeOut)
439+
}
432440
o.rpcClient = rpc2.NewClientWithCodec(jsonrpc.NewJSONCodec(conn))
433441
o.rpcClient.SetBlocking(true)
434442
o.rpcClient.Handle("echo", func(_ *rpc2.Client, args []interface{}, reply *[]interface{}) error {

client/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const (
1515
defaultTCPEndpoint = "tcp:127.0.0.1:6640"
1616
defaultSSLEndpoint = "ssl:127.0.0.1:6640"
1717
defaultUnixEndpoint = "unix:/var/run/openvswitch/ovsdb.sock"
18+
defaultTimeOut = 60 * time.Second
1819
)
1920

2021
type options struct {

internal/syscall_linux.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package internal
2+
3+
import (
4+
"fmt"
5+
"net"
6+
"syscall"
7+
"time"
8+
9+
"golang.org/x/sys/unix"
10+
)
11+
12+
// SetTCPUserTimeout sets the TCP user timeout on a connection's socket
13+
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
14+
tcpconn, ok := conn.(*net.TCPConn)
15+
if !ok {
16+
// not a TCP connection. exit early
17+
return nil
18+
}
19+
rawConn, err := tcpconn.SyscallConn()
20+
if err != nil {
21+
return fmt.Errorf("error getting raw connection: %v", err)
22+
}
23+
err = rawConn.Control(func(fd uintptr) {
24+
err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
25+
})
26+
if err != nil {
27+
return fmt.Errorf("error setting option on socket: %v", err)
28+
}
29+
30+
return nil
31+
}

internal/syscall_nonlinux.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//go:build !linux
2+
// +build !linux
3+
4+
package internal
5+
6+
import (
7+
"net"
8+
"time"
9+
)
10+
11+
// SetTCPUserTimeout is a no-op function under non-linux environments.
12+
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
13+
return nil
14+
}

0 commit comments

Comments
 (0)