Sync upstream Go 1.20

Excluding `boring` or test files
This commit is contained in:
RPRX
2023-11-12 12:08:30 -05:00
committed by yuhan6665
parent da6c695a34
commit 870716f6af
15 changed files with 247 additions and 168 deletions
+25 -28
View File
@@ -35,11 +35,10 @@ type Conn struct {
isClient bool
handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
// handshakeStatus is 1 if the connection is currently transferring
// isHandshakeComplete is true if the connection is currently transferring
// application data (i.e. is not currently processing a handshake).
// handshakeStatus == 1 implies handshakeErr == nil.
// This field is only to be accessed with sync/atomic.
handshakeStatus uint32
// isHandshakeComplete is true implies handshakeErr == nil.
isHandshakeComplete atomic.Bool
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex
handshakeErr error // error resulting from handshake
@@ -55,6 +54,9 @@ type Conn struct {
ocspResponse []byte // stapled OCSP response
scts [][]byte // signed certificate timestamps from server
peerCertificates []*x509.Certificate
// activeCertHandles contains the cache handles to certificates in
// peerCertificates that are used to track active references.
activeCertHandles []*activeCert
// verifiedChains contains the certificate chains that we built, as
// opposed to the ones presented by the server.
verifiedChains [][]*x509.Certificate
@@ -115,10 +117,9 @@ type Conn struct {
// handshake, nor deliver application data. Protected by in.Mutex.
retryCount int
// activeCall is an atomic int32; the low bit is whether Close has
// been called. the rest of the bits are the number of goroutines
// in Conn.Write.
activeCall int32
// activeCall indicates whether Close has been call in the low bit.
// the rest of the bits are the number of goroutines in Conn.Write.
activeCall atomic.Int32
tmp [16]byte
}
@@ -639,7 +640,7 @@ func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
if c.in.err != nil {
return c.in.err
}
handshakeComplete := c.handshakeComplete()
handshakeComplete := c.isHandshakeComplete.Load()
// This function modifies c.rawInput, which owns the c.input memory.
if c.input.Len() != 0 {
@@ -1154,15 +1155,15 @@ var (
func (c *Conn) Write(b []byte) (int, error) {
// interlock with Close below
for {
x := atomic.LoadInt32(&c.activeCall)
x := c.activeCall.Load()
if x&1 != 0 {
return 0, net.ErrClosed
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x+2) {
if c.activeCall.CompareAndSwap(x, x+2) {
break
}
}
defer atomic.AddInt32(&c.activeCall, -2)
defer c.activeCall.Add(-2)
if err := c.Handshake(); err != nil {
return 0, err
@@ -1175,7 +1176,7 @@ func (c *Conn) Write(b []byte) (int, error) {
return 0, err
}
if !c.handshakeComplete() {
if !c.isHandshakeComplete.Load() {
return 0, alertInternalError
}
@@ -1245,7 +1246,7 @@ func (c *Conn) handleRenegotiation() error {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
atomic.StoreUint32(&c.handshakeStatus, 0)
c.isHandshakeComplete.Store(false)
if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
c.handshakes++
}
@@ -1363,11 +1364,11 @@ func (c *Conn) Close() error {
// Interlock with Conn.Write above.
var x int32
for {
x = atomic.LoadInt32(&c.activeCall)
x = c.activeCall.Load()
if x&1 != 0 {
return net.ErrClosed
}
if atomic.CompareAndSwapInt32(&c.activeCall, x, x|1) {
if c.activeCall.CompareAndSwap(x, x|1) {
break
}
}
@@ -1382,7 +1383,7 @@ func (c *Conn) Close() error {
}
var alertErr error
if c.handshakeComplete() {
if c.isHandshakeComplete.Load() {
if err := c.closeNotify(); err != nil {
alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
}
@@ -1400,7 +1401,7 @@ var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake com
// called once the handshake has completed and does not call CloseWrite on the
// underlying connection. Most callers should just use Close.
func (c *Conn) CloseWrite() error {
if !c.handshakeComplete() {
if !c.isHandshakeComplete.Load() {
return errEarlyCloseWrite
}
@@ -1454,7 +1455,7 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
// Fast sync/atomic-based exit if there is no handshake in flight and the
// last one succeeded without an error. Avoids the expensive context setup
// and mutex for most Read and Write calls.
if c.handshakeComplete() {
if c.isHandshakeComplete.Load() {
return nil
}
@@ -1497,7 +1498,7 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
if err := c.handshakeErr; err != nil {
return err
}
if c.handshakeComplete() {
if c.isHandshakeComplete.Load() {
return nil
}
@@ -1513,10 +1514,10 @@ func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
c.flush()
}
if c.handshakeErr == nil && !c.handshakeComplete() {
if c.handshakeErr == nil && !c.isHandshakeComplete.Load() {
c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
}
if c.handshakeErr != nil && c.handshakeComplete() {
if c.handshakeErr != nil && c.isHandshakeComplete.Load() {
panic("tls: internal error: handshake returned an error but is marked successful")
}
@@ -1532,7 +1533,7 @@ func (c *Conn) ConnectionState() ConnectionState {
func (c *Conn) connectionStateLocked() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete()
state.HandshakeComplete = c.isHandshakeComplete.Load()
state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
@@ -1576,7 +1577,7 @@ func (c *Conn) VerifyHostname(host string) error {
if !c.isClient {
return errors.New("tls: VerifyHostname called on TLS server connection")
}
if !c.handshakeComplete() {
if !c.isHandshakeComplete.Load() {
return errors.New("tls: handshake has not yet been performed")
}
if len(c.verifiedChains) == 0 {
@@ -1584,7 +1585,3 @@ func (c *Conn) VerifyHostname(host string) error {
}
return c.peerCertificates[0].VerifyHostname(host)
}
func (c *Conn) handshakeComplete() bool {
return atomic.LoadUint32(&c.handshakeStatus) == 1
}