mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 10:44:02 +03:00
Change algorithm of TCP relaying
This commit is contained in:
+4
-29
@@ -5,8 +5,6 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/libp2p/go-reuseport"
|
||||
)
|
||||
|
||||
type defaultDialer struct {
|
||||
@@ -31,36 +29,14 @@ func (d *defaultDialer) DialContext(ctx context.Context, network, address string
|
||||
return nil, fmt.Errorf("cannot dial to %s: %w", address, err)
|
||||
}
|
||||
|
||||
tcpConn, ok := conn.(*net.TCPConn)
|
||||
if !ok {
|
||||
panic("conn type is not tcp")
|
||||
}
|
||||
|
||||
if err := tcpConn.SetNoDelay(true); err != nil {
|
||||
// we do not need to call to end user. End users call us.
|
||||
if err := SetServerSocketOptions(conn, d.bufferSize); err != nil {
|
||||
conn.Close()
|
||||
|
||||
return nil, fmt.Errorf("cannot set TCP_NO_DELAY: %w", err)
|
||||
return nil, fmt.Errorf("cannot set socket options: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetReadBuffer(d.bufferSize); err != nil {
|
||||
tcpConn.Close()
|
||||
|
||||
return nil, fmt.Errorf("cannot set read buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetWriteBuffer(d.bufferSize); err != nil {
|
||||
tcpConn.Close()
|
||||
|
||||
return nil, fmt.Errorf("cannot set write buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := tcpConn.SetKeepAlive(true); err != nil {
|
||||
tcpConn.Close()
|
||||
|
||||
return nil, fmt.Errorf("cannot enable keep-alive: %w", err)
|
||||
}
|
||||
|
||||
return tcpConn, nil
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// NewDefaultDialer build a new dialer which dials bypassing proxies
|
||||
@@ -87,7 +63,6 @@ func NewDefaultDialer(timeout time.Duration, bufferSize int) (Dialer, error) {
|
||||
return &defaultDialer{
|
||||
Dialer: net.Dialer{
|
||||
Timeout: timeout,
|
||||
Control: reuseport.Control,
|
||||
},
|
||||
bufferSize: bufferSize,
|
||||
}, nil
|
||||
|
||||
@@ -70,6 +70,10 @@ const (
|
||||
|
||||
// DNSTimeout defines a timeout for DNS queries.
|
||||
DNSTimeout = 5 * time.Second
|
||||
|
||||
// tcpLingerTimeout defines a number of seconds to wait for sending
|
||||
// unacknowledged data.
|
||||
tcpLingerTimeout = 1
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// SetClientSocketOptions tunes a TCP socket that represents a connection to
|
||||
// end user (not Telegram service or fronting domain).
|
||||
func SetClientSocketOptions(conn net.Conn, bufferSize int) error {
|
||||
tcpConn := conn.(*net.TCPConn) // nolint: forcetypeassert
|
||||
|
||||
if err := tcpConn.SetNoDelay(false); err != nil {
|
||||
return fmt.Errorf("cannot disable TCP_NO_DELAY: %w", err)
|
||||
}
|
||||
|
||||
return setCommonSocketOptions(tcpConn, bufferSize)
|
||||
}
|
||||
|
||||
// SetServerSocketOptions tunes a TCP socket that represents a connection to
|
||||
// remote server like Telegram or fronting domain (but not end user).
|
||||
func SetServerSocketOptions(conn net.Conn, bufferSize int) error {
|
||||
tcpConn := conn.(*net.TCPConn) // nolint: forcetypeassert
|
||||
|
||||
if err := tcpConn.SetNoDelay(true); err != nil {
|
||||
return fmt.Errorf("cannot enable TCP_NO_DELAY: %w", err)
|
||||
}
|
||||
|
||||
return setCommonSocketOptions(tcpConn, bufferSize)
|
||||
}
|
||||
|
||||
func setCommonSocketOptions(conn *net.TCPConn, bufferSize int) error {
|
||||
if err := conn.SetReadBuffer(bufferSize); err != nil {
|
||||
return fmt.Errorf("cannot set read buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := conn.SetWriteBuffer(bufferSize); err != nil {
|
||||
return fmt.Errorf("cannot set write buffer size: %w", err)
|
||||
}
|
||||
|
||||
if err := conn.SetKeepAlive(false); err != nil {
|
||||
return fmt.Errorf("cannot disable TCP keepalive probes: %w", err)
|
||||
}
|
||||
|
||||
if err := conn.SetLinger(tcpLingerTimeout); err != nil {
|
||||
return fmt.Errorf("cannot set TCP linger timeout: %w", err)
|
||||
}
|
||||
|
||||
rawConn, err := conn.SyscallConn()
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot get underlying raw connection")
|
||||
}
|
||||
|
||||
rawConn.Control(func(fd uintptr) { // nolint: errcheck
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("cannot set SO_REUSEADDR: %w", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("cannot set SO_REUSEPORT: %w", err)
|
||||
}
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user