diff --git a/app/cmd/client.go b/app/cmd/client.go index bf11fef..3f51e86 100644 --- a/app/cmd/client.go +++ b/app/cmd/client.go @@ -136,6 +136,7 @@ func client(config *clientConfig) { for { try += 1 c, err := cs.NewClient(config.Server, auth, tlsConfig, quicConfig, pktConnFunc, up, down, config.FastOpen, + config.LazyStart, func(err error) { if config.QuitOnDisconnect { logrus.WithFields(logrus.Fields{ @@ -170,7 +171,11 @@ func client(config *clientConfig) { } } defer client.Close() - logrus.WithField("addr", config.Server).Info("Connected") + if config.LazyStart { + logrus.WithField("addr", config.Server).Info("Lazy start enabled, waiting for first connection") + } else { + logrus.WithField("addr", config.Server).Info("Connected") + } // Local errChan := make(chan error) diff --git a/app/cmd/config.go b/app/cmd/config.go index 65f7e4e..67b30f0 100644 --- a/app/cmd/config.go +++ b/app/cmd/config.go @@ -227,6 +227,7 @@ type clientConfig struct { ReceiveWindow uint64 `json:"recv_window"` DisableMTUDiscovery bool `json:"disable_mtu_discovery"` FastOpen bool `json:"fast_open"` + LazyStart bool `json:"lazy_start"` Resolver string `json:"resolver"` ResolvePreference string `json:"resolve_preference"` } diff --git a/core/cs/client.go b/core/cs/client.go index d139d3f..93d3249 100644 --- a/core/cs/client.go +++ b/core/cs/client.go @@ -49,7 +49,7 @@ type Client struct { } func NewClient(serverAddr string, auth []byte, tlsConfig *tls.Config, quicConfig *quic.Config, - pktConnFunc pktconns.ClientPacketConnFunc, sendBPS uint64, recvBPS uint64, fastOpen bool, + pktConnFunc pktconns.ClientPacketConnFunc, sendBPS uint64, recvBPS uint64, fastOpen bool, lazyStart bool, quicReconnectFunc func(err error), ) (*Client, error) { quicConfig.DisablePathMTUDiscovery = quicConfig.DisablePathMTUDiscovery || pmtud.DisablePathMTUDiscovery @@ -64,6 +64,9 @@ func NewClient(serverAddr string, auth []byte, tlsConfig *tls.Config, quicConfig pktConnFunc: pktConnFunc, quicReconnectFunc: quicReconnectFunc, } + if lazyStart { + return c, nil + } if err := c.connect(); err != nil { return nil, err } @@ -182,18 +185,20 @@ func (c *Client) openStreamWithReconnect() (quic.Connection, quic.Stream, error) if c.closed { return nil, nil, ErrClosed } - stream, err := c.quicConn.OpenStream() - if err == nil { - // All good - return c.quicConn, &qStream{stream}, nil - } - // Something is wrong - if nErr, ok := err.(net.Error); ok && nErr.Temporary() { - // Temporary error, just return - return nil, nil, err - } - if c.quicReconnectFunc != nil { - c.quicReconnectFunc(err) + if c.quicConn != nil { + stream, err := c.quicConn.OpenStream() + if err == nil { + // All good + return c.quicConn, &qStream{stream}, nil + } + // Something is wrong + if nErr, ok := err.(net.Error); ok && nErr.Temporary() { + // Temporary error, just return + return nil, nil, err + } + if c.quicReconnectFunc != nil { + c.quicReconnectFunc(err) + } } // Permanent error, need to reconnect if err := c.connect(); err != nil { @@ -201,7 +206,7 @@ func (c *Client) openStreamWithReconnect() (quic.Connection, quic.Stream, error) return nil, nil, err } // We are not going to try again even if it still fails the second time - stream, err = c.quicConn.OpenStream() + stream, err := c.quicConn.OpenStream() return c.quicConn, &qStream{stream}, err }