github.com/devops-filetransfer/sshego@v7.0.4+incompatible/listen_test.go (about) 1 package sshego 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "testing" 8 "time" 9 10 cv "github.com/glycerine/goconvey/convey" 11 ) 12 13 func Test501BasicServerListenStartupAcceptAndShutdown(t *testing.T) { 14 15 cv.Convey("BasicServer should start and stop when requested-- in response to Listen() and Close() -- in place of Start() and Stop()", t, func() { 16 cfg, r1 := GenTestConfig() 17 r1() // release the held-open ports. 18 defer TempDirCleanup(cfg.Origdir, cfg.Tempdir) 19 s := NewBasicServer(cfg) 20 bs, err := s.Listen(cfg.EmbeddedSSHd.Addr) 21 panicOn(err) 22 var aerr error 23 acceptDone := make(chan bool) 24 ctx := context.Background() 25 go func() { 26 pp("bs.Accept starting") 27 _, aerr = bs.Accept(ctx) 28 _ = aerr 29 close(acceptDone) 30 pp("bs.Accept done and close(acceptDone) happened.") 31 }() 32 33 err = bs.Close() 34 pp("bs.Close() done") 35 // don't panic on err 36 <-acceptDone 37 pp("past <-acceptDone") 38 39 //pp("about to <-cfg.Esshd.Done") 40 //<-cfg.Esshd.Halt.DoneChan() 41 //pp("past <-cfg.Esshd.Done") 42 cv.So(true, cv.ShouldEqual, true) // we should get here. 43 fmt.Printf("\n done with 501\n") 44 }) 45 } 46 47 func Test502BasicServerListenStartupAndShutdown(t *testing.T) { 48 49 cv.Convey("BasicServer should start and stop when requested-- in response to Listen() and Close() -- even if not Accept()-ing yet.", t, func() { 50 cfg, r1 := GenTestConfig() 51 r1() // release the held-open ports. 52 defer TempDirCleanup(cfg.Origdir, cfg.Tempdir) 53 s := NewBasicServer(cfg) 54 bs, err := s.Listen(cfg.EmbeddedSSHd.Addr) 55 panicOn(err) 56 57 err = bs.Close() 58 panicOn(err) 59 60 cv.So(true, cv.ShouldEqual, true) // we should get here. 61 }) 62 } 63 64 // help method for tests in this file 65 func startBackgroundTestSshServer2(ctx context.Context, serverDone chan bool, payloadByteCount int, confirmationPayload string, confirmationReply string, tcpSrvLsn *BasicListener) { 66 go func() { 67 for { 68 pp("startBackgroundTestTcpServer() about to call Accept().") 69 tcpServerConn, err := tcpSrvLsn.Accept(ctx) 70 if err != nil { 71 pp("startBackgroundTestSshServer2 ignoring"+ 72 " error from Accept: '%v'", err) 73 continue 74 } 75 pp("startBackgroundTestTcpServer() progress: got Accept() back: %v", 76 tcpServerConn) 77 78 b := make([]byte, payloadByteCount) 79 n, err := tcpServerConn.Read(b) 80 panicOn(err) 81 if n != payloadByteCount { 82 panic(fmt.Errorf("read too short! got %v but expected %v", n, payloadByteCount)) 83 } 84 saw := string(b) 85 86 if saw != confirmationPayload { 87 panic(fmt.Errorf("expected '%s', but saw '%s'", confirmationPayload, saw)) 88 } 89 90 pp("success! in startBackgroundTestSshServer2(): "+ 91 "server got expected confirmation payload of '%s'", saw) 92 93 // reply back 94 n, err = tcpServerConn.Write([]byte(confirmationReply)) 95 panicOn(err) 96 if n != payloadByteCount { 97 panic(fmt.Errorf("write too short! got %v but expected %v", n, payloadByteCount)) 98 } 99 //tcpServerConn.Close() 100 close(serverDone) 101 pp("startBackgroundTestSshServer2 goroutine returning") 102 return 103 } 104 }() 105 } 106 107 // help method for tests in this file 108 func verifyExchange2(channelToTcpServer net.Conn, confirmationPayload, confirmationReply string, payloadByteCount int) { 109 m, err := channelToTcpServer.Write([]byte(confirmationPayload)) 110 panicOn(err) 111 if m != len(confirmationPayload) { 112 panic("too short a write!") 113 } 114 115 // check reply 116 rep := make([]byte, payloadByteCount) 117 m, err = channelToTcpServer.Read(rep) 118 panicOn(err) 119 if m != payloadByteCount { 120 msg := fmt.Sprintf("too short a reply! m = %v, expected %v. rep = '%v'", m, payloadByteCount, string(rep)) 121 pp(msg) 122 panic(msg) 123 } 124 125 srep := string(rep) 126 if srep != confirmationReply { 127 panic(fmt.Errorf("saw '%s' but expected '%s'", srep, confirmationReply)) 128 } 129 pp("reply success! we got the expected srep reply '%s'", srep) 130 } 131 132 func Test504BasicServerListenAndAcceptConnection(t *testing.T) { 133 134 cv.Convey("Simple version of: Given an sshd BasicServer started with Listen() and Accept(), the verifyClientServerExchangeAcrossSshd() check with nonce requests and reply should verify the net.Conn usage. This is like cli_test.go Test201 but with the server using Listen() and Accept().", t, func() { 135 136 // 1. start a simple TCP server that is the target of the forward through the sshd, 137 // so we can confirm the client has made the connection. 138 // 2. generate a random payload for the client to send to the server. 139 payloadByteCount := 50 140 confirmationPayload := RandomString(payloadByteCount) 141 confirmationReply := RandomString(payloadByteCount) 142 143 serverDone := make(chan bool) 144 145 cfg, r1 := GenTestConfig() 146 cfg.SkipTOTP = true 147 cfg.SkipPassphrase = true 148 r1() // release the held-open ports. 149 defer TempDirCleanup(cfg.Origdir, cfg.Tempdir) 150 151 bs := NewBasicServer(cfg) 152 mylogin, _, rsaPath, _, err := TestCreateNewAccount(cfg) 153 panicOn(err) 154 ctx := context.Background() 155 156 blsn, err := bs.Listen(cfg.EmbeddedSSHd.Addr) 157 panicOn(err) 158 // let server come up. 159 time.Sleep(50 * time.Millisecond) 160 161 startBackgroundTestSshServer2( 162 ctx, 163 serverDone, 164 payloadByteCount, 165 confirmationPayload, 166 confirmationReply, 167 blsn) 168 169 // =============== 170 // begin dialing, client contacts server! 171 // =============== 172 dc := DialConfig{ 173 // shortcut: re-use server's know hosts dir 174 ClientKnownHostsPath: cfg.ClientKnownHostsPath, 175 Mylogin: mylogin, 176 RsaPath: rsaPath, 177 Sshdhost: cfg.EmbeddedSSHd.Host, 178 Sshdport: cfg.EmbeddedSSHd.Port, 179 DownstreamHostPort: "127.0.0.1:1", 180 TofuAddIfNotKnown: true, 181 } 182 183 // first time we add the server key 184 channelToTcpServer, _, _, err := dc.Dial(ctx, nil, false) 185 pp("here!!") 186 cv.So(err.Error(), cv.ShouldContainSubstring, "Re-run without -new") 187 188 // second time we connect based on that server key 189 dc.TofuAddIfNotKnown = false 190 channelToTcpServer, _, _, err = dc.Dial(ctx, nil, false) 191 cv.So(err, cv.ShouldBeNil) 192 193 verifyExchange2( 194 channelToTcpServer, 195 confirmationPayload, 196 confirmationReply, 197 payloadByteCount) 198 199 // close out the client side. 200 channelToTcpServer.Close() 201 202 // tcp-server should have exited because it got the expected 203 // message and replied with the agreed upon reply and then exited. 204 pp("just before <-serverDone") 205 <-serverDone 206 pp("just after <-serverDone") 207 208 cv.So(true, cv.ShouldEqual, true) // we should get here. 209 210 fmt.Printf("\n done with 504\n") 211 }) 212 } 213 214 func Test505BasicServerInterruptsAcceptOnClose(t *testing.T) { 215 216 cv.Convey("BasicServer.Close() should interrupt a waiting Accept() call.", 217 t, func() { 218 cfg, r1 := GenTestConfig() 219 r1() // release the held-open ports. 220 defer TempDirCleanup(cfg.Origdir, cfg.Tempdir) 221 s := NewBasicServer(cfg) 222 bs, err := s.Listen(cfg.EmbeddedSSHd.Addr) 223 panicOn(err) 224 ctx := context.Background() 225 226 var aerr error 227 acceptDone := make(chan bool) 228 go func() { 229 pp("bs.Accept starting") 230 _, aerr = bs.Accept(ctx) 231 close(acceptDone) 232 pp("bs.Accept done and close(acceptDone) happened.") 233 }() 234 235 select { 236 case <-time.After(time.Second): 237 pp("good, no acceptDone seen when Close() not yet called.") 238 case <-acceptDone: 239 panic("problem: we saw acceptDone before the Close()") 240 } 241 242 err = bs.Close() 243 pp("bs.Close() done") 244 // don't panic on err 245 <-acceptDone 246 pp("past <-acceptDone") 247 cv.So(aerr.Error(), cv.ShouldEqual, "shutting down") 248 }) 249 }