Skip to content

Commit 29c56cc

Browse files
authored
register channel to receive ssh channel close signal
1 parent 67b1361 commit 29c56cc

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

ssh/channel.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,16 @@ const (
2222
// We follow OpenSSH here.
2323
channelWindowSize = 64 * channelMaxPacket
2424
)
25+
type CloseReason int
26+
27+
const (
28+
// server send close
29+
SEND_SERVER_CLOSE CloseReason = iota
30+
// recv channel close
31+
RECV_CHANNEL_CLOSE
32+
// recv channel EOF
33+
RECV_CHANNEL_EOF
34+
)
2535

2636
// NewChannel represents an incoming request to a channel. It must either be
2737
// accepted for use by calling Accept, or rejected by calling Reject.
@@ -76,6 +86,12 @@ type Channel interface {
7686
// safely be read and written from a different goroutine than
7787
// Read and Write respectively.
7888
Stderr() io.ReadWriter
89+
90+
// RegisterCloseReasonSignal registers a channel to receive
91+
// close reason signal from server or client. The channel
92+
// must handel singal ,or it will block a goroutine.
93+
// During the time no channel is registered signals are ignored.
94+
RegisterCloseReasonSignal(ch chan CloseReason)
7995
}
8096

8197
// Request is a request sent outside of the normal stream of
@@ -203,6 +219,16 @@ type channel struct {
203219
// packetPool has a buffer for each extended channel ID to
204220
// save allocations during writes.
205221
packetPool map[uint32][]byte
222+
223+
closeSignalChan chan CloseReason
224+
}
225+
// send close reason to channel if channel registered.
226+
// use this with go ch.sendCloseReason or it may block
227+
// the request.
228+
func (ch *channel) sendCloseReason(reason CloseReason) {
229+
if ch.closeSignalChan != nil {
230+
ch.closeSignalChan <- reason
231+
}
206232
}
207233

208234
// writePacket sends a packet. If the packet is a channel close, it updates
@@ -415,12 +441,14 @@ func (ch *channel) handlePacket(packet []byte) error {
415441
ch.sendMessage(channelCloseMsg{PeersID: ch.remoteId})
416442
ch.mux.chanList.remove(ch.localId)
417443
ch.close()
444+
go ch.sendCloseReason(RECV_CHANNEL_CLOSE)
418445
return nil
419446
case msgChannelEOF:
420447
// RFC 4254 is mute on how EOF affects dataExt messages but
421448
// it is logical to signal EOF at the same time.
422449
ch.extPending.eof()
423450
ch.pending.eof()
451+
go ch.sendCloseReason(RECV_CHANNEL_EOF)
424452
return nil
425453
}
426454

@@ -552,6 +580,7 @@ func (ch *channel) CloseWrite() error {
552580
return errUndecided
553581
}
554582
ch.sentEOF = true
583+
go ch.sendCloseReason(SEND_SERVER_CLOSE)
555584
return ch.sendMessage(channelEOFMsg{
556585
PeersID: ch.remoteId})
557586
}
@@ -560,7 +589,7 @@ func (ch *channel) Close() error {
560589
if !ch.decided {
561590
return errUndecided
562591
}
563-
592+
go ch.sendCloseReason(SEND_SERVER_CLOSE)
564593
return ch.sendMessage(channelCloseMsg{
565594
PeersID: ch.remoteId})
566595
}
@@ -577,7 +606,9 @@ func (ch *channel) Extended(code uint32) io.ReadWriter {
577606
func (ch *channel) Stderr() io.ReadWriter {
578607
return ch.Extended(1)
579608
}
580-
609+
func (ch *channel) RegisterCloseReasonSignal(c chan CloseReason) {
610+
ch.closeSignalChan = c
611+
}
581612
func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (bool, error) {
582613
if !ch.decided {
583614
return false, errUndecided

0 commit comments

Comments
 (0)