// makeTCPDialer creates a custom dialer which creates TCPConn. An upstream // proxy is used when specified. func makeTCPDialer(config *DialConfig) func(network, addr string) (net.Conn, error) { dialer := func(network, addr string) (net.Conn, error) { if network != "tcp" { return nil, errors.New("unsupported network type in TCPConn dialer") } conn, err := interruptibleTCPDial(addr, config) if err != nil { return nil, ContextError(err) } return conn, nil } if config.UpstreamProxyUrl != "" { upstreamDialer := upstreamproxy.NewProxyDialFunc( &upstreamproxy.UpstreamProxyConfig{ ForwardDialFunc: dialer, ProxyURIString: config.UpstreamProxyUrl, }) dialer = func(network, addr string) (conn net.Conn, err error) { // The entire upstream dial is wrapped in an explicit timeout. This // may include network connection read and writes when proxy auth negotation // is performed. type upstreamDialResult struct { conn net.Conn err error } if config.ConnectTimeout != 0 { resultChannel := make(chan *upstreamDialResult, 2) time.AfterFunc(config.ConnectTimeout, func() { // TODO: we could "interrupt" the underlying TCPConn at this point, as // it's being abandoned. But we don't have a reference to it. It's left // to the outer DialConfig.PendingConns to track and clean up that TCPConn. resultChannel <- &upstreamDialResult{nil, errors.New("upstreamproxy dial timeout")} }) go func() { conn, err := upstreamDialer(network, addr) resultChannel <- &upstreamDialResult{conn, err} }() result := <-resultChannel conn, err = result.conn, result.err } else { conn, err = upstreamDialer(network, addr) } if _, ok := err.(*upstreamproxy.Error); ok { NoticeUpstreamProxyError(err) } return conn, err } } return dialer }
// proxiedTcpDial wraps a tcpDial call in an upstreamproxy dial. func proxiedTcpDial( addr string, config *DialConfig, dialResult chan error) (net.Conn, error) { dialer := func(network, addr string) (net.Conn, error) { return tcpDial(addr, config, dialResult) } upstreamDialer := upstreamproxy.NewProxyDialFunc( &upstreamproxy.UpstreamProxyConfig{ ForwardDialFunc: dialer, ProxyURIString: config.UpstreamProxyUrl, }) netConn, err := upstreamDialer("tcp", addr) if _, ok := err.(*upstreamproxy.Error); ok { NoticeUpstreamProxyError(err) } return netConn, err }