github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/net/reverseconnection/api.go (about)

     1  package reverseconnection
     2  
     3  import (
     4  	"net"
     5  	"net/http"
     6  	"sync"
     7  	"time"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/lib/log"
    10  	libnet "github.com/Cloud-Foundations/Dominator/lib/net"
    11  )
    12  
    13  type acceptEvent struct {
    14  	conn  *listenerConn
    15  	error error
    16  }
    17  
    18  type listenerConn struct {
    19  	libnet.TCPConn
    20  	listener *Listener
    21  }
    22  
    23  type Dialer struct {
    24  	dialer            *net.Dialer
    25  	minimumInterval   time.Duration
    26  	maximumInterval   time.Duration
    27  	logger            log.DebugLogger
    28  	connectionMapLock sync.Mutex
    29  	connectionMap     map[string]net.Conn // Key: address (ip:port).
    30  }
    31  
    32  type ip4Address [4]byte
    33  
    34  type Listener struct {
    35  	listener          net.Listener
    36  	portNumber        uint
    37  	logger            log.DebugLogger
    38  	acceptChannel     chan acceptEvent
    39  	closed            bool
    40  	connectionMapLock sync.Mutex
    41  	connectionMap     map[ip4Address]uint
    42  }
    43  
    44  // ReverseListenerConfig describes the configuration for a remote server for
    45  // which connections are requested.
    46  type ReverseListenerConfig struct {
    47  	Network         string        // May be empty or "tcp".
    48  	ServerAddress   string        // Address of the remote server.
    49  	MinimumInterval time.Duration // Minimum interval to request connections.
    50  	MaximumInterval time.Duration // Maximum interval to request connections.
    51  }
    52  
    53  // Listen creates a listener which may be used to accept incoming connections.
    54  // It listens on all available IP addresses on the local system.
    55  func Listen(network string, portNumber uint, logger log.DebugLogger) (
    56  	*Listener, error) {
    57  	return listen(network, portNumber, logger)
    58  }
    59  
    60  func (l *Listener) Accept() (net.Conn, error) {
    61  	return l.accept()
    62  }
    63  
    64  func (l *Listener) Addr() net.Addr {
    65  	return l.listener.Addr()
    66  }
    67  
    68  func (l *Listener) Close() error {
    69  	return l.close()
    70  }
    71  
    72  // RequestConnections starts a goroutine which will periodically attempt to
    73  // establish a connection with a remote server if there is no incoming
    74  // connection from the remote server. The connection that is established will be
    75  // returned by the Accept method. The configuration information for the remote
    76  // server is read from the JSON-encoded file with filename:
    77  // "/etc/reverse-listeners/"+serviceName with the format ReverseListenerConfig.
    78  func (l *Listener) RequestConnections(serviceName string) error {
    79  	return l.requestConnections(serviceName)
    80  }
    81  
    82  // NewDialer creates a dialer that may be used to make connections. It also
    83  // registers a HTTP handler for receiving connections from remote systems which
    84  // have requested connections. When the Dial method is called, if a new
    85  // connection has been received it is used instead of dialing out the normal
    86  // way. If rawDialer is nil, the default dialer is used to dial out when needed.
    87  // If serveMux is nil then the default http.ServeMux is used. NewDialer may be
    88  // called only once per serveMux.
    89  // The minimumInterval and maximumInterval parameters are passed back to remote
    90  // systems which are making connections, overriding their default configuration.
    91  func NewDialer(rawDialer *net.Dialer, serveMux *http.ServeMux,
    92  	minimumInterval, maximumInterval time.Duration,
    93  	logger log.DebugLogger) *Dialer {
    94  	return newDialer(rawDialer, serveMux, minimumInterval, maximumInterval,
    95  		logger)
    96  }
    97  
    98  // Dial makes a connection to a remote address, possibly consuming a connection
    99  // that was initiated by the remote address.
   100  func (d *Dialer) Dial(network, address string) (net.Conn, error) {
   101  	return d.dial(network, address)
   102  }