|
|
@@ -30,6 +30,8 @@ type Conn struct { |
|
|
|
phase handshakeStatus // protected by in.Mutex |
|
|
|
// handshakeConfirmed is an atomic bool for phase == handshakeConfirmed |
|
|
|
handshakeConfirmed int32 |
|
|
|
// confirmMutex is held by any read operation before handshakeConfirmed |
|
|
|
confirmMutex sync.Mutex |
|
|
|
|
|
|
|
// constant after handshake; protected by handshakeMutex |
|
|
|
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex |
|
|
@@ -1254,13 +1256,27 @@ func (c *Conn) ConfirmHandshake() error { |
|
|
|
return err |
|
|
|
} |
|
|
|
|
|
|
|
c.in.Lock() |
|
|
|
defer c.in.Unlock() |
|
|
|
if c.vers < VersionTLS13 { |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
if c.phase == handshakeConfirmed { |
|
|
|
c.confirmMutex.Lock() |
|
|
|
if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed |
|
|
|
c.confirmMutex.Unlock() |
|
|
|
return nil |
|
|
|
} else { |
|
|
|
defer func() { |
|
|
|
// If we transitioned to handshakeConfirmed we already released the lock, |
|
|
|
// otherwise do it here. |
|
|
|
if c.phase != handshakeConfirmed { |
|
|
|
c.confirmMutex.Unlock() |
|
|
|
} |
|
|
|
}() |
|
|
|
} |
|
|
|
|
|
|
|
c.in.Lock() |
|
|
|
defer c.in.Unlock() |
|
|
|
|
|
|
|
var input *block |
|
|
|
if c.phase == readingEarlyData || c.input != nil { |
|
|
|
buf := &bytes.Buffer{} |
|
|
@@ -1341,6 +1357,19 @@ func (c *Conn) Read(b []byte) (n int, err error) { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
c.confirmMutex.Lock() |
|
|
|
if atomic.LoadInt32(&c.handshakeConfirmed) == 1 { // c.phase == handshakeConfirmed |
|
|
|
c.confirmMutex.Unlock() |
|
|
|
} else { |
|
|
|
defer func() { |
|
|
|
// If we transitioned to handshakeConfirmed we already released the lock, |
|
|
|
// otherwise do it here. |
|
|
|
if c.phase != handshakeConfirmed { |
|
|
|
c.confirmMutex.Unlock() |
|
|
|
} |
|
|
|
}() |
|
|
|
} |
|
|
|
|
|
|
|
c.in.Lock() |
|
|
|
defer c.in.Unlock() |
|
|
|
|
|
|
|