public.go 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. // Copyright (C) 2015 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package dialer
  7. import (
  8. "fmt"
  9. "net"
  10. "time"
  11. )
  12. // Dial tries dialing via proxy if a proxy is configured, and falls back to
  13. // a direct connection if no proxy is defined, or connecting via proxy fails.
  14. func Dial(network, addr string) (net.Conn, error) {
  15. if usingProxy {
  16. return dialWithFallback(proxyDialer.Dial, net.Dial, network, addr)
  17. }
  18. return net.Dial(network, addr)
  19. }
  20. // DialTimeout tries dialing via proxy with a timeout if a proxy is configured,
  21. // and falls back to a direct connection if no proxy is defined, or connecting
  22. // via proxy fails. The timeout can potentially be applied twice, once trying
  23. // to connect via the proxy connection, and second time trying to connect
  24. // directly.
  25. func DialTimeout(network, addr string, timeout time.Duration) (net.Conn, error) {
  26. if usingProxy {
  27. // Because the proxy package is poorly structured, we have to
  28. // construct a struct that matches proxy.Dialer but has a timeout
  29. // and reconstrcut the proxy dialer using that, in order to be able to
  30. // set a timeout.
  31. dd := &timeoutDirectDialer{
  32. timeout: timeout,
  33. }
  34. // Check if the dialer we are getting is not timeoutDirectDialer we just
  35. // created. It could happen that usingProxy is true, but getDialer
  36. // returns timeoutDirectDialer due to env vars changing.
  37. if timeoutProxyDialer := getDialer(dd); timeoutProxyDialer != dd {
  38. directDialFunc := func(inetwork, iaddr string) (net.Conn, error) {
  39. return net.DialTimeout(inetwork, iaddr, timeout)
  40. }
  41. return dialWithFallback(timeoutProxyDialer.Dial, directDialFunc, network, addr)
  42. }
  43. }
  44. return net.DialTimeout(network, addr, timeout)
  45. }
  46. // SetTCPOptions sets our default TCP options on a TCP connection, possibly
  47. // digging through dialerConn to extract the *net.TCPConn
  48. func SetTCPOptions(conn net.Conn) error {
  49. switch conn := conn.(type) {
  50. case *net.TCPConn:
  51. var err error
  52. if err = conn.SetLinger(0); err != nil {
  53. return err
  54. }
  55. if err = conn.SetNoDelay(false); err != nil {
  56. return err
  57. }
  58. if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil {
  59. return err
  60. }
  61. if err = conn.SetKeepAlive(true); err != nil {
  62. return err
  63. }
  64. return nil
  65. case dialerConn:
  66. return SetTCPOptions(conn.Conn)
  67. default:
  68. return fmt.Errorf("unknown connection type %T", conn)
  69. }
  70. }