github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/requests/dialer.go (about)

     1  /*
     2   * Copyright (C) 2020 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package requests
    19  
    20  import (
    21  	"context"
    22  	"net"
    23  	"time"
    24  
    25  	"github.com/mysteriumnetwork/node/requests/resolver"
    26  )
    27  
    28  // DialContext specifies the dial function for creating unencrypted TCP connections.
    29  type DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
    30  
    31  // Dialer wraps default go dialer with extra features.
    32  type Dialer struct {
    33  	// ResolveContext specifies the resolve function for doing custom DNS lookup.
    34  	// If ResolveContext is nil, then the transport dials using package net.
    35  	ResolveContext resolver.ResolveContext
    36  
    37  	// Dialer specifies the dial function for creating unencrypted TCP connections.
    38  	Dialer DialContext
    39  }
    40  
    41  // NewDialer creates dialer with default configuration.
    42  func NewDialer(srcIP string) *Dialer {
    43  	return &Dialer{
    44  		Dialer: (&net.Dialer{
    45  			Timeout:   60 * time.Second,
    46  			KeepAlive: 30 * time.Second,
    47  			LocalAddr: &net.TCPAddr{IP: net.ParseIP(srcIP)},
    48  		}).DialContext,
    49  	}
    50  }
    51  
    52  // DialContext connects to the address on the named network using the provided context.
    53  func (d *Dialer) DialContext(ctx context.Context, network, addr string) (conn net.Conn, err error) {
    54  	if d.ResolveContext != nil {
    55  		addrs, err := d.ResolveContext(ctx, network, addr)
    56  		if err != nil {
    57  			return nil, &net.OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
    58  		}
    59  
    60  		conn, err := d.dialAddrs(ctx, network, addrs)
    61  		if err != nil {
    62  			return nil, &net.OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
    63  		}
    64  
    65  		return conn, nil
    66  	}
    67  
    68  	return d.Dialer(ctx, network, addr)
    69  }
    70  
    71  func (d *Dialer) dialAddrs(ctx context.Context, network string, addrs []string) (conn net.Conn, err error) {
    72  	for _, addr := range addrs {
    73  		conn, err = d.Dialer(ctx, network, addr)
    74  		if err == nil {
    75  			return conn, nil
    76  		}
    77  	}
    78  
    79  	return conn, err
    80  }