// 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 (
	
	
	
	
	
	
)

const (
	minPacketLength = 9
	// channelMaxPacket contains the maximum number of bytes that will be
	// sent in a single packet. As per RFC 4253, section 6.1, 32k is also
	// the minimum.
	channelMaxPacket = 1 << 15
	// We follow OpenSSH here.
	channelWindowSize = 64 * channelMaxPacket
)

// NewChannel represents an incoming request to a channel. It must either be
// accepted for use by calling Accept, or rejected by calling Reject.
type NewChannel interface {
	// Accept accepts the channel creation request. It returns the Channel
	// and a Go channel containing SSH requests. The Go channel must be
	// serviced otherwise the Channel will hang.
	Accept() (Channel, <-chan *Request, error)

	// Reject rejects the channel creation request. After calling
	// this, no other methods on the Channel may be called.
	Reject(reason RejectionReason, message string) error

	// ChannelType returns the type of the channel, as supplied by the
	// client.
	ChannelType() string

	// ExtraData returns the arbitrary payload for this channel, as supplied
	// by the client. This data is specific to the channel type.
	ExtraData() []byte
}

// A Channel is an ordered, reliable, flow-controlled, duplex stream
// that is multiplexed over an SSH connection.
type Channel interface {
	// Read reads up to len(data) bytes from the channel.
	Read(data []byte) (int, error)

	// Write writes len(data) bytes to the channel.
	Write(data []byte) (int, error)

	// Close signals end of channel use. No data may be sent after this
	// call.
	Close() error

	// CloseWrite signals the end of sending in-band
	// data. Requests may still be sent, and the other side may
	// still send data
	CloseWrite() error

	// SendRequest sends a channel request.  If wantReply is true,
	// it will wait for a reply and return the result as a
	// boolean, otherwise the return value will be false. Channel
	// requests are out-of-band messages so they may be sent even
	// if the data stream is closed or blocked by flow control.
	// If the channel is closed before a reply is returned, io.EOF
	// is returned.
	SendRequest(name string, wantReply bool, payload []byte) (bool, error)

	// Stderr returns an io.ReadWriter that writes to this channel
	// with the extended data type set to stderr. Stderr may
	// safely be read and written from a different goroutine than
	// Read and Write respectively.
	Stderr() io.ReadWriter
}

// Request is a request sent outside of the normal stream of
// data. Requests can either be specific to an SSH channel, or they
// can be global.
type Request struct {
	Type      string
	WantReply bool
	Payload   []byte

	ch  *channel
	mux *mux
}

// Reply sends a response to a request. It must be called for all requests
// where WantReply is true and is a no-op otherwise. The payload argument is
// ignored for replies to channel-specific requests.
func ( *Request) ( bool,  []byte) error {
	if !.WantReply {
		return nil
	}

	if .ch == nil {
		return .mux.ackRequest(, )
	}

	return .ch.ackRequest()
}

// RejectionReason is an enumeration used when rejecting channel creation
// requests. See RFC 4254, section 5.1.
type RejectionReason uint32

const (
	Prohibited RejectionReason = iota + 1
	ConnectionFailed
	UnknownChannelType
	ResourceShortage
)

// String converts the rejection reason to human readable form.
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 min( uint32,  int) uint32 {
	if  < uint32() {
		return 
	}
	return uint32()
}

type channelDirection uint8

const (
	channelInbound channelDirection = iota
	channelOutbound
)

