dial.go 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. package edgediscovery
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "net"
  6. "time"
  7. "github.com/pkg/errors"
  8. )
  9. // DialEdge makes a TLS connection to a Cloudflare edge node
  10. func DialEdge(
  11. ctx context.Context,
  12. timeout time.Duration,
  13. tlsConfig *tls.Config,
  14. edgeTCPAddr *net.TCPAddr,
  15. localIP net.IP,
  16. ) (net.Conn, error) {
  17. // Inherit from parent context so we can cancel (Ctrl-C) while dialing
  18. dialCtx, dialCancel := context.WithTimeout(ctx, timeout)
  19. defer dialCancel()
  20. dialer := net.Dialer{}
  21. if localIP != nil {
  22. dialer.LocalAddr = &net.TCPAddr{IP: localIP, Port: 0}
  23. }
  24. edgeConn, err := dialer.DialContext(dialCtx, "tcp", edgeTCPAddr.String())
  25. if err != nil {
  26. return nil, newDialError(err, "DialContext error")
  27. }
  28. tlsEdgeConn := tls.Client(edgeConn, tlsConfig)
  29. tlsEdgeConn.SetDeadline(time.Now().Add(timeout))
  30. if err = tlsEdgeConn.Handshake(); err != nil {
  31. return nil, newDialError(err, "TLS handshake with edge error")
  32. }
  33. // clear the deadline on the conn; http2 has its own timeouts
  34. tlsEdgeConn.SetDeadline(time.Time{})
  35. return tlsEdgeConn, nil
  36. }
  37. // DialError is an error returned from DialEdge
  38. type DialError struct {
  39. cause error
  40. }
  41. func newDialError(err error, message string) error {
  42. return DialError{cause: errors.Wrap(err, message)}
  43. }
  44. func (e DialError) Error() string {
  45. return e.cause.Error()
  46. }
  47. func (e DialError) Cause() error {
  48. return e.cause
  49. }