This repository has been archived by the owner on Oct 2, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
channelWrapper.go
135 lines (124 loc) · 2.83 KB
/
channelWrapper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package sshserver
import (
"errors"
"fmt"
"io"
"sync"
"github.com/containerssh/log"
"golang.org/x/crypto/ssh"
)
type channelWrapper struct {
channel ssh.Channel
logger log.Logger
lock *sync.Mutex
exitSent bool
exitSignalSent bool
closedWrite bool
closed bool
}
func (c *channelWrapper) Stdin() io.Reader {
if c.channel == nil {
panic(fmt.Errorf("BUG: stdin requested before channel is open"))
}
return c.channel
}
func (c *channelWrapper) Stdout() io.Writer {
if c.channel == nil {
panic(fmt.Errorf("BUG: stdout requested before channel is open"))
}
return c.channel
}
func (c *channelWrapper) Stderr() io.Writer {
if c.channel == nil {
panic(fmt.Errorf("BUG: stderr requested before channel is open"))
}
return c.channel.Stderr()
}
func (c *channelWrapper) ExitStatus(exitCode uint32) {
c.lock.Lock()
defer c.lock.Unlock()
if c.channel == nil {
panic(fmt.Errorf("BUG: exit status sent before channel is open"))
}
c.logger.Debug(log.NewMessage(
MExit,
"Program exited with status %d",
exitCode,
).Label("exitCode", exitCode))
if c.exitSent || c.closed {
return
}
c.exitSent = true
if _, err := c.channel.SendRequest(
"exit-status",
false,
ssh.Marshal(exitStatusPayload{
ExitStatus: exitCode,
})); err != nil {
if !errors.Is(err, io.EOF) {
c.logger.Debug(log.Wrap(
err,
EExitCodeFailed,
"Failed to send exit status to client",
))
}
}
}
func (c *channelWrapper) ExitSignal(signal string, coreDumped bool, errorMessage string, languageTag string) {
c.lock.Lock()
defer c.lock.Unlock()
if c.channel == nil {
panic(fmt.Errorf("BUG: exit signal sent before channel is open"))
}
c.logger.Debug(log.NewMessage(
MExitSignal,
"Program exited with signal %s",
signal,
).Label("signal", signal).Label("coreDumped", coreDumped))
if c.exitSignalSent || c.closed {
return
}
c.exitSignalSent = true
if _, err := c.channel.SendRequest(
"exit-signal",
false,
ssh.Marshal(exitSignalPayload{
Signal: signal,
CoreDumped: coreDumped,
ErrorMessage: errorMessage,
LanguageTag: languageTag,
})); err != nil {
if !errors.Is(err, io.EOF) {
c.logger.Debug(log.Wrap(
err,
EExitCodeFailed,
"Failed to send exit status to client",
))
}
}
}
func (c *channelWrapper) CloseWrite() error {
c.lock.Lock()
defer c.lock.Unlock()
if c.channel == nil {
panic(fmt.Errorf("BUG: channel closed for writing before channel is open"))
}
if c.closed || c.closedWrite {
return nil
}
return c.channel.CloseWrite()
}
func (c *channelWrapper) Close() error {
c.lock.Lock()
defer c.lock.Unlock()
if c.channel == nil {
panic(fmt.Errorf("BUG: channel closed before channel is open"))
}
c.closed = true
return c.channel.Close()
}
func (c *channelWrapper) onClose() {
c.lock.Lock()
defer c.lock.Unlock()
c.closed = true
}