aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/exp/ssh/channel.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/exp/ssh/channel.go')
-rw-r--r--libgo/go/exp/ssh/channel.go318
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
-}