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

Side by Side Diff: ssh/session_test.go

Issue 14225043: code review 14225043: go.crypto/ssh: reimplement SSH connection protocol modu... (Closed)
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:
View unified diff | Download patch
« no previous file with comments | « ssh/session.go ('k') | ssh/tcpip.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Session tests. 7 // Session tests.
8 8
9 import ( 9 import (
10 "bytes" 10 "bytes"
11 crypto_rand "crypto/rand" 11 crypto_rand "crypto/rand"
12 "io" 12 "io"
13 "io/ioutil" 13 "io/ioutil"
14 "math/rand" 14 "math/rand"
15 "net" 15 "net"
16 "testing" 16 "testing"
17 17
18 "code.google.com/p/go.crypto/ssh/terminal" 18 "code.google.com/p/go.crypto/ssh/terminal"
19 ) 19 )
20 20
21 type serverType func(*serverChan, *testing.T) 21 type serverType func(*channel, *testing.T)
22 22
23 // dial constructs a new test server and returns a *ClientConn. 23 // dial constructs a new test server and returns a *ClientConn.
24 func dial(handler serverType, t *testing.T) *ClientConn { 24 func dial(handler serverType, t *testing.T) *ClientConn {
25 l, err := Listen("tcp", "127.0.0.1:0", serverConfig) 25 l, err := Listen("tcp", "127.0.0.1:0", serverConfig)
26 if err != nil { 26 if err != nil {
27 t.Fatalf("unable to listen: %v", err) 27 t.Fatalf("unable to listen: %v", err)
28 } 28 }
29 go func() { 29 go func() {
30 defer l.Close() 30 defer l.Close()
31 conn, err := l.Accept() 31 conn, err := l.Accept()
(...skipping 17 matching lines...) Expand all
49 return 49 return
50 } 50 }
51 if err != nil { 51 if err != nil {
52 t.Errorf("Unable to accept incoming channel requ est: %v", err) 52 t.Errorf("Unable to accept incoming channel requ est: %v", err)
53 return 53 return
54 } 54 }
55 if ch.ChannelType() != "session" { 55 if ch.ChannelType() != "session" {
56 ch.Reject(UnknownChannelType, "unknown channel t ype") 56 ch.Reject(UnknownChannelType, "unknown channel t ype")
57 continue 57 continue
58 } 58 }
59 » » » ch.Accept() 59
60 » » » if err = ch.Accept(); err != nil {
61 » » » » t.Errorf("Accept: %v", err)
62 » » » }
60 go func() { 63 go func() {
61 defer close(done) 64 defer close(done)
62 » » » » handler(ch.(*serverChan), t) 65 » » » » handler(ch.(*compatChannel).channel, t)
63 }() 66 }()
64 } 67 }
65 <-done 68 <-done
66 }() 69 }()
67 70
68 config := &ClientConfig{ 71 config := &ClientConfig{
69 User: "testuser", 72 User: "testuser",
70 Auth: []ClientAuth{ 73 Auth: []ClientAuth{
71 ClientAuthPassword(clientPassword), 74 ClientAuthPassword(clientPassword),
72 }, 75 },
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 t.Fatalf("expected command to fail but it didn't") 326 t.Fatalf("expected command to fail but it didn't")
324 } 327 }
325 _, ok := err.(*ExitError) 328 _, ok := err.(*ExitError)
326 if ok { 329 if ok {
327 // you can't actually test for errors.errorString 330 // you can't actually test for errors.errorString
328 // because it's not exported. 331 // because it's not exported.
329 t.Fatalf("expected *errorString but got %T", err) 332 t.Fatalf("expected *errorString but got %T", err)
330 } 333 }
331 } 334 }
332 335
333 func TestInvalidServerMessage(t *testing.T) { 336 // TODO(hanwen): this test should be at the transport level.
334 » conn := dial(sendInvalidRecord, t)
335 » defer conn.Close()
336 » session, err := conn.NewSession()
337 » if err != nil {
338 » » t.Fatalf("Unable to request new session: %v", err)
339 » }
340 » // Make sure that we closed all the clientChans when the connection
341 » // failed.
342 » session.wait()
343
344 » defer session.Close()
345 }
346
347 // In the wild some clients (and servers) send zero sized window updates.
348 // Test that the client can continue after receiving a zero sized update.
349 func TestClientZeroWindowAdjust(t *testing.T) {
350 » conn := dial(sendZeroWindowAdjust, t)
351 » defer conn.Close()
352 » session, err := conn.NewSession()
353 » if err != nil {
354 » » t.Fatalf("Unable to request new session: %v", err)
355 » }
356 » defer session.Close()
357
358 » if err := session.Shell(); err != nil {
359 » » t.Fatalf("Unable to execute command: %v", err)
360 » }
361 » err = session.Wait()
362 » if err != nil {
363 » » t.Fatalf("expected nil but got %v", err)
364 » }
365 }
366
367 // In the wild some clients (and servers) send zero sized window updates.
368 // Test that the server can continue after receiving a zero size update.
369 func TestServerZeroWindowAdjust(t *testing.T) {
370 » conn := dial(exitStatusZeroHandler, t)
371 » defer conn.Close()
372 » session, err := conn.NewSession()
373 » if err != nil {
374 » » t.Fatalf("Unable to request new session: %v", err)
375 » }
376 » defer session.Close()
377
378 » if err := session.Shell(); err != nil {
379 » » t.Fatalf("Unable to execute command: %v", err)
380 » }
381
382 » // send a bogus zero sized window update
383 » session.clientChan.sendWindowAdj(0)
384
385 » err = session.Wait()
386 » if err != nil {
387 » » t.Fatalf("expected nil but got %v", err)
388 » }
389 }
390
391 // Verify that the client never sends a packet larger than maxpacket.
392 func TestClientStdinRespectsMaxPacketSize(t *testing.T) {
393 » conn := dial(discardHandler, t)
394 » defer conn.Close()
395 » session, err := conn.NewSession()
396 » if err != nil {
397 » » t.Fatalf("failed to request new session: %v", err)
398 » }
399 » defer session.Close()
400 » stdin, err := session.StdinPipe()
401 » if err != nil {
402 » » t.Fatalf("failed to obtain stdinpipe: %v", err)
403 » }
404 » const size = 100 * 1000
405 » for i := 0; i < 10; i++ {
406 » » n, err := stdin.Write(make([]byte, size))
407 » » if n != size || err != nil {
408 » » » t.Fatalf("failed to write: %d, %v", n, err)
409 » » }
410 » }
411 }
412
413 // Verify that the client never accepts a packet larger than maxpacket.
414 func TestServerStdoutRespectsMaxPacketSize(t *testing.T) {
415 » conn := dial(largeSendHandler, t)
416 » defer conn.Close()
417 » session, err := conn.NewSession()
418 » if err != nil {
419 » » t.Fatalf("Unable to request new session: %v", err)
420 » }
421 » defer session.Close()
422 » out, err := session.StdoutPipe()
423 » if err != nil {
424 » » t.Fatalf("Unable to connect to Stdout: %v", err)
425 » }
426 » if err := session.Shell(); err != nil {
427 » » t.Fatalf("Unable to execute command: %v", err)
428 » }
429 » if _, err := ioutil.ReadAll(out); err != nil {
430 » » t.Fatalf("failed to read: %v", err)
431 » }
432 }
433
434 func TestClientCannotSendAfterEOF(t *testing.T) {
435 » conn := dial(exitWithoutSignalOrStatus, t)
436 » defer conn.Close()
437 » session, err := conn.NewSession()
438 » if err != nil {
439 » » t.Fatalf("Unable to request new session: %v", err)
440 » }
441 » defer session.Close()
442 » in, err := session.StdinPipe()
443 » if err != nil {
444 » » t.Fatalf("Unable to connect channel stdin: %v", err)
445 » }
446 » if err := session.Shell(); err != nil {
447 » » t.Fatalf("Unable to execute command: %v", err)
448 » }
449 » if err := in.Close(); err != nil {
450 » » t.Fatalf("Unable to close stdin: %v", err)
451 » }
452 » if _, err := in.Write([]byte("foo")); err == nil {
453 » » t.Fatalf("Session write should fail")
454 » }
455 }
456
457 func TestClientCannotSendAfterClose(t *testing.T) {
458 » conn := dial(exitWithoutSignalOrStatus, t)
459 » defer conn.Close()
460 » session, err := conn.NewSession()
461 » if err != nil {
462 » » t.Fatalf("Unable to request new session: %v", err)
463 » }
464 » defer session.Close()
465 » in, err := session.StdinPipe()
466 » if err != nil {
467 » » t.Fatalf("Unable to connect channel stdin: %v", err)
468 » }
469 » if err := session.Shell(); err != nil {
470 » » t.Fatalf("Unable to execute command: %v", err)
471 » }
472 » // close underlying channel
473 » if err := session.channel.Close(); err != nil {
474 » » t.Fatalf("Unable to close session: %v", err)
475 » }
476 » if _, err := in.Write([]byte("foo")); err == nil {
477 » » t.Fatalf("Session write should fail")
478 » }
479 }
480
481 func TestClientCannotSendHugePacket(t *testing.T) { 337 func TestClientCannotSendHugePacket(t *testing.T) {
482 // client and server use the same transport write code so this 338 // client and server use the same transport write code so this
483 // test suffices for both. 339 // test suffices for both.
484 conn := dial(shellHandler, t) 340 conn := dial(shellHandler, t)
485 defer conn.Close() 341 defer conn.Close()
486 if err := conn.transport.writePacket(make([]byte, maxPacket*2)); err == nil { 342 if err := conn.transport.writePacket(make([]byte, maxPacket*2)); err == nil {
487 t.Fatalf("huge packet write should fail") 343 t.Fatalf("huge packet write should fail")
488 } 344 }
489 } 345 }
490 346
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
553 if err := session.Shell(); err != nil { 409 if err := session.Shell(); err != nil {
554 t.Fatalf("Unable to execute command: %v", err) 410 t.Fatalf("Unable to execute command: %v", err)
555 } 411 }
556 err = session.Wait() 412 err = session.Wait()
557 if err != nil { 413 if err != nil {
558 t.Fatalf("expected nil but got: %v", err) 414 t.Fatalf("expected nil but got: %v", err)
559 } 415 }
560 } 416 }
561 417
562 type exitStatusMsg struct { 418 type exitStatusMsg struct {
563 » PeersId uint32 419 » Status uint32
564 » Request string
565 » WantReply bool
566 » Status uint32
567 } 420 }
568 421
569 type exitSignalMsg struct { 422 type exitSignalMsg struct {
570 PeersId uint32
571 Request string
572 WantReply bool
573 Signal string 423 Signal string
574 CoreDumped bool 424 CoreDumped bool
575 Errmsg string 425 Errmsg string
576 Lang string 426 Lang string
577 } 427 }
578 428
579 func newServerShell(ch *serverChan, prompt string) *ServerTerminal { 429 func newServerShell(ch *channel, prompt string) *ServerTerminal {
580 term := terminal.NewTerminal(ch, prompt) 430 term := terminal.NewTerminal(ch, prompt)
581 » return &ServerTerminal{ 431 » s := &ServerTerminal{
582 Term: term, 432 Term: term,
583 » » Channel: ch, 433 » » Channel: newCompatChannel(ch),
584 } 434 }
435 return s
585 } 436 }
586 437
587 func exitStatusZeroHandler(ch *serverChan, t *testing.T) { 438 func exitStatusZeroHandler(ch *channel, t *testing.T) {
588 defer ch.Close() 439 defer ch.Close()
589 // this string is returned to stdout 440 // this string is returned to stdout
590 shell := newServerShell(ch, "> ") 441 shell := newServerShell(ch, "> ")
591 readLine(shell, t) 442 readLine(shell, t)
592 sendStatus(0, ch, t) 443 sendStatus(0, ch, t)
593 } 444 }
594 445
595 func exitStatusNonZeroHandler(ch *serverChan, t *testing.T) { 446 func exitStatusNonZeroHandler(ch *channel, t *testing.T) {
596 defer ch.Close() 447 defer ch.Close()
597 shell := newServerShell(ch, "> ") 448 shell := newServerShell(ch, "> ")
598 readLine(shell, t) 449 readLine(shell, t)
599 sendStatus(15, ch, t) 450 sendStatus(15, ch, t)
600 } 451 }
601 452
602 func exitSignalAndStatusHandler(ch *serverChan, t *testing.T) { 453 func exitSignalAndStatusHandler(ch *channel, t *testing.T) {
603 defer ch.Close() 454 defer ch.Close()
604 shell := newServerShell(ch, "> ") 455 shell := newServerShell(ch, "> ")
605 readLine(shell, t) 456 readLine(shell, t)
606 sendStatus(15, ch, t) 457 sendStatus(15, ch, t)
607 sendSignal("TERM", ch, t) 458 sendSignal("TERM", ch, t)
608 } 459 }
609 460
610 func exitSignalHandler(ch *serverChan, t *testing.T) { 461 func exitSignalHandler(ch *channel, t *testing.T) {
611 defer ch.Close() 462 defer ch.Close()
612 shell := newServerShell(ch, "> ") 463 shell := newServerShell(ch, "> ")
613 readLine(shell, t) 464 readLine(shell, t)
614 sendSignal("TERM", ch, t) 465 sendSignal("TERM", ch, t)
615 } 466 }
616 467
617 func exitSignalUnknownHandler(ch *serverChan, t *testing.T) { 468 func exitSignalUnknownHandler(ch *channel, t *testing.T) {
618 defer ch.Close() 469 defer ch.Close()
619 shell := newServerShell(ch, "> ") 470 shell := newServerShell(ch, "> ")
620 readLine(shell, t) 471 readLine(shell, t)
621 sendSignal("SYS", ch, t) 472 sendSignal("SYS", ch, t)
622 } 473 }
623 474
624 func exitWithoutSignalOrStatus(ch *serverChan, t *testing.T) { 475 func exitWithoutSignalOrStatus(ch *channel, t *testing.T) {
625 defer ch.Close() 476 defer ch.Close()
626 shell := newServerShell(ch, "> ") 477 shell := newServerShell(ch, "> ")
627 readLine(shell, t) 478 readLine(shell, t)
628 } 479 }
629 480
630 func shellHandler(ch *serverChan, t *testing.T) { 481 func shellHandler(ch *channel, t *testing.T) {
631 defer ch.Close() 482 defer ch.Close()
632 // this string is returned to stdout 483 // this string is returned to stdout
633 shell := newServerShell(ch, "golang") 484 shell := newServerShell(ch, "golang")
634 readLine(shell, t) 485 readLine(shell, t)
635 sendStatus(0, ch, t) 486 sendStatus(0, ch, t)
636 } 487 }
637 488
638 // Ignores the command, writes fixed strings to stderr and stdout. 489 // Ignores the command, writes fixed strings to stderr and stdout.
639 // Strings are "this-is-stdout." and "this-is-stderr.". 490 // Strings are "this-is-stdout." and "this-is-stderr.".
640 func fixedOutputHandler(ch *serverChan, t *testing.T) { 491 func fixedOutputHandler(ch *channel, t *testing.T) {
641 defer ch.Close() 492 defer ch.Close()
642
643 _, err := ch.Read(make([]byte, 0)) 493 _, err := ch.Read(make([]byte, 0))
644 if _, ok := err.(ChannelRequest); !ok { 494 if _, ok := err.(ChannelRequest); !ok {
645 t.Fatalf("error: expected channel request, got: %#v", err) 495 t.Fatalf("error: expected channel request, got: %#v", err)
646 return 496 return
647 } 497 }
498
648 // ignore request, always send some text 499 // ignore request, always send some text
649 ch.AckRequest(true) 500 ch.AckRequest(true)
650 501
651 _, err = io.WriteString(ch, "this-is-stdout.") 502 _, err = io.WriteString(ch, "this-is-stdout.")
652 if err != nil { 503 if err != nil {
653 t.Fatalf("error writing on server: %v", err) 504 t.Fatalf("error writing on server: %v", err)
654 } 505 }
655 » _, err = io.WriteString(ch.Stderr(), "this-is-stderr.") 506 » _, err = io.WriteString(ch.Extended(1), "this-is-stderr.")
656 if err != nil { 507 if err != nil {
657 t.Fatalf("error writing on server: %v", err) 508 t.Fatalf("error writing on server: %v", err)
658 } 509 }
659 sendStatus(0, ch, t) 510 sendStatus(0, ch, t)
660 } 511 }
661 512
662 func readLine(shell *ServerTerminal, t *testing.T) { 513 func readLine(shell *ServerTerminal, t *testing.T) {
663 if _, err := shell.ReadLine(); err != nil && err != io.EOF { 514 if _, err := shell.ReadLine(); err != nil && err != io.EOF {
664 t.Errorf("unable to read line: %v", err) 515 t.Errorf("unable to read line: %v", err)
665 } 516 }
666 } 517 }
667 518
668 func sendStatus(status uint32, ch *serverChan, t *testing.T) { 519 func sendStatus(status uint32, ch *channel, t *testing.T) {
669 msg := exitStatusMsg{ 520 msg := exitStatusMsg{
670 » » PeersId: ch.remoteId, 521 » » Status: status,
671 » » Request: "exit-status",
672 » » WantReply: false,
673 » » Status: status,
674 } 522 }
675 » if err := ch.writePacket(marshal(msgChannelRequest, msg)); err != nil { 523 » if _, err := ch.SendRequest("exit-status", false, marshal(0, msg)); err != nil {
676 t.Errorf("unable to send status: %v", err) 524 t.Errorf("unable to send status: %v", err)
677 } 525 }
678 } 526 }
679 527
680 func sendSignal(signal string, ch *serverChan, t *testing.T) { 528 func sendSignal(signal string, ch *channel, t *testing.T) {
681 sig := exitSignalMsg{ 529 sig := exitSignalMsg{
682 PeersId: ch.remoteId,
683 Request: "exit-signal",
684 WantReply: false,
685 Signal: signal, 530 Signal: signal,
686 CoreDumped: false, 531 CoreDumped: false,
687 Errmsg: "Process terminated", 532 Errmsg: "Process terminated",
688 Lang: "en-GB-oed", 533 Lang: "en-GB-oed",
689 } 534 }
690 » if err := ch.writePacket(marshal(msgChannelRequest, sig)); err != nil { 535 » if _, err := ch.SendRequest("exit-signal", false, marshal(0, sig)); err != nil {
691 t.Errorf("unable to send signal: %v", err) 536 t.Errorf("unable to send signal: %v", err)
692 } 537 }
693 } 538 }
694 539
695 func sendInvalidRecord(ch *serverChan, t *testing.T) { 540 func discardHandler(ch *channel, t *testing.T) {
696 » defer ch.Close()
697 » packet := make([]byte, 1+4+4+1)
698 » packet[0] = msgChannelData
699 » marshalUint32(packet[1:], 29348723 /* invalid channel id */)
700 » marshalUint32(packet[5:], 1)
701 » packet[9] = 42
702
703 » if err := ch.writePacket(packet); err != nil {
704 » » t.Errorf("unable send invalid record: %v", err)
705 » }
706 }
707
708 func sendZeroWindowAdjust(ch *serverChan, t *testing.T) {
709 » defer ch.Close()
710 » // send a bogus zero sized window update
711 » ch.sendWindowAdj(0)
712 » shell := newServerShell(ch, "> ")
713 » readLine(shell, t)
714 » sendStatus(0, ch, t)
715 }
716
717 func discardHandler(ch *serverChan, t *testing.T) {
718 defer ch.Close() 541 defer ch.Close()
719 // grow the window to avoid being fooled by 542 // grow the window to avoid being fooled by
720 // the initial 1 << 14 window. 543 // the initial 1 << 14 window.
721 » ch.sendWindowAdj(1024 * 1024) 544 » ch.adjustWindow(1024 * 1024)
545
722 io.Copy(ioutil.Discard, ch) 546 io.Copy(ioutil.Discard, ch)
723 } 547 }
724 548
725 func largeSendHandler(ch *serverChan, t *testing.T) { 549 func echoHandler(ch *channel, t *testing.T) {
726 » defer ch.Close()
727 » // grow the window to avoid being fooled by
728 » // the initial 1 << 14 window.
729 » ch.sendWindowAdj(1024 * 1024)
730 » shell := newServerShell(ch, "> ")
731 » readLine(shell, t)
732 » // try to send more than the 32k window
733 » // will allow
734 » if err := ch.writePacket(make([]byte, 128*1024)); err == nil {
735 » » t.Errorf("wrote packet larger than 32k")
736 » }
737 }
738
739 func echoHandler(ch *serverChan, t *testing.T) {
740 defer ch.Close() 550 defer ch.Close()
741 if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil { 551 if n, err := copyNRandomly("echohandler", ch, ch, windowTestBytes); err != nil {
742 t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTes tBytes, err) 552 t.Errorf("short write, wrote %d, expected %d: %v ", n, windowTes tBytes, err)
743 } 553 }
744 } 554 }
745 555
746 // copyNRandomly copies n bytes from src to dst. It uses a variable, and random, 556 // copyNRandomly copies n bytes from src to dst. It uses a variable, and random,
747 // buffer size to exercise more code paths. 557 // buffer size to exercise more code paths.
748 func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, erro r) { 558 func copyNRandomly(title string, dst io.Writer, src io.Reader, n int) (int, erro r) {
749 var ( 559 var (
(...skipping 16 matching lines...) Expand all
766 if nr != nw { 576 if nr != nw {
767 return written, io.ErrShortWrite 577 return written, io.ErrShortWrite
768 } 578 }
769 if er != nil && er != io.EOF { 579 if er != nil && er != io.EOF {
770 return written, er 580 return written, er
771 } 581 }
772 } 582 }
773 return written, nil 583 return written, nil
774 } 584 }
775 585
776 func channelKeepaliveSender(ch *serverChan, t *testing.T) { 586 func channelKeepaliveSender(ch *channel, t *testing.T) {
777 defer ch.Close() 587 defer ch.Close()
778 shell := newServerShell(ch, "> ") 588 shell := newServerShell(ch, "> ")
779 readLine(shell, t) 589 readLine(shell, t)
780 » msg := channelRequestMsg{ 590 » if _, err := ch.SendRequest("keepalive@openssh.com", true, nil); err != nil {
781 » » PeersId: ch.remoteId,
782 » » Request: "keepalive@openssh.com",
783 » » WantReply: true,
784 » }
785 » if err := ch.writePacket(marshal(msgChannelRequest, msg)); err != nil {
786 t.Errorf("unable to send channel keepalive request: %v", err) 591 t.Errorf("unable to send channel keepalive request: %v", err)
787 } 592 }
788 sendStatus(0, ch, t) 593 sendStatus(0, ch, t)
789 } 594 }
595
596 func TestClientWriteEOF(t *testing.T) {
597 conn := dial(simpleEchoHandler, t)
598 defer conn.Close()
599
600 session, err := conn.NewSession()
601 if err != nil {
602 t.Fatal(err)
603 }
604 defer session.Close()
605 stdin, err := session.StdinPipe()
606 if err != nil {
607 t.Fatalf("StdinPipe failed: %v", err)
608 }
609 stdout, err := session.StdoutPipe()
610 if err != nil {
611 t.Fatalf("StdoutPipe failed: %v", err)
612 }
613
614 data := []byte(`0000`)
615 _, err = stdin.Write(data)
616 if err != nil {
617 t.Fatalf("Write failed: %v", err)
618 }
619 stdin.Close()
620
621 res, err := ioutil.ReadAll(stdout)
622 if err != nil {
623 t.Fatalf("Read failed: %v", err)
624 }
625
626 if !bytes.Equal(data, res) {
627 t.Fatalf("Read differed from write, wrote: %v, read: %v", data, res)
628 }
629 }
630
631 func simpleEchoHandler(ch *channel, t *testing.T) {
632 defer ch.Close()
633 data, err := ioutil.ReadAll(ch)
634 if err != nil {
635 t.Errorf("handler read error: %v", err)
636 }
637 _, err = ch.Write(data)
638 if err != nil {
639 t.Errorf("handler write error: %v", err)
640 }
641 }
OLDNEW
« no previous file with comments | « ssh/session.go ('k') | ssh/tcpip.go » ('j') | no next file with comments »

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