go.crypto/ssh: make {client,server}Chan use common window management

R=agl, gustav.paul, kardianos
CC=golang-dev
https://golang.org/cl/6208043
This commit is contained in:
Dave Cheney
2012-05-11 05:56:44 +10:00
parent 523290a72d
commit 8a2e7c966a
4 changed files with 76 additions and 82 deletions
+7 -51
View File
@@ -276,7 +276,7 @@ func (c *ClientConn) mainLoop() {
case *channelRequestMsg:
c.getChan(msg.PeersId).msg <- msg
case *windowAdjustMsg:
if !c.getChan(msg.PeersId).stdin.win.add(msg.AdditionalBytes) {
if !c.getChan(msg.PeersId).remoteWin.add(msg.AdditionalBytes) {
// invalid window update
return
}
@@ -317,7 +317,7 @@ func (c *ClientConn) handleChanOpen(msg *channelOpenMsg) {
}
ch := c.newChan(c.transport)
ch.remoteId = msg.PeersId
ch.stdin.win.add(msg.PeersWindow)
ch.remoteWin.add(msg.PeersWindow)
m := channelOpenConfirmMsg{
PeersId: ch.remoteId,
@@ -438,13 +438,13 @@ type clientChan struct {
func newClientChan(cc conn, id uint32) *clientChan {
c := &clientChan{
channel: channel{
conn: cc,
localId: id,
conn: cc,
localId: id,
remoteWin: window{Cond: newCond()},
},
msg: make(chan interface{}, 16),
}
c.stdin = &chanWriter{
win: &window{Cond: sync.NewCond(new(sync.Mutex))},
channel: &c.channel,
}
c.stdout = &chanReader{
@@ -465,7 +465,7 @@ func (c *clientChan) waitForChannelOpenResponse() error {
case *channelOpenConfirmMsg:
// fixup remoteId field
c.remoteId = msg.MyId
c.stdin.win.add(msg.MyWindow)
c.remoteWin.add(msg.MyWindow)
return nil
case *channelOpenFailureMsg:
return errors.New(safeString(msg.Message))
@@ -542,7 +542,6 @@ func (c *chanList) closeAll() {
// A chanWriter represents the stdin of a remote process.
type chanWriter struct {
win *window
*channel
}
@@ -551,7 +550,7 @@ func (w *chanWriter) Write(data []byte) (written int, err error) {
for len(data) > 0 {
// n cannot be larger than 2^31 as len(data) cannot
// be larger than 2^31
n := int(w.win.reserve(uint32(len(data))))
n := int(w.remoteWin.reserve(uint32(len(data))))
remoteId := w.remoteId
packet := []byte{
msgChannelData,
@@ -621,46 +620,3 @@ func (r *chanReader) Read(data []byte) (int, error) {
}
panic("unreachable")
}
// window represents the buffer available to clients
// wishing to write to a channel.
type window struct {
*sync.Cond
win uint32 // RFC 4254 5.2 says the window size can grow to 2^32-1
}
// add adds win to the amount of window available
// for consumers.
func (w *window) add(win uint32) bool {
if win == 0 {
return false
}
w.L.Lock()
if w.win+win < win {
w.L.Unlock()
return false
}
w.win += win
// It is unusual that multiple goroutines would be attempting to reserve
// window space, but not guaranteed. Use broadcast to notify all waiters
// that additional window is available.
w.Broadcast()
w.L.Unlock()
return true
}
// reserve reserves win from the available window capacity.
// If no capacity remains, reserve will block. reserve may
// return less than requested.
func (w *window) reserve(win uint32) uint32 {
w.L.Lock()
for w.win == 0 {
w.Wait()
}
if w.win < win {
win = w.win
}
w.win -= win
w.L.Unlock()
return win
}