diff --git a/README.md b/README.md index 33fa3c3..109d929 100644 --- a/README.md +++ b/README.md @@ -119,9 +119,14 @@ This field also has no effect if `AdminUID` isn't a valid UID or is empty. upstream proxy server. Zero or negative value disables it. Default is 0 (disabled). `LoopbackTcpSendBuffer` is the number of bytes to use for the tcp loopback send buffer. Use a low value like 4096 for a server-to-server bridge. + `LoopbackTcpReceiveBuffer` is the number of bytes to use for the tcp loopback receive buffer. Use a low value like 4096 for a server-to-server bridge. -These 2 options are not normally needed except when setting up a tcp server-to-server bridge using a shadowsocks or similar tcp server in the `ProxyBook` to reduce tcp performance degradation due to bufferbloat across the bridge. +`RemoteTcpSendBuffer` is the number of bytes to use for the tcp remote send buffer. Use a low value like 4096 for a server-to-server bridge. + +`RemoteTcpReceiveBuffer` is the number of bytes to use for the tcp remote receive buffer. Use a low value like 4096 for a server-to-server bridge. + +These 4 options are not normally needed except when setting up a tcp server-to-server bridge using a shadowsocks or similar tcp server in the `ProxyBook` to reduce tcp performance degradation due to bufferbloat across the bridge. ### Client diff --git a/internal/client/connector.go b/internal/client/connector.go index 1b283d8..d6c1c9a 100644 --- a/internal/client/connector.go +++ b/internal/client/connector.go @@ -32,6 +32,9 @@ func MakeSession(connConfig RemoteConnConfig, authInfo AuthInfo, dialer common.D goto makeconn } + sendBufferSize := connConfig.TcpSendBuffer + receiveBufferSize := connConfig.TcpReceiveBuffer + tcpConn, ok := remoteConn.(*net.TCPConn) if ok { syscallConn, err := tcpConn.SyscallConn() @@ -40,6 +43,22 @@ func MakeSession(connConfig RemoteConnConfig, authInfo AuthInfo, dialer common.D } err = syscallConn.Control(func(fd uintptr) { + if sendBufferSize > 0 { + log.Debugf("Setting remote connection tcp send buffer: %d", sendBufferSize) + err := syscall.SetsockoptInt(common.Platformfd(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, sendBufferSize) + if err != nil { + log.Errorf("setsocketopt SO_SNDBUF: %s\n", err) + } + } + + if receiveBufferSize > 0 { + log.Debugf("Setting remote connection tcp receive buffer: %d", receiveBufferSize) + err = syscall.SetsockoptInt(common.Platformfd(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, receiveBufferSize) + if err != nil { + log.Errorf("setsocketopt SO_RCVBUF: %s\n", err) + } + } + err = syscall.SetsockoptInt(common.Platformfd(fd), syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1) if err != nil { log.Errorf("setsocketopt TCP_NODELAY: %s\n", err) diff --git a/internal/client/state.go b/internal/client/state.go index 4a5e0e5..cd11e90 100644 --- a/internal/client/state.go +++ b/internal/client/state.go @@ -42,14 +42,18 @@ type RawConfig struct { KeepAlive int // nullable LoopbackTcpSendBuffer int // nullable LoopbackTcpReceiveBuffer int // nullable + RemoteTcpSendBuffer int // nullable + RemoteTcpReceiveBuffer int // nullable } type RemoteConnConfig struct { - Singleplex bool - NumConn int - KeepAlive time.Duration - RemoteAddr string - TransportMaker func() Transport + Singleplex bool + NumConn int + KeepAlive time.Duration + RemoteAddr string + TransportMaker func() Transport + TcpSendBuffer int + TcpReceiveBuffer int } type LocalConnConfig struct { @@ -291,5 +295,13 @@ func (raw *RawConfig) ProcessRawConfig(worldState common.WorldState) (local Loca local.TcpReceiveBuffer = raw.LoopbackTcpReceiveBuffer } + if raw.RemoteTcpSendBuffer > 0 { + remote.TcpSendBuffer = raw.RemoteTcpSendBuffer + } + + if raw.RemoteTcpReceiveBuffer > 0 { + remote.TcpReceiveBuffer = raw.RemoteTcpReceiveBuffer + } + return }