go.crypto/ssh: introduce a circular buffer for chanReader

R=agl, gustav.paul, kardianos
CC=golang-dev
https://golang.org/cl/6207051
This commit is contained in:
Dave Cheney
2012-05-16 08:03:54 +10:00
parent 8a2e7c966a
commit e6ded17971
3 changed files with 196 additions and 39 deletions
+13 -39
View File
@@ -224,7 +224,7 @@ func (c *ClientConn) mainLoop() {
if length != uint32(len(packet)) {
return
}
c.getChan(remoteId).stdout.handleData(packet)
c.getChan(remoteId).stdout.write(packet)
case msgChannelExtendedData:
if len(packet) < 13 {
// malformed data packet
@@ -242,7 +242,7 @@ func (c *ClientConn) mainLoop() {
// for stderr on interactive sessions. Other data types are
// silently discarded.
if datatype == 1 {
c.getChan(remoteId).stderr.handleData(packet)
c.getChan(remoteId).stderr.write(packet)
}
default:
switch msg := decode(packet).(type) {
@@ -448,12 +448,12 @@ func newClientChan(cc conn, id uint32) *clientChan {
channel: &c.channel,
}
c.stdout = &chanReader{
data: make(chan []byte, 16),
channel: &c.channel,
buffer: newBuffer(),
}
c.stderr = &chanReader{
data: make(chan []byte, 16),
channel: &c.channel,
buffer: newBuffer(),
}
return c
}
@@ -579,44 +579,18 @@ func (w *chanWriter) Close() error {
// A chanReader represents stdout or stderr of a remote process.
type chanReader struct {
// TODO(dfc) a fixed size channel may not be the right data structure.
// If writes to this channel block, they will block mainLoop, making
// it unable to receive new messages from the remote side.
data chan []byte // receives data from remote
dataClosed bool // protects data from being closed twice
*channel // the channel backing this reader
buf []byte
}
// eof signals to the consumer that there is no more data to be received.
func (r *chanReader) eof() {
if !r.dataClosed {
r.dataClosed = true
close(r.data)
}
}
// handleData sends buf to the reader's consumer. If r.data is closed
// the data will be silently discarded
func (r *chanReader) handleData(buf []byte) {
if !r.dataClosed {
r.data <- buf
}
*channel // the channel backing this reader
*buffer
}
// Read reads data from the remote process's stdout or stderr.
func (r *chanReader) Read(data []byte) (int, error) {
var ok bool
for {
if len(r.buf) > 0 {
n := copy(data, r.buf)
r.buf = r.buf[n:]
return n, r.sendWindowAdj(n)
}
r.buf, ok = <-r.data
if !ok {
return 0, io.EOF
func (r *chanReader) Read(buf []byte) (int, error) {
n, err := r.buffer.Read(buf)
if err != nil {
if err == io.EOF {
return n, err
}
return 0, err
}
panic("unreachable")
return n, r.sendWindowAdj(n)
}