<p><!-- CL 256897 -->
I/O operations on closing or closed TLS connections can now be detected using
- the new <a href="/pkg/net/#ErrClosed">ErrClosed</a> error. A typical use
- would be <code>errors.Is(err, net.ErrClosed)</code>. In earlier releases
+ the new <a href="/pkg/net/#ErrClosed">ErrClosed</a> error. A typical use
+ would be <code>errors.Is(err, net.ErrClosed)</code>. In earlier releases
the only way to reliably detect this case was to match the string returned
by the <code>Error</code> method with <code>"tls: use of closed connection"</code>.
</p>
+<p><!-- CL 266037 -->
+ A default deadline is set in <a href="/pkg/crypto/tls/#Conn.Close">Close</a>
+ before sending the close notify alert, in order to prevent blocking
+ indefinitely.
+</p>
+
<h3 id="crypto/x509"><a href="/pkg/crypto/x509">crypto/x509</a></h3>
<p><!-- CL 235078 -->
)
// Write writes data to the connection.
+//
+// As Write calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Write is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
func (c *Conn) Write(b []byte) (int, error) {
// interlock with Close below
for {
return nil
}
-// Read can be made to time out and return a net.Error with Timeout() == true
-// after a fixed time limit; see SetDeadline and SetReadDeadline.
+// Read reads data from the connection.
+//
+// As Read calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Read is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
func (c *Conn) Read(b []byte) (int, error) {
if err := c.Handshake(); err != nil {
return 0, err
}
var alertErr error
-
if c.handshakeComplete() {
- alertErr = c.closeNotify()
+ if err := c.closeNotify(); err != nil {
+ alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
+ }
}
if err := c.conn.Close(); err != nil {
defer c.out.Unlock()
if !c.closeNotifySent {
+ // Set a Write Deadline to prevent possibly blocking forever.
+ c.SetWriteDeadline(time.Now().Add(time.Second * 5))
c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
c.closeNotifySent = true
+ // Any subsequent writes will fail.
+ c.SetWriteDeadline(time.Now())
}
return c.closeNotifyErr
}