github.com/glycerine/xcryptossh@v7.0.4+incompatible/writebump_test.go (about) 1 package ssh 2 3 import ( 4 "fmt" 5 "io" 6 "testing" 7 "time" 8 ) 9 10 // Given a read-only idle timeout of 1 sec, and a write happening 11 // every 100 msec: when reads stop, even with the ongoing write 12 // success, the read should still timeout. i.e. read timeout should 13 // be independent of write success. This is needed because 14 // writers are buffered and typically return a nil error, but 15 // this tells us nothing about the status of connectivity. 16 func TestTimeout009ReadsIdleOutEvenIfWritesOK(t *testing.T) { 17 defer xtestend(xtestbegin(t)) 18 19 halt := NewHalter() 20 defer halt.RequestStop() 21 22 r, wun, mux := channelPair(t, halt) 23 defer wun.Close() 24 25 writeFreq := time.Millisecond * 100 26 27 idleout := 1000 * time.Millisecond 28 overall := 3 * idleout 29 30 t0 := time.Now() 31 tstop := t0.Add(overall) 32 33 tExpectIdleOut := t0.Add(idleout) 34 35 // set the timeout on the reader 36 err := r.SetReadIdleTimeout(idleout) 37 if err != nil { 38 panic(fmt.Sprintf("r.SetIdleTimeout: %v", err)) 39 } 40 41 readErr := make(chan error) 42 writeErr := make(chan error) 43 var ring *infiniteRing 44 45 go to009ReaderToRing(idleout, r, overall, tstop, readErr, &ring) 46 47 go to009pingWrite(r, tstop, writeFreq, overall, writeErr, halt) 48 49 // wait for our overall time, and for both to return 50 var rerr, werr error 51 var rok, wok bool 52 complete := func() bool { 53 return rok && wok 54 } 55 collectionLoop: 56 for { 57 select { 58 case <-time.After(2 * overall): 59 panic(fmt.Sprintf("TestTimeout009WriteIdlesOutWhenReadsStop: waited " + 60 "two overall, yet still no idle timeout!")) 61 62 case rerr = <-readErr: 63 p("got rerr: '%#v'", rerr) 64 now := time.Now() 65 66 // the main point of the test is these checks: 67 68 // we want tExpectIdleOut >= now >= tstop 69 // so that the read idled-out even though writes are ok 70 if now.Before(tExpectIdleOut) { 71 panic(fmt.Sprintf("rerr: '%v', stopped too early, before '%v'. now=%v. now-expected=%v", rerr, tExpectIdleOut, now, now.Sub(tExpectIdleOut))) 72 } 73 if now.After(tstop) { 74 panic(fmt.Sprintf("rerr: '%v', stopped too late, after '%v'. now=%v. now-tstop=%v", rerr, tstop, now, now.Sub(tstop))) 75 } 76 rok = true 77 78 if complete() { 79 break collectionLoop 80 } 81 82 case werr = <-writeErr: 83 p("got werr") 84 now := time.Now() 85 if now.Before(tstop) { 86 panic(fmt.Sprintf("werr: '%v', stopped too early, before '%v'. now=%v. now-before=%v", werr, tstop, now, now.Sub(tstop))) 87 } 88 wok = true 89 90 if complete() { 91 break collectionLoop 92 } 93 } 94 95 } 96 p("done with collection loop") 97 98 r.Close() 99 mux.Close() 100 101 } 102 103 // setup reader r -> infiniteRing ring. returns 104 // readOk upon success. 105 func to009ReaderToRing(idleout time.Duration, r Channel, overall time.Duration, tstop time.Time, readErr chan error, pRing **infiniteRing) (err error) { 106 defer func() { 107 p("readerToRing returning on readErr, err = '%v'", err) 108 readErr <- err 109 }() 110 111 ring := newInfiniteRing() 112 *pRing = ring 113 114 src := r 115 dst := ring 116 buf := make([]byte, 32*1024) 117 118 for { 119 nr, er := src.Read(buf) 120 if nr > 0 { 121 nw, ew := dst.Write(buf[0:nr]) 122 if ew != nil { 123 err = ew 124 p("readerToRing sees Write err %v", ew) 125 break 126 } 127 if nr != nw { 128 err = io.ErrShortWrite 129 break 130 } 131 } 132 133 if time.Now().After(tstop) { 134 p("reader: reached tstop, bailing out of copy loop.") 135 return readOk 136 } 137 138 if er != nil { 139 p("readerToRing sees Read err %v", er) 140 if er != io.EOF { 141 err = er 142 } 143 break 144 } 145 } //end for 146 147 return err 148 } 149 150 // write a zero byte every freq, so keep idling from idling out. 151 // we return after overall 152 func to009pingWrite(w Channel, tstop time.Time, writeFreq time.Duration, overall time.Duration, writeErr chan error, halt *Halter) (err error) { 153 defer func() { 154 halt.MarkDone() 155 p("readerToRing returning on readErr, err = '%v'", err) 156 writeErr <- err 157 }() 158 159 buf := make([]byte, 1) 160 ping := time.After(writeFreq) 161 overallTime := time.After(overall) 162 for { 163 select { 164 case <-ping: 165 // byte a byte 166 w.Write(buf) 167 ping = time.After(writeFreq) 168 169 case <-halt.ReqStopChan(): 170 return 171 case <-overallTime: 172 return 173 } 174 } 175 }