OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |