@@ -3,16 +3,39 @@ package ssh
33import (
44 "context"
55 "net"
6+ "sync"
67 "time"
78)
89
910type serverConn struct {
1011 net.Conn
1112
12- idleTimeout time.Duration
13+ idleTimeout time.Duration
14+ maxDeadline time.Time
15+ closeCanceler context.CancelFunc
16+
17+ // handshakeDeadline is cleared once the handshake completes, which happens
18+ // after gossh.NewServerConn has started goroutines that read it via
19+ // updateDeadline. Access it only through the accessors below.
20+ mu sync.Mutex
1321 handshakeDeadline time.Time
14- maxDeadline time.Time
15- closeCanceler context.CancelFunc
22+ }
23+
24+ // setHandshakeDeadline bounds how long the handshake may take.
25+ func (c * serverConn ) setHandshakeDeadline (t time.Time ) {
26+ c .mu .Lock ()
27+ c .handshakeDeadline = t
28+ c .mu .Unlock ()
29+ c .updateDeadline ()
30+ }
31+
32+ // clearHandshakeDeadline drops the handshake deadline once the handshake has
33+ // completed, leaving the idle and max deadlines to govern the connection.
34+ func (c * serverConn ) clearHandshakeDeadline () {
35+ c .mu .Lock ()
36+ c .handshakeDeadline = time.Time {}
37+ c .mu .Unlock ()
38+ c .updateDeadline ()
1639}
1740
1841func (c * serverConn ) Write (p []byte ) (n int , err error ) {
@@ -46,10 +69,16 @@ func (c *serverConn) Close() (err error) {
4669}
4770
4871func (c * serverConn ) updateDeadline () {
72+ c .mu .Lock ()
73+ handshakeDeadline := c .handshakeDeadline
74+ c .mu .Unlock ()
75+
76+ // idleTimeout and maxDeadline are set before the handshake starts and never
77+ // mutated afterwards, so they need no locking.
4978 deadline := c .maxDeadline
5079
51- if ! c . handshakeDeadline .IsZero () && (deadline .IsZero () || c . handshakeDeadline .Before (deadline )) {
52- deadline = c . handshakeDeadline
80+ if ! handshakeDeadline .IsZero () && (deadline .IsZero () || handshakeDeadline .Before (deadline )) {
81+ deadline = handshakeDeadline
5382 }
5483
5584 if c .idleTimeout > 0 {
0 commit comments