feat: add quic_settings into client config

fix: #420

allow user to disable auto reconnect when quic disconnected, along with
quic handshake & idle timeout.

an extra failed request would be required to make the client exit in
case of quic disconnected, but i don't think this would be a problem in
the common usage.
This commit is contained in:
Haruue Icymoon
2022-08-31 16:34:51 +08:00
parent f7de18fd43
commit 4cd18e6685
3 changed files with 27 additions and 3 deletions

View File

@@ -75,10 +75,15 @@ func client(config *clientConfig) {
MaxStreamReceiveWindow: config.ReceiveWindowConn, MaxStreamReceiveWindow: config.ReceiveWindowConn,
InitialConnectionReceiveWindow: config.ReceiveWindow, InitialConnectionReceiveWindow: config.ReceiveWindow,
MaxConnectionReceiveWindow: config.ReceiveWindow, MaxConnectionReceiveWindow: config.ReceiveWindow,
KeepAlivePeriod: KeepAlivePeriod, HandshakeIdleTimeout: time.Duration(config.QUICSettings.HandshakeIdleTimeout) * time.Second,
MaxIdleTimeout: time.Duration(config.QUICSettings.MaxIdleTimeout) * time.Second,
DisablePathMTUDiscovery: config.DisableMTUDiscovery, DisablePathMTUDiscovery: config.DisableMTUDiscovery,
EnableDatagrams: true, EnableDatagrams: true,
} }
quicConfig.KeepAlivePeriod = quicConfig.MaxIdleTimeout / 2
if quicConfig.KeepAlivePeriod == 0 || quicConfig.KeepAlivePeriod > KeepAlivePeriod {
quicConfig.KeepAlivePeriod = KeepAlivePeriod
}
if config.ReceiveWindowConn == 0 { if config.ReceiveWindowConn == 0 {
quicConfig.InitialStreamReceiveWindow = DefaultStreamReceiveWindow quicConfig.InitialStreamReceiveWindow = DefaultStreamReceiveWindow
quicConfig.MaxStreamReceiveWindow = DefaultStreamReceiveWindow quicConfig.MaxStreamReceiveWindow = DefaultStreamReceiveWindow
@@ -141,7 +146,17 @@ func client(config *clientConfig) {
transport.DefaultClientTransport, up, down, transport.DefaultClientTransport, up, down,
func(refBPS uint64) congestion.CongestionControl { func(refBPS uint64) congestion.CongestionControl {
return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS)) return hyCongestion.NewBrutalSender(congestion.ByteCount(refBPS))
}, obfuscator) }, obfuscator, func(err error) {
if config.QUICSettings.DisableAutoReconnect {
logrus.WithFields(logrus.Fields{
"error": err,
}).Fatal("QUIC connection lost, exiting...")
} else {
logrus.WithFields(logrus.Fields{
"error": err,
}).Info("QUIC connection lost, reconnecting...")
}
})
if err != nil { if err != nil {
logrus.WithField("error", err).Error("Failed to initialize client") logrus.WithField("error", err).Error("Failed to initialize client")
if try <= config.Retry || config.Retry < 0 { if try <= config.Retry || config.Retry < 0 {

View File

@@ -147,6 +147,11 @@ type clientConfig struct {
Retry int `json:"retry"` Retry int `json:"retry"`
RetryInterval int `json:"retry_interval"` RetryInterval int `json:"retry_interval"`
// Optional below // Optional below
QUICSettings struct {
DisableAutoReconnect bool `json:"disable_auto_reconnect"`
HandshakeIdleTimeout int `json:"handshake_idle_timeout"`
MaxIdleTimeout int `json:"max_idle_timeout"`
} `json:"quic_settings"`
SOCKS5 struct { SOCKS5 struct {
Listen string `json:"listen"` Listen string `json:"listen"`
Timeout int `json:"timeout"` Timeout int `json:"timeout"`

View File

@@ -44,11 +44,13 @@ type Client struct {
udpSessionMutex sync.RWMutex udpSessionMutex sync.RWMutex
udpSessionMap map[uint32]chan *udpMessage udpSessionMap map[uint32]chan *udpMessage
udpDefragger defragger udpDefragger defragger
quicReconnectFunc func(err error)
} }
func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config, func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config,
transport *transport.ClientTransport, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory, transport *transport.ClientTransport, sendBPS uint64, recvBPS uint64, congestionFactory CongestionFactory,
obfuscator obfs.Obfuscator, obfuscator obfs.Obfuscator, quicReconnectFunc func(err error),
) (*Client, error) { ) (*Client, error) {
quicConfig.DisablePathMTUDiscovery = quicConfig.DisablePathMTUDiscovery || pmtud_fix.DisablePathMTUDiscovery quicConfig.DisablePathMTUDiscovery = quicConfig.DisablePathMTUDiscovery || pmtud_fix.DisablePathMTUDiscovery
c := &Client{ c := &Client{
@@ -62,6 +64,7 @@ func NewClient(serverAddr string, protocol string, auth []byte, tlsConfig *tls.C
obfuscator: obfuscator, obfuscator: obfuscator,
tlsConfig: tlsConfig, tlsConfig: tlsConfig,
quicConfig: quicConfig, quicConfig: quicConfig,
quicReconnectFunc: quicReconnectFunc,
} }
if err := c.connectToServer(); err != nil { if err := c.connectToServer(); err != nil {
return nil, err return nil, err
@@ -173,6 +176,7 @@ func (c *Client) openStreamWithReconnect() (quic.Connection, quic.Stream, error)
// Temporary error, just return // Temporary error, just return
return nil, nil, err return nil, nil, err
} }
c.quicReconnectFunc(err)
// Permanent error, need to reconnect // Permanent error, need to reconnect
if err := c.connectToServer(); err != nil { if err := c.connectToServer(); err != nil {
// Still error, oops // Still error, oops