// channel is an implementation of the Channel interface that works
// with the mux class.
type channel struct {
	// R/O after creation
	chanType          string
	extraData         []byte
	localId, remoteId uint32

	// maxIncomingPayload and maxRemotePayload are the maximum
	// payload sizes of normal and extended data packets for
	// receiving and sending, respectively. The wire packet will
	// be 9 or 13 bytes larger (excluding encryption overhead).
	maxIncomingPayload uint32
	maxRemotePayload   uint32

	mux *mux

	// decided is set to true if an accept or reject message has been sent
	// (for outbound channels) or received (for inbound channels).
	decided bool

	// direction contains either channelOutbound, for channels created
	// locally, or channelInbound, for channels created by the peer.
	direction channelDirection

	// Pending internal channel messages.
	msg chan interface{}

	// Since requests have no ID, there can be only one request
	// with WantReply=true outstanding.  This lock is held by a
	// goroutine that has such an outgoing request pending.
	sentRequestMu sync.Mutex

	incomingRequests chan *Request

	sentEOF bool

	// thread-safe data
	remoteWin  window
	pending    *buffer
	extPending *buffer

	// windowMu protects myWindow, the flow-control window.
	windowMu sync.Mutex
	myWindow uint32

	// writeMu serializes calls to mux.conn.writePacket() and
	// protects sentClose and packetPool. This mutex must be
	// different from windowMu, as writePacket can block if there
	// is a key exchange pending.
	writeMu   sync.Mutex
	sentClose bool

	// packetPool has a buffer for each extended channel ID to
	// save allocations during writes.
	packetPool map[uint32][]byte
}

// writePacket sends a packet. If the packet is a channel close, it updates
// sentClose. This method takes the lock c.writeMu.
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()
}

// WriteExtended writes data to a specific extended stream. These streams are
// used, for example, for stderr.
func ( *channel) ( []byte,  uint32) ( int,  error) {
	if .sentEOF {
		return 0, io.EOF
	}
	// 1 byte message type, 4 bytes remoteId, 4 bytes data length
	 := byte(msgChannelData)
	 := uint32(9)
	if  > 0 {
		 += 4
		 = msgChannelExtendedData
	}

	.writeMu.Lock()
	 := .packetPool[]
	// We don't remove the buffer from packetPool, so
	// WriteExtended calls from different goroutines will be
	// flagged as errors by the race detector.
	.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
	}
	if len() <  {
		// malformed data packet
		return parseError([0])
	}

	var  uint32
	if  {
		 = binary.BigEndian.Uint32([5:])
	}

	 := binary.BigEndian.Uint32([-4 : ])
	if  == 0 {
		return nil
	}
	if  > .maxIncomingPayload {
		// TODO(hanwen): should send Disconnect?
		return errors.New("ssh: incoming packet exceeds maximum payload size")
	}

	 := [:]
	if  != uint32(len()) {
		return errors.New("ssh: wrong packet length")
	}

	.windowMu.Lock()
	if .myWindow <  {
		.windowMu.Unlock()
		// TODO(hanwen): should send Disconnect with reason?
		return errors.New("ssh: remote side wrote too much")
	}
	.myWindow -= 
	.windowMu.Unlock()

	if  == 1 {
		.extPending.write()
	} else if  > 0 {
		// discard other extended data.
	} else {
		.pending.write()
	}
	return nil
}

func ( *channel) ( uint32) error {
	.windowMu.Lock()
	// Since myWindow is managed on our side, and can never exceed
	// the initial window setting, we don't worry about overflow.
	.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 {
		 = .adjustWindow(uint32())
		// sendWindowAdjust can return io.EOF if the remote
		// peer has closed the connection, however we want to
		// defer forwarding io.EOF to the caller of Read until
		// the buffer has been drained.
		if  > 0 &&  == io.EOF {
			 = nil
		}
	}

	return , 
}

func ( *channel) () {
	.pending.eof()
	.extPending.eof()
	close(.msg)
	close(.incomingRequests)
	.writeMu.Lock()
	// This is not necessary for a normal channel teardown, but if
	// there was another error, it is.
	.sentClose = true
	.writeMu.Unlock()
	// Unblock writers.
	.remoteWin.close()
}

// responseMessageReceived is called when a success or failure message is
// received on a channel to check that such a message is reasonable for the
// given channel.
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
	case msgChannelEOF:
		// RFC 4254 is mute on how EOF affects dataExt messages but
		// it is logical to signal EOF at the same time.
		.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})
}

// Extended returns an io.ReadWriter that sends and receives data on the given,
// SSH extended stream. Such streams are used, for example, for stderr.
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
}

// ackRequest either sends an ack or nack to the channel request.
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
}