(ctx context.Context)
| 1682 | } |
| 1683 | |
| 1684 | func (c *Conn) handshakeContext(ctx context.Context) (ret error) { |
| 1685 | // Fast sync/atomic-based exit if there is no handshake in flight and the |
| 1686 | // last one succeeded without an error. Avoids the expensive context setup |
| 1687 | // and mutex for most Read and Write calls. |
| 1688 | if c.handshakeComplete() { |
| 1689 | return nil |
| 1690 | } |
| 1691 | |
| 1692 | handshakeCtx, cancel := context.WithCancel(ctx) |
| 1693 | // Note: defer this before starting the "interrupter" goroutine |
| 1694 | // so that we can tell the difference between the input being canceled and |
| 1695 | // this cancellation. In the former case, we need to close the connection. |
| 1696 | defer cancel() |
| 1697 | |
| 1698 | // Start the "interrupter" goroutine, if this context might be canceled. |
| 1699 | // (The background context cannot). |
| 1700 | // |
| 1701 | // The interrupter goroutine waits for the input context to be done and |
| 1702 | // closes the connection if this happens before the function returns. |
| 1703 | if ctx.Done() != nil { |
| 1704 | done := make(chan struct{}) |
| 1705 | interruptRes := make(chan error, 1) |
| 1706 | defer func() { |
| 1707 | close(done) |
| 1708 | if ctxErr := <-interruptRes; ctxErr != nil { |
| 1709 | // Return context error to user. |
| 1710 | ret = ctxErr |
| 1711 | } |
| 1712 | }() |
| 1713 | go func() { |
| 1714 | select { |
| 1715 | case <-handshakeCtx.Done(): |
| 1716 | // Close the connection, discarding the error |
| 1717 | _ = c.conn.Close() |
| 1718 | interruptRes <- handshakeCtx.Err() |
| 1719 | case <-done: |
| 1720 | interruptRes <- nil |
| 1721 | } |
| 1722 | }() |
| 1723 | } |
| 1724 | |
| 1725 | c.handshakeMutex.Lock() |
| 1726 | defer c.handshakeMutex.Unlock() |
| 1727 | |
| 1728 | if err := c.handshakeErr; err != nil { |
| 1729 | return err |
| 1730 | } |
| 1731 | if c.handshakeComplete() { |
| 1732 | return nil |
| 1733 | } |
| 1734 | |
| 1735 | c.in.Lock() |
| 1736 | defer c.in.Unlock() |
| 1737 | |
| 1738 | c.handshakeErr = c.handshakeFn(handshakeCtx) |
| 1739 | if c.handshakeErr == nil { |
| 1740 | c.handshakes++ |
| 1741 | } else { |
no test coverage detected