@@ -45,7 +45,10 @@ type zeroNetAddr struct{}
4545func (zeroNetAddr ) Network () string { return "no" }
4646func (zeroNetAddr ) String () string { return "none" }
4747
48- const maxRetryCount = 3
48+ const (
49+ maxRetryCount = 3
50+ maxEmptyReads = 3
51+ )
4952
5053// ippPins maintains a limited-time mapping between ip:port addresses and dialer IDs.
5154// TODO: invalidate cache on network changes.
@@ -408,22 +411,28 @@ func (r *retrier) CloseRead() error {
408411
409412// Read data from r.conn into buf
410413func (r * retrier ) Read (buf []byte ) (n int , err error ) {
411- c := r .conn
412- if c == nil || core .IsNil (c ) { // should rarely happen
413- log .E ("retrier: read: [] <= %s, no conn" , r .raddr )
414- return 0 , errNoConn
415- }
416-
417414 note := log .V
418415
419- n , err = c .Read (buf ) // r.conn may be provisional or final connection
420- if n == 0 && err == nil { // no data and no error
421- note ("retrier: read: no data; retrying [%s<=%s]" , laddr (c ), r .raddr )
422- return // nothing yet to retry; on to next read
423- }
424- logeor (err , note )("retrier: read: [%s<=%s] %d; err: %v" , laddr (c ), r .raddr , n , err )
416+ c := r .conn // r.conn may be provisional or final connection
417+ if c != nil && core .IsNotNil (c ) {
418+ log .W ("retrier: read: [] <= %s, no conn" , r .raddr )
419+
420+ for reads := range maxEmptyReads {
421+ n , err = c .Read (buf )
422+ if n == 0 && err == nil { // no data and no error
423+ note ("retrier: read: no data #%d; retrying [%s<=%s]" , reads , laddr (c ), r .raddr )
424+ continue // nothing yet to retry; on to next read
425+ } // else: check if retry is needed (c == nil or err != nil)
426+ break
427+ }
428+ if n == 0 && err == nil {
429+ err = io .ErrNoProgress
430+ }
431+ logeor (err , note )("retrier: read: [%s<=%s] %d; err: %v" , laddr (c ), r .raddr , n , err )
432+ } // else: needs retry as c == nil
425433
426434 note = log .D
435+
427436 if ! r .retryCompleted () {
428437 r .mu .Lock ()
429438 defer r .mu .Unlock ()
0 commit comments