context.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // Copyright (c) 2022 Tailscale Inc & AUTHORS All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package tailssh
  5. import (
  6. "context"
  7. "sync"
  8. "time"
  9. )
  10. // sshContext is the context.Context implementation we use for SSH
  11. // that adds a CloseWithError method. Otherwise it's just a normalish
  12. // Context.
  13. type sshContext struct {
  14. underlying context.Context
  15. cancel context.CancelFunc // cancels underlying
  16. mu sync.Mutex
  17. closed bool
  18. err error
  19. }
  20. func newSSHContext(ctx context.Context) *sshContext {
  21. ctx, cancel := context.WithCancel(ctx)
  22. return &sshContext{underlying: ctx, cancel: cancel}
  23. }
  24. func (ctx *sshContext) CloseWithError(err error) {
  25. ctx.mu.Lock()
  26. defer ctx.mu.Unlock()
  27. if ctx.closed {
  28. return
  29. }
  30. ctx.closed = true
  31. ctx.err = err
  32. ctx.cancel()
  33. }
  34. func (ctx *sshContext) Err() error {
  35. ctx.mu.Lock()
  36. defer ctx.mu.Unlock()
  37. return ctx.err
  38. }
  39. func (ctx *sshContext) Done() <-chan struct{} { return ctx.underlying.Done() }
  40. func (ctx *sshContext) Deadline() (deadline time.Time, ok bool) { return }
  41. func (ctx *sshContext) Value(k any) any { return ctx.underlying.Value(k) }
  42. // userVisibleError is a wrapper around an error that implements
  43. // SSHTerminationError, so msg is written to their session.
  44. type userVisibleError struct {
  45. msg string
  46. error
  47. }
  48. func (ue userVisibleError) SSHTerminationMessage() string { return ue.msg }
  49. // SSHTerminationError is implemented by errors that terminate an SSH
  50. // session and should be written to user's sessions.
  51. type SSHTerminationError interface {
  52. error
  53. SSHTerminationMessage() string
  54. }