Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(941)

Delta Between Two Patch Sets: ssh/channel.go

Issue 14225043: code review 14225043: go.crypto/ssh: reimplement SSH connection protocol modu... (Closed)
Left Patch Set: diff -r 213a06a7ce81 https://code.google.com/p/go.crypto Created 10 years, 5 months ago
Right Patch Set: diff -r cd1eea1eb828 https://code.google.com/p/go.crypto Created 10 years, 5 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « no previous file | ssh/client.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 package ssh 5 package ssh
6 6
7 import ( 7 import (
8 "encoding/binary" 8 "encoding/binary"
9 "errors" 9 "errors"
10 "fmt" 10 "fmt"
11 "io" 11 "io"
12 "log" 12 "log"
13 "sync" 13 "sync"
14 ) 14 )
15 15
16 type ChannelCreationRequest interface { 16 // A Channel is an ordered, reliable, duplex stream that is
17 // multiplexed over an SSH connection.
18 type Channel interface {
17 // Accept accepts the channel creation request. 19 // Accept accepts the channel creation request.
18 » Accept() (Channel, error) 20 » Accept() error
19 21
20 // Reject rejects the channel creation request. After calling 22 // Reject rejects the channel creation request. After calling
21 // this, no other methods on the Channel may be called. 23 // this, no other methods on the Channel may be called.
22 Reject(reason RejectionReason, message string) error 24 Reject(reason RejectionReason, message string) error
23 25
24 » // ChannelType returns the type of the channel, as supplied by the 26 » // Read may return a ChannelRequest as an error.
25 » // client.
26 » ChannelType() string
27
28 » // ExtraData returns the arbitrary payload for this channel, as supplied
29 » // by the client. This data is specific to the channel type.
30 » ExtraData() []byte
31 }
32
33 // A Channel is an ordered, reliable, duplex stream that is
34 // multiplexed over an SSH connection.
35 type Channel interface {
36 » // NOSUBMIT - should add ReadExtended/WriteExtended here?
37
38 Read(data []byte) (int, error) 27 Read(data []byte) (int, error)
39 Write(data []byte) (int, error) 28 Write(data []byte) (int, error)
40
41 // Sends EOF to the other side.
42 CloseWrite() error
43 29
44 // Signals end of channel use. No data may be sent after this 30 // Signals end of channel use. No data may be sent after this
45 // call. 31 // call.
46 Close() error 32 Close() error
47 33
48 » // Stderr returns an io.ReadWriter to write to (server) or 34 » // Stderr returns an io.Writer that writes to this channel with the
49 » // read from (client) stderr. 35 » // extended data type set to stderr.
50 » Stderr() io.ReadWriter 36 » Stderr() io.Writer
51
52 » // SendRequest sends a channel request.
53 » SendRequest(name string, wantReply bool, payload []byte) (bool, error)
54
55 » // IncomingRequests returns the channel for out-of-band
56 » // requests. For all requests received that have WantReply, a
57 » // call of AckRequest should follow.
58 » IncomingRequests() chan *ChannelRequest
59 37
60 // AckRequest either sends an ack or nack to the channel 38 // AckRequest either sends an ack or nack to the channel
61 // request. It should only be called if the last 39 // request. It should only be called if the last
62 // ChannelRequest had a WantReply 40 // ChannelRequest had a WantReply
63 AckRequest(ok bool) error 41 AckRequest(ok bool) error
64 42
65 // ChannelType returns the type of the channel, as supplied by the 43 // ChannelType returns the type of the channel, as supplied by the
66 // client. 44 // client.
67 ChannelType() string 45 ChannelType() string
68 46
69 // ExtraData returns the arbitrary payload for this channel, as supplied 47 // ExtraData returns the arbitrary payload for this channel, as supplied
70 // by the client. This data is specific to the channel type. 48 // by the client. This data is specific to the channel type.
71 ExtraData() []byte 49 ExtraData() []byte
72 } 50 }
73 51
74 // ChannelRequest represents a request sent, outside of the normal 52 // ChannelRequest represents a request sent, outside of the normal
75 // stream of bytes. Requests may either be channel specific, or global 53 // stream of bytes.
76 type ChannelRequest struct { 54 type ChannelRequest struct {
77 Request string 55 Request string
78 WantReply bool 56 WantReply bool
79 Payload []byte 57 Payload []byte
58 }
59
60 func (c ChannelRequest) Error() string {
61 return "ssh: channel request received"
80 } 62 }
81 63
82 // RejectionReason is an enumeration used when rejecting channel creation 64 // RejectionReason is an enumeration used when rejecting channel creation
83 // requests. See RFC 4254, section 5.1. 65 // requests. See RFC 4254, section 5.1.
84 type RejectionReason uint32 66 type RejectionReason uint32
85 67
86 const ( 68 const (
87 Prohibited RejectionReason = iota + 1 69 Prohibited RejectionReason = iota + 1
88 ConnectionFailed 70 ConnectionFailed
89 UnknownChannelType 71 UnknownChannelType
(...skipping 24 matching lines...) Expand all
114 maxPacket uint32 96 maxPacket uint32
115 mux *mux 97 mux *mux
116 98
117 // If set, we have called Accept or Reject on this channel 99 // If set, we have called Accept or Reject on this channel
118 decided bool 100 decided bool
119 101
120 // Pending internal channel messages. 102 // Pending internal channel messages.
121 msg chan interface{} 103 msg chan interface{}
122 104
123 // Pending user-serviceable messages. 105 // Pending user-serviceable messages.
124 » sentRequestMu sync.Mutex 106 » sentRequestMu sync.Mutex
125 » pendingRequests chan *ChannelRequest 107
108 » incomingRequests chan *ChannelRequest
126 109
127 sentEOF bool 110 sentEOF bool
128 111
129 // thread-safe data 112 // thread-safe data
130 remoteWin window 113 remoteWin window
131 pending *buffer 114 pending *buffer
132 extPending *buffer 115 extPending *buffer
133 116
134 // Protects all of the below. 117 // Protects all of the below.
135 mu sync.Mutex 118 mu sync.Mutex
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
269 return c.sendMessage(msgChannelWindowAdjust, windowAdjustMsg{ 252 return c.sendMessage(msgChannelWindowAdjust, windowAdjustMsg{
270 AdditionalBytes: uint32(n), 253 AdditionalBytes: uint32(n),
271 }) 254 })
272 } 255 }
273 256
274 func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) { 257 func (c *channel) ReadExtended(data []byte, extended uint32) (n int, err error) {
275 if extended == 1 { 258 if extended == 1 {
276 n, err = c.extPending.Read(data) 259 n, err = c.extPending.Read(data)
277 } else if extended == 0 { 260 } else if extended == 0 {
278 n, err = c.pending.Read(data) 261 n, err = c.pending.Read(data)
262 } else {
263 return 0, fmt.Errorf("ssh: extended code %d implemented", extend ed)
279 } 264 }
280 265
281 if n > 0 { 266 if n > 0 {
282 err = c.adjustWindow(uint32(n)) 267 err = c.adjustWindow(uint32(n))
283 // sendWindowAdjust can return io.EOF if the remote 268 // sendWindowAdjust can return io.EOF if the remote
284 // peer has closed the connection, however we want to 269 // peer has closed the connection, however we want to
285 // defer forwarding io.EOF to the caller of Read until 270 // defer forwarding io.EOF to the caller of Read until
286 // the buffer has been drained. 271 // the buffer has been drained.
287 if n > 0 && err == io.EOF { 272 if n > 0 && err == io.EOF {
288 err = nil 273 err = nil
(...skipping 13 matching lines...) Expand all
302 case msgChannelData, msgChannelExtendedData: 287 case msgChannelData, msgChannelExtendedData:
303 return c.handleData(packet) 288 return c.handleData(packet)
304 case msgChannelClose: 289 case msgChannelClose:
305 // Ack the close. 290 // Ack the close.
306 c.sendMessage(msgChannelClose, channelCloseMsg{ 291 c.sendMessage(msgChannelClose, channelCloseMsg{
307 PeersId: c.remoteId}) 292 PeersId: c.remoteId})
308 293
309 c.pending.eof() 294 c.pending.eof()
310 c.extPending.eof() 295 c.extPending.eof()
311 close(c.msg) 296 close(c.msg)
312 » » close(c.pendingRequests) 297 » » close(c.incomingRequests)
313 c.mux.chanList.remove(c.localId) 298 c.mux.chanList.remove(c.localId)
314 299
315 return nil 300 return nil
316 case msgChannelEOF: 301 case msgChannelEOF:
317 c.pending.eof()
318 // RFC 4254 is mute on how EOF affects dataExt messages but 302 // RFC 4254 is mute on how EOF affects dataExt messages but
319 // it is logical to signal EOF at the same time. 303 // it is logical to signal EOF at the same time.
320 c.extPending.eof() 304 c.extPending.eof()
305
306 // For ServerConn, ChannelRequests are actually output
307 // as Read error. This means that no requests can be
308 // processed after EOF is sent, which is a bug
309 c.pending.eof()
321 return nil 310 return nil
322 } 311 }
323 312
324 decoded, err := decode(packet) 313 decoded, err := decode(packet)
325 if err != nil { 314 if err != nil {
326 return err 315 return err
327 } 316 }
328 317
329 switch msg := decoded.(type) { 318 switch msg := decoded.(type) {
330 case *windowAdjustMsg: 319 case *windowAdjustMsg:
331 if !c.remoteWin.add(msg.AdditionalBytes) { 320 if !c.remoteWin.add(msg.AdditionalBytes) {
332 return fmt.Errorf("invalid window update %d", msg.Additi onalBytes) 321 return fmt.Errorf("invalid window update %d", msg.Additi onalBytes)
333 } 322 }
334 323
335 case *channelRequestMsg: 324 case *channelRequestMsg:
336 req := ChannelRequest{ 325 req := ChannelRequest{
337 Request: msg.Request, 326 Request: msg.Request,
338 WantReply: msg.WantReply, 327 WantReply: msg.WantReply,
339 Payload: msg.RequestSpecificData, 328 Payload: msg.RequestSpecificData,
340 } 329 }
341 330
342 » » c.pendingRequests <- &req 331 » » c.incomingRequests <- &req
343 default: 332 default:
344 c.msg <- msg 333 c.msg <- msg
345 } 334 }
346 return nil 335 return nil
347 } 336 }
348 337
349 func newChannel(chanType string, extraData []byte) *channel { 338 func newChannel(chanType string, extraData []byte) *channel {
350 return &channel{ 339 return &channel{
351 » » remoteWin: window{Cond: newCond()}, 340 » » remoteWin: window{Cond: newCond()},
352 » » myWindow: defaultWindowSize, 341 » » myWindow: defaultWindowSize,
353 » » pending: newBuffer(), 342 » » pending: newBuffer(),
354 » » extPending: newBuffer(), 343 » » extPending: newBuffer(),
355 » » pendingRequests: make(chan *ChannelRequest, 16), 344 » » incomingRequests: make(chan *ChannelRequest, 16),
356 » » msg: make(chan interface{}, 16), 345 » » msg: make(chan interface{}, 16),
357 » » chanType: chanType, 346 » » chanType: chanType,
358 » » extraData: extraData, 347 » » extraData: extraData,
359 } 348 }
360 } 349 }
361 350
362 var errUndecided = errors.New("ssh: must Accept or Reject channel") 351 var errUndecided = errors.New("ssh: must Accept or Reject channel")
363 var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once") 352 var errDecidedAlready = errors.New("ssh: can call Accept or Reject only once")
364 353
365 type extChannel channel 354 type extChannel struct {
355 » code uint32
356 » ch *channel
357 }
366 358
367 func (e *extChannel) Write(data []byte) (n int, err error) { 359 func (e *extChannel) Write(data []byte) (n int, err error) {
368 » return ((*channel)(e)).WriteExtended(data, 1) 360 » return e.ch.WriteExtended(data, e.code)
369 } 361 }
370 func (e *extChannel) Read(data []byte) (n int, err error) { 362 func (e *extChannel) Read(data []byte) (n int, err error) {
371 » return ((*channel)(e)).ReadExtended(data, 1) 363 » return e.ch.ReadExtended(data, e.code)
372 } 364 }
373 365
374 func (c *channel) Accept() (Channel, error) { 366 func (c *channel) Accept() error {
375 if c.decided { 367 if c.decided {
376 » » return nil, errDecidedAlready 368 » » return errDecidedAlready
377 } 369 }
378 confirm := channelOpenConfirmMsg{ 370 confirm := channelOpenConfirmMsg{
379 PeersId: c.remoteId, 371 PeersId: c.remoteId,
380 MyId: c.localId, 372 MyId: c.localId,
381 MyWindow: c.myWindow, 373 MyWindow: c.myWindow,
382 MaxPacketSize: c.maxPacket, 374 MaxPacketSize: c.maxPacket,
383 } 375 }
384 c.decided = true 376 c.decided = true
385 if err := c.sendMessage(msgChannelOpenConfirm, confirm); err != nil { 377 if err := c.sendMessage(msgChannelOpenConfirm, confirm); err != nil {
386 » » return nil, err 378 » » return err
387 » } 379 » }
388 380
389 » return c, nil 381 » return nil
390 } 382 }
391 383
392 func (ch *channel) Reject(reason RejectionReason, message string) error { 384 func (ch *channel) Reject(reason RejectionReason, message string) error {
393 if ch.decided { 385 if ch.decided {
394 return errDecidedAlready 386 return errDecidedAlready
395 } 387 }
396 reject := channelOpenFailureMsg{ 388 reject := channelOpenFailureMsg{
397 PeersId: ch.remoteId, 389 PeersId: ch.remoteId,
398 Reason: reason, 390 Reason: reason,
399 Message: message, 391 Message: message,
400 Language: "en", 392 Language: "en",
401 } 393 }
402 ch.decided = true 394 ch.decided = true
403 return ch.sendMessage(msgChannelOpenFailure, reject) 395 return ch.sendMessage(msgChannelOpenFailure, reject)
404 } 396 }
405 397
406 func (ch *channel) Read(data []byte) (int, error) { 398 func (ch *channel) Read(data []byte) (int, error) {
407 if !ch.decided { 399 if !ch.decided {
408 return 0, errUndecided 400 return 0, errUndecided
409 } 401 }
410 402
411 return ch.ReadExtended(data, 0) 403 return ch.ReadExtended(data, 0)
412 } 404 }
413 405
414 func (ch *channel) IncomingRequests() chan *ChannelRequest {
415 return ch.pendingRequests
416 }
417
418 func (ch *channel) Write(data []byte) (int, error) { 406 func (ch *channel) Write(data []byte) (int, error) {
419 if !ch.decided { 407 if !ch.decided {
420 return 0, errUndecided 408 return 0, errUndecided
421 } 409 }
422 return ch.WriteExtended(data, 0) 410 return ch.WriteExtended(data, 0)
423 } 411 }
424 412
425 func (ch *channel) CloseWrite() error { 413 func (ch *channel) CloseWrite() error {
426 if !ch.decided { 414 if !ch.decided {
427 return errUndecided 415 return errUndecided
428 } 416 }
429 ch.sentEOF = true 417 ch.sentEOF = true
430 return ch.sendMessage(msgChannelEOF, channelEOFMsg{ 418 return ch.sendMessage(msgChannelEOF, channelEOFMsg{
431 PeersId: ch.remoteId}) 419 PeersId: ch.remoteId})
432 } 420 }
433 421
434 func (ch *channel) Close() error { 422 func (ch *channel) Close() error {
435 if !ch.decided { 423 if !ch.decided {
436 return errUndecided 424 return errUndecided
437 } 425 }
438 426
439 return ch.sendMessage(msgChannelClose, channelCloseMsg{ 427 return ch.sendMessage(msgChannelClose, channelCloseMsg{
440 PeersId: ch.remoteId}) 428 PeersId: ch.remoteId})
441 } 429 }
442 430
443 func (ch *channel) Stderr() io.ReadWriter { 431 func (ch *channel) Extended(code uint32) io.ReadWriter {
444 if !ch.decided { 432 if !ch.decided {
445 return nil 433 return nil
446 } 434 }
447 » return (*extChannel)(ch) 435 » return &extChannel{code, ch}
448 } 436 }
449 437
450 // SendRequest sends a channel request. If wantReply is set, it will 438 // SendRequest sends a channel request. If wantReply is set, it will
451 // wait for a reply and return the result as a boolean. 439 // wait for a reply and return the result as a boolean.
452 func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo l, error) { 440 func (ch *channel) SendRequest(name string, wantReply bool, payload []byte) (boo l, error) {
453 if !ch.decided { 441 if !ch.decided {
454 return false, errUndecided 442 return false, errUndecided
455 } 443 }
456 444
457 if wantReply { 445 if wantReply {
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 return ch.sendMessage(code, msg) 498 return ch.sendMessage(code, msg)
511 } 499 }
512 500
513 func (ch *channel) ChannelType() string { 501 func (ch *channel) ChannelType() string {
514 return ch.chanType 502 return ch.chanType
515 } 503 }
516 504
517 func (ch *channel) ExtraData() []byte { 505 func (ch *channel) ExtraData() []byte {
518 return ch.extraData 506 return ch.extraData
519 } 507 }
508
509 // compatChannel is a hack to implement Channel's
510 // handing of channel requests.
511 type compatChannel struct {
512 *channel
513 }
514
515 func newCompatChannel(ch *channel) *compatChannel {
516 c := &compatChannel{ch}
517 go c.loop()
518 return c
519 }
520
521 func (c *compatChannel) loop() {
522 for r := range c.channel.incomingRequests {
523 c.channel.pending.addRequest(r)
524 }
525 }
526
527 func (c *compatChannel) Stderr() io.Writer {
528 return c.Extended(1)
529 }
LEFTRIGHT
« no previous file | ssh/client.go » ('j') | Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Toggle Comments ('s')

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b