conn net.Conn
isClient bool
+ // handshakeStatus is 1 if the connection is currently transferring
+ // application data (i.e. is not currently processing a handshake).
+ // This field is only to be accessed with sync/atomic.
+ handshakeStatus uint32
// constant after handshake; protected by handshakeMutex
handshakeMutex sync.Mutex
handshakeErr error // error resulting from handshake
vers uint16 // TLS version
haveVers bool // version has been negotiated
config *Config // configuration passed to constructor
- // handshakeComplete is true if the connection is currently transferring
- // application data (i.e. is not currently processing a handshake).
- handshakeComplete bool
// handshakes counts the number of handshakes performed on the
// connection so far. If renegotiation is disabled then this is either
// zero or one.
c.sendAlert(alertInternalError)
return c.in.setErrorLocked(errors.New("tls: unknown record type requested"))
case recordTypeHandshake, recordTypeChangeCipherSpec:
- if c.handshakeComplete {
+ if c.handshakeComplete() {
c.sendAlert(alertInternalError)
return c.in.setErrorLocked(errors.New("tls: handshake or ChangeCipherSpec requested while not in handshake"))
}
case recordTypeApplicationData:
- if !c.handshakeComplete {
+ if !c.handshakeComplete() {
c.sendAlert(alertInternalError)
return c.in.setErrorLocked(errors.New("tls: application data record requested while in handshake"))
}
return 0, err
}
- if !c.handshakeComplete {
+ if !c.handshakeComplete() {
return 0, alertInternalError
}
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
- c.handshakeComplete = false
+ atomic.StoreUint32(&c.handshakeStatus, 0)
if c.handshakeErr = c.clientHandshake(); c.handshakeErr == nil {
c.handshakes++
}
var alertErr error
- c.handshakeMutex.Lock()
- if c.handshakeComplete {
+ if c.handshakeComplete() {
alertErr = c.closeNotify()
}
- c.handshakeMutex.Unlock()
if err := c.conn.Close(); err != nil {
return err
// 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 {
- c.handshakeMutex.Lock()
- defer c.handshakeMutex.Unlock()
- if !c.handshakeComplete {
+ if !c.handshakeComplete() {
return errEarlyCloseWrite
}
if err := c.handshakeErr; err != nil {
return err
}
- if c.handshakeComplete {
+ if c.handshakeComplete() {
return nil
}
c.flush()
}
- if c.handshakeErr == nil && !c.handshakeComplete {
+ if c.handshakeErr == nil && !c.handshakeComplete() {
panic("handshake should have had a result.")
}
defer c.handshakeMutex.Unlock()
var state ConnectionState
- state.HandshakeComplete = c.handshakeComplete
+ state.HandshakeComplete = c.handshakeComplete()
state.ServerName = c.serverName
- if c.handshakeComplete {
+ if state.HandshakeComplete {
state.Version = c.vers
state.NegotiatedProtocol = c.clientProtocol
state.DidResume = c.didResume
if !c.isClient {
return errors.New("tls: VerifyHostname called on TLS server connection")
}
- if !c.handshakeComplete {
+ if !c.handshakeComplete() {
return errors.New("tls: handshake has not yet been performed")
}
if len(c.verifiedChains) == 0 {
}
return c.peerCertificates[0].VerifyHostname(host)
}
+
+func (c *Conn) handshakeComplete() bool {
+ return atomic.LoadUint32(&c.handshakeStatus) == 1
+}
}
var testP256PrivateKey, _ = x509.ParseECPrivateKey(fromHex("30770201010420012f3b52bc54c36ba3577ad45034e2e8efe1e6999851284cb848725cfe029991a00a06082a8648ce3d030107a14403420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75"))
+
+func TestCloseServerConnectionOnIdleClient(t *testing.T) {
+ clientConn, serverConn := net.Pipe()
+ server := Server(serverConn, testConfig.Clone())
+ go func() {
+ clientConn.Write([]byte{'0'})
+ server.Close()
+ }()
+ server.SetReadDeadline(time.Now().Add(time.Second))
+ err := server.Handshake()
+ if err != nil {
+ if !strings.Contains(err.Error(), "read/write on closed pipe") {
+ t.Errorf("Error expected containing 'read/write on closed pipe' but got '%s'", err.Error())
+ }
+ } else {
+ t.Errorf("Error expected, but no error returned")
+ }
+}