diff options
Diffstat (limited to 'libgo/go/exp/ssh/channel.go')
-rw-r--r-- | libgo/go/exp/ssh/channel.go | 318 |
1 files changed, 0 insertions, 318 deletions
diff --git a/libgo/go/exp/ssh/channel.go b/libgo/go/exp/ssh/channel.go deleted file mode 100644 index 9d75f37..0000000 --- a/libgo/go/exp/ssh/channel.go +++ /dev/null @@ -1,318 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package ssh - -import ( - "errors" - "io" - "sync" -) - -// A Channel is an ordered, reliable, duplex stream that is multiplexed over an -// SSH connection. -type Channel interface { - // Accept accepts the channel creation request. - Accept() error - // Reject rejects the channel creation request. After calling this, no - // other methods on the Channel may be called. If they are then the - // peer is likely to signal a protocol error and drop the connection. - Reject(reason RejectionReason, message string) error - - // Read may return a ChannelRequest as an error. - Read(data []byte) (int, error) - Write(data []byte) (int, error) - Close() error - - // AckRequest either sends an ack or nack to the channel request. - AckRequest(ok bool) error - - // ChannelType returns the type of the channel, as supplied by the - // client. - ChannelType() string - // ExtraData returns the arbitary payload for this channel, as supplied - // by the client. This data is specific to the channel type. - ExtraData() []byte -} - -// ChannelRequest represents a request sent on a channel, outside of the normal -// stream of bytes. It may result from calling Read on a Channel. -type ChannelRequest struct { - Request string - WantReply bool - Payload []byte -} - -func (c ChannelRequest) Error() string { - return "channel request received" -} - -// RejectionReason is an enumeration used when rejecting channel creation -// requests. See RFC 4254, section 5.1. -type RejectionReason int - -const ( - Prohibited RejectionReason = iota + 1 - ConnectionFailed - UnknownChannelType - ResourceShortage -) - -type channel struct { - // immutable once created - chanType string - extraData []byte - - theyClosed bool - theySentEOF bool - weClosed bool - dead bool - - serverConn *ServerConn - myId, theirId uint32 - myWindow, theirWindow uint32 - maxPacketSize uint32 - err error - - pendingRequests []ChannelRequest - pendingData []byte - head, length int - - // This lock is inferior to serverConn.lock - lock sync.Mutex - cond *sync.Cond -} - -func (c *channel) Accept() error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - confirm := channelOpenConfirmMsg{ - PeersId: c.theirId, - MyId: c.myId, - MyWindow: c.myWindow, - MaxPacketSize: c.maxPacketSize, - } - return c.serverConn.writePacket(marshal(msgChannelOpenConfirm, confirm)) -} - -func (c *channel) Reject(reason RejectionReason, message string) error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - reject := channelOpenFailureMsg{ - PeersId: c.theirId, - Reason: uint32(reason), - Message: message, - Language: "en", - } - return c.serverConn.writePacket(marshal(msgChannelOpenFailure, reject)) -} - -func (c *channel) handlePacket(packet interface{}) { - c.lock.Lock() - defer c.lock.Unlock() - - switch packet := packet.(type) { - case *channelRequestMsg: - req := ChannelRequest{ - Request: packet.Request, - WantReply: packet.WantReply, - Payload: packet.RequestSpecificData, - } - - c.pendingRequests = append(c.pendingRequests, req) - c.cond.Signal() - case *channelCloseMsg: - c.theyClosed = true - c.cond.Signal() - case *channelEOFMsg: - c.theySentEOF = true - c.cond.Signal() - default: - panic("unknown packet type") - } -} - -func (c *channel) handleData(data []byte) { - c.lock.Lock() - defer c.lock.Unlock() - - // The other side should never send us more than our window. - if len(data)+c.length > len(c.pendingData) { - // TODO(agl): we should tear down the channel with a protocol - // error. - return - } - - c.myWindow -= uint32(len(data)) - for i := 0; i < 2; i++ { - tail := c.head + c.length - if tail > len(c.pendingData) { - tail -= len(c.pendingData) - } - n := copy(c.pendingData[tail:], data) - data = data[n:] - c.length += n - } - - c.cond.Signal() -} - -func (c *channel) Read(data []byte) (n int, err error) { - c.lock.Lock() - defer c.lock.Unlock() - - if c.err != nil { - return 0, c.err - } - - if c.myWindow <= uint32(len(c.pendingData))/2 { - packet := marshal(msgChannelWindowAdjust, windowAdjustMsg{ - PeersId: c.theirId, - AdditionalBytes: uint32(len(c.pendingData)) - c.myWindow, - }) - if err := c.serverConn.writePacket(packet); err != nil { - return 0, err - } - } - - for { - if c.theySentEOF || c.theyClosed || c.dead { - return 0, io.EOF - } - - if len(c.pendingRequests) > 0 { - req := c.pendingRequests[0] - if len(c.pendingRequests) == 1 { - c.pendingRequests = nil - } else { - oldPendingRequests := c.pendingRequests - c.pendingRequests = make([]ChannelRequest, len(oldPendingRequests)-1) - copy(c.pendingRequests, oldPendingRequests[1:]) - } - - return 0, req - } - - if c.length > 0 { - tail := c.head + c.length - if tail > len(c.pendingData) { - tail -= len(c.pendingData) - } - n = copy(data, c.pendingData[c.head:tail]) - c.head += n - c.length -= n - if c.head == len(c.pendingData) { - c.head = 0 - } - return - } - - c.cond.Wait() - } - - panic("unreachable") -} - -func (c *channel) Write(data []byte) (n int, err error) { - for len(data) > 0 { - c.lock.Lock() - if c.dead || c.weClosed { - return 0, io.EOF - } - - if c.theirWindow == 0 { - c.cond.Wait() - continue - } - c.lock.Unlock() - - todo := data - if uint32(len(todo)) > c.theirWindow { - todo = todo[:c.theirWindow] - } - - packet := make([]byte, 1+4+4+len(todo)) - packet[0] = msgChannelData - packet[1] = byte(c.theirId >> 24) - packet[2] = byte(c.theirId >> 16) - packet[3] = byte(c.theirId >> 8) - packet[4] = byte(c.theirId) - packet[5] = byte(len(todo) >> 24) - packet[6] = byte(len(todo) >> 16) - packet[7] = byte(len(todo) >> 8) - packet[8] = byte(len(todo)) - copy(packet[9:], todo) - - c.serverConn.lock.Lock() - if err = c.serverConn.writePacket(packet); err != nil { - c.serverConn.lock.Unlock() - return - } - c.serverConn.lock.Unlock() - - n += len(todo) - data = data[len(todo):] - } - - return -} - -func (c *channel) Close() error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - if c.weClosed { - return errors.New("ssh: channel already closed") - } - c.weClosed = true - - closeMsg := channelCloseMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelClose, closeMsg)) -} - -func (c *channel) AckRequest(ok bool) error { - c.serverConn.lock.Lock() - defer c.serverConn.lock.Unlock() - - if c.serverConn.err != nil { - return c.serverConn.err - } - - if ok { - ack := channelRequestSuccessMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelSuccess, ack)) - } else { - ack := channelRequestFailureMsg{ - PeersId: c.theirId, - } - return c.serverConn.writePacket(marshal(msgChannelFailure, ack)) - } - panic("unreachable") -} - -func (c *channel) ChannelType() string { - return c.chanType -} - -func (c *channel) ExtraData() []byte { - return c.extraData -} |