@@ -22,6 +22,16 @@ const (
22
22
// We follow OpenSSH here.
23
23
channelWindowSize = 64 * channelMaxPacket
24
24
)
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
+ )
25
35
26
36
// NewChannel represents an incoming request to a channel. It must either be
27
37
// accepted for use by calling Accept, or rejected by calling Reject.
@@ -76,6 +86,12 @@ type Channel interface {
76
86
// safely be read and written from a different goroutine than
77
87
// Read and Write respectively.
78
88
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 )
79
95
}
80
96
81
97
// Request is a request sent outside of the normal stream of
@@ -203,6 +219,16 @@ type channel struct {
203
219
// packetPool has a buffer for each extended channel ID to
204
220
// save allocations during writes.
205
221
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
+ }
206
232
}
207
233
208
234
// writePacket sends a packet. If the packet is a channel close, it updates
@@ -415,12 +441,14 @@ func (ch *channel) handlePacket(packet []byte) error {
415
441
ch .sendMessage (channelCloseMsg {PeersID : ch .remoteId })
416
442
ch .mux .chanList .remove (ch .localId )
417
443
ch .close ()
444
+ go ch .sendCloseReason (RECV_CHANNEL_CLOSE )
418
445
return nil
419
446
case msgChannelEOF :
420
447
// RFC 4254 is mute on how EOF affects dataExt messages but
421
448
// it is logical to signal EOF at the same time.
422
449
ch .extPending .eof ()
423
450
ch .pending .eof ()
451
+ go ch .sendCloseReason (RECV_CHANNEL_EOF )
424
452
return nil
425
453
}
426
454
@@ -552,6 +580,7 @@ func (ch *channel) CloseWrite() error {
552
580
return errUndecided
553
581
}
554
582
ch .sentEOF = true
583
+ go ch .sendCloseReason (SEND_SERVER_CLOSE )
555
584
return ch .sendMessage (channelEOFMsg {
556
585
PeersID : ch .remoteId })
557
586
}
@@ -560,7 +589,7 @@ func (ch *channel) Close() error {
560
589
if ! ch .decided {
561
590
return errUndecided
562
591
}
563
-
592
+ go ch . sendCloseReason ( SEND_SERVER_CLOSE )
564
593
return ch .sendMessage (channelCloseMsg {
565
594
PeersID : ch .remoteId })
566
595
}
@@ -577,7 +606,9 @@ func (ch *channel) Extended(code uint32) io.ReadWriter {
577
606
func (ch * channel ) Stderr () io.ReadWriter {
578
607
return ch .Extended (1 )
579
608
}
580
-
609
+ func (ch * channel ) RegisterCloseReasonSignal (c chan CloseReason ) {
610
+ ch .closeSignalChan = c
611
+ }
581
612
func (ch * channel ) SendRequest (name string , wantReply bool , payload []byte ) (bool , error ) {
582
613
if ! ch .decided {
583
614
return false , errUndecided
0 commit comments