Source File
channel.go
Belonging Package
golang.org/x/crypto/ssh
package ssh
import (
)
const (
channelWindowSize = 64 * channelMaxPacket
)
Reject(reason RejectionReason, message string) error
ChannelType() string
ExtraData() []byte
}
Close() error
CloseWrite() error
Stderr() io.ReadWriter
}
type RejectionReason uint32
const (
Prohibited RejectionReason = iota + 1
ConnectionFailed
UnknownChannelType
ResourceShortage
)
func ( RejectionReason) () string {
switch {
case Prohibited:
return "administratively prohibited"
case ConnectionFailed:
return "connect failed"
case UnknownChannelType:
return "unknown channel type"
case ResourceShortage:
return "resource shortage"
}
return fmt.Sprintf("unknown reason %d", int())
}
func ( uint32, int) uint32 {
if < uint32() {
return
}
return uint32()
}
type channelDirection uint8
const (
channelInbound channelDirection = iota
channelOutbound
)
msg chan interface{}
packetPool map[uint32][]byte
}
func ( *channel) ( []byte) error {
.writeMu.Lock()
if .sentClose {
.writeMu.Unlock()
return io.EOF
}
.sentClose = ([0] == msgChannelClose)
:= .mux.conn.writePacket()
.writeMu.Unlock()
return
}
func ( *channel) ( interface{}) error {
if debugMux {
log.Printf("send(%d): %#v", .mux.chanList.offset, )
}
:= Marshal()
binary.BigEndian.PutUint32([1:], .remoteId)
return .writePacket()
}
:= byte(msgChannelData)
:= uint32(9)
if > 0 {
+= 4
= msgChannelExtendedData
}
.writeMu.Lock()
.writeMu.Unlock()
for len() > 0 {
:= min(.maxRemotePayload, len())
if , = .remoteWin.reserve(); != nil {
return ,
}
if := + ; uint32(cap()) < {
= make([]byte, )
} else {
= [:]
}
:= [:]
[0] =
binary.BigEndian.PutUint32([1:], .remoteId)
if > 0 {
binary.BigEndian.PutUint32([5:], uint32())
}
binary.BigEndian.PutUint32([-4:], uint32(len()))
copy([:], )
if = .writePacket(); != nil {
return ,
}
+= len()
= [len():]
}
.writeMu.Lock()
.packetPool[] =
.writeMu.Unlock()
return ,
}
func ( *channel) ( []byte) error {
:= 9
:= [0] == msgChannelExtendedData
if {
= 13
}
.myWindow += uint32()
.windowMu.Unlock()
return .sendMessage(windowAdjustMsg{
AdditionalBytes: uint32(),
})
}
func ( *channel) ( []byte, uint32) ( int, error) {
switch {
case 1:
, = .extPending.Read()
case 0:
, = .pending.Read()
default:
return 0, fmt.Errorf("ssh: extended code %d unimplemented", )
}
if > 0 {
func ( *channel) () error {
if .direction == channelInbound {
return errors.New("ssh: channel response message received on inbound channel")
}
if .decided {
return errors.New("ssh: duplicate response received for channel")
}
.decided = true
return nil
}
func ( *channel) ( []byte) error {
switch [0] {
case msgChannelData, msgChannelExtendedData:
return .handleData()
case msgChannelClose:
.sendMessage(channelCloseMsg{PeersID: .remoteId})
.mux.chanList.remove(.localId)
.close()
return nil
.extPending.eof()
.pending.eof()
return nil
}
, := decode()
if != nil {
return
}
switch msg := .(type) {
case *channelOpenFailureMsg:
if := .responseMessageReceived(); != nil {
return
}
.mux.chanList.remove(.PeersID)
.msg <-
case *channelOpenConfirmMsg:
if := .responseMessageReceived(); != nil {
return
}
if .MaxPacketSize < minPacketLength || .MaxPacketSize > 1<<31 {
return fmt.Errorf("ssh: invalid MaxPacketSize %d from peer", .MaxPacketSize)
}
.remoteId = .MyID
.maxRemotePayload = .MaxPacketSize
.remoteWin.add(.MyWindow)
.msg <-
case *windowAdjustMsg:
if !.remoteWin.add(.AdditionalBytes) {
return fmt.Errorf("ssh: invalid window update for %d bytes", .AdditionalBytes)
}
case *channelRequestMsg:
:= Request{
Type: .Request,
WantReply: .WantReply,
Payload: .RequestSpecificData,
ch: ,
}
.incomingRequests <- &
default:
.msg <-
}
return nil
}
func ( *mux) ( string, channelDirection, []byte) *channel {
:= &channel{
remoteWin: window{Cond: newCond()},
myWindow: channelWindowSize,
pending: newBuffer(),
extPending: newBuffer(),
direction: ,
incomingRequests: make(chan *Request, chanSize),
msg: make(chan interface{}, chanSize),
chanType: ,
extraData: ,
mux: ,
packetPool: make(map[uint32][]byte),
}
.localId = .chanList.add()
return
}
var errUndecided = errors.New("ssh: must Accept or Reject channel")
var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
type extChannel struct {
code uint32
ch *channel
}
func ( *extChannel) ( []byte) ( int, error) {
return .ch.WriteExtended(, .code)
}
func ( *extChannel) ( []byte) ( int, error) {
return .ch.ReadExtended(, .code)
}
func ( *channel) () (Channel, <-chan *Request, error) {
if .decided {
return nil, nil, errDecidedAlready
}
.maxIncomingPayload = channelMaxPacket
:= channelOpenConfirmMsg{
PeersID: .remoteId,
MyID: .localId,
MyWindow: .myWindow,
MaxPacketSize: .maxIncomingPayload,
}
.decided = true
if := .sendMessage(); != nil {
return nil, nil,
}
return , .incomingRequests, nil
}
func ( *channel) ( RejectionReason, string) error {
if .decided {
return errDecidedAlready
}
:= channelOpenFailureMsg{
PeersID: .remoteId,
Reason: ,
Message: ,
Language: "en",
}
.decided = true
return .sendMessage()
}
func ( *channel) ( []byte) (int, error) {
if !.decided {
return 0, errUndecided
}
return .ReadExtended(, 0)
}
func ( *channel) ( []byte) (int, error) {
if !.decided {
return 0, errUndecided
}
return .WriteExtended(, 0)
}
func ( *channel) () error {
if !.decided {
return errUndecided
}
.sentEOF = true
return .sendMessage(channelEOFMsg{
PeersID: .remoteId})
}
func ( *channel) () error {
if !.decided {
return errUndecided
}
return .sendMessage(channelCloseMsg{
PeersID: .remoteId})
}
func ( *channel) ( uint32) io.ReadWriter {
if !.decided {
return nil
}
return &extChannel{, }
}
func ( *channel) () io.ReadWriter {
return .Extended(1)
}
func ( *channel) ( string, bool, []byte) (bool, error) {
if !.decided {
return false, errUndecided
}
if {
.sentRequestMu.Lock()
defer .sentRequestMu.Unlock()
}
:= channelRequestMsg{
PeersID: .remoteId,
Request: ,
WantReply: ,
RequestSpecificData: ,
}
if := .sendMessage(); != nil {
return false,
}
if {
, := (<-.msg)
if ! {
return false, io.EOF
}
switch .(type) {
case *channelRequestFailureMsg:
return false, nil
case *channelRequestSuccessMsg:
return true, nil
default:
return false, fmt.Errorf("ssh: unexpected response to channel request: %#v", )
}
}
return false, nil
}
func ( *channel) ( bool) error {
if !.decided {
return errUndecided
}
var interface{}
if ! {
= channelRequestFailureMsg{
PeersID: .remoteId,
}
} else {
= channelRequestSuccessMsg{
PeersID: .remoteId,
}
}
return .sendMessage()
}
func ( *channel) () string {
return .chanType
}
func ( *channel) () []byte {
return .extraData
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |