diff --git a/config/config.go b/config/config.go index 3ce4381..9b11c62 100644 --- a/config/config.go +++ b/config/config.go @@ -231,8 +231,9 @@ type SSHStdinserverConnect struct { type LocalConnect struct { ConnectCommon `yaml:",inline"` - ListenerName string `yaml:"listener_name"` - ClientIdentity string `yaml:"client_identity"` + ListenerName string `yaml:"listener_name"` + ClientIdentity string `yaml:"client_identity"` + DialTimeout time.Duration `yaml:"dial_timeout,zeropositive,default=2s"` } type ServeEnum struct { diff --git a/docs/configuration/transports.rst b/docs/configuration/transports.rst index 075e918..e471006 100644 --- a/docs/configuration/transports.rst +++ b/docs/configuration/transports.rst @@ -345,5 +345,6 @@ The ``client_identity`` is used by the sink as documented above. type: local listener_name: localsink client_identity: local_backup + dial_timeout: 2s # optional, 0 for no timeout ... diff --git a/transport/local/connect_local.go b/transport/local/connect_local.go index fc1af56..ac82884 100644 --- a/transport/local/connect_local.go +++ b/transport/local/connect_local.go @@ -12,6 +12,7 @@ import ( type LocalConnecter struct { listenerName string clientIdentity string + dialTimeout time.Duration } func LocalConnecterFromConfig(in *config.LocalConnect) (*LocalConnecter, error) { @@ -21,13 +22,24 @@ func LocalConnecterFromConfig(in *config.LocalConnect) (*LocalConnecter, error) if in.ListenerName == "" { return nil, fmt.Errorf("ListenerName must not be empty") } - return &LocalConnecter{listenerName: in.ListenerName, clientIdentity: in.ClientIdentity}, nil + if in.DialTimeout < 0 { + return nil, fmt.Errorf("DialTimeout must be zero or positive") + } + cn := &LocalConnecter{ + listenerName: in.ListenerName, + clientIdentity: in.ClientIdentity, + dialTimeout: in.DialTimeout, + } + return cn, nil } func (c *LocalConnecter) Connect(dialCtx context.Context) (transport.Wire, error) { l := GetLocalListener(c.listenerName) - dialCtx, cancel := context.WithTimeout(dialCtx, 1*time.Second) // fail fast, config error by user is very likely - defer cancel() + if c.dialTimeout > 0 { + ctx, cancel := context.WithTimeout(dialCtx, c.dialTimeout) + defer cancel() + dialCtx = ctx // shadow + } w, err := l.Connect(dialCtx, c.clientIdentity) if err == context.DeadlineExceeded { return nil, fmt.Errorf("local listener %q not reachable", c.listenerName)