github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/p2p/listener.go (about)

     1  package p2p
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	log "github.com/sirupsen/logrus"
    11  	cmn "github.com/tendermint/tmlibs/common"
    12  
    13  	cfg "github.com/bytom/bytom/config"
    14  	"github.com/bytom/bytom/errors"
    15  	"github.com/bytom/bytom/p2p/upnp"
    16  )
    17  
    18  const (
    19  	numBufferedConnections = 10
    20  	defaultExternalPort    = 8770
    21  	tryListenTimes         = 5
    22  )
    23  
    24  //Listener subset of the methods of DefaultListener
    25  type Listener interface {
    26  	Connections() <-chan net.Conn
    27  	InternalAddress() *NetAddress
    28  	ExternalAddress() *NetAddress
    29  	String() string
    30  	Stop() error
    31  }
    32  
    33  // Defaults to tcp
    34  func protocolAndAddress(listenAddr string) (string, string) {
    35  	p, address := "tcp", listenAddr
    36  	parts := strings.SplitN(address, "://", 2)
    37  	if len(parts) == 2 {
    38  		p, address = parts[0], parts[1]
    39  	}
    40  	return p, address
    41  }
    42  
    43  // GetListener get listener and listen address.
    44  func GetListener(config *cfg.P2PConfig) (Listener, string) {
    45  	p, address := protocolAndAddress(config.ListenAddress)
    46  	l, listenerStatus := NewDefaultListener(p, address, config.SkipUPNP)
    47  
    48  	// We assume that the rpcListener has the same ExternalAddress.
    49  	// This is probably true because both P2P and RPC listeners use UPnP,
    50  	// except of course if the rpc is only bound to localhost
    51  	if listenerStatus {
    52  		return l, cmn.Fmt("%v:%v", l.ExternalAddress().IP.String(), l.ExternalAddress().Port)
    53  	}
    54  
    55  	return l, cmn.Fmt("%v:%v", l.InternalAddress().IP.String(), l.InternalAddress().Port)
    56  }
    57  
    58  //getUPNPExternalAddress UPNP external address discovery & port mapping
    59  func getUPNPExternalAddress(externalPort, internalPort int) (*NetAddress, error) {
    60  	nat, err := upnp.Discover()
    61  	if err != nil {
    62  		return nil, errors.Wrap(err, "could not perform UPNP discover")
    63  	}
    64  
    65  	ext, err := nat.GetExternalAddress()
    66  	if err != nil {
    67  		return nil, errors.Wrap(err, "could not perform UPNP external address")
    68  	}
    69  
    70  	if externalPort == 0 {
    71  		externalPort = defaultExternalPort
    72  	}
    73  	externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "bytomd tcp", 0)
    74  	if err != nil {
    75  		return nil, errors.Wrap(err, "could not add tcp UPNP port mapping")
    76  	}
    77  	externalPort, err = nat.AddPortMapping("udp", externalPort, internalPort, "bytomd udp", 0)
    78  	if err != nil {
    79  		return nil, errors.Wrap(err, "could not add udp UPNP port mapping")
    80  	}
    81  	return NewNetAddressIPPort(ext, uint16(externalPort)), nil
    82  }
    83  
    84  func splitHostPort(addr string) (host string, port int) {
    85  	host, portStr, err := net.SplitHostPort(addr)
    86  	if err != nil {
    87  		cmn.PanicSanity(err)
    88  	}
    89  	port, err = strconv.Atoi(portStr)
    90  	if err != nil {
    91  		cmn.PanicSanity(err)
    92  	}
    93  	return host, port
    94  }
    95  
    96  //DefaultListener Implements bytomd server Listener
    97  type DefaultListener struct {
    98  	cmn.BaseService
    99  
   100  	listener    net.Listener
   101  	intAddr     *NetAddress
   102  	extAddr     *NetAddress
   103  	connections chan net.Conn
   104  }
   105  
   106  //NewDefaultListener create a default listener
   107  func NewDefaultListener(protocol string, lAddr string, skipUPNP bool) (Listener, bool) {
   108  	// Local listen IP & port
   109  	lAddrIP, lAddrPort := splitHostPort(lAddr)
   110  
   111  	listener, err := net.Listen(protocol, lAddr)
   112  	for i := 0; i < tryListenTimes && err != nil; i++ {
   113  		time.Sleep(time.Second * 1)
   114  		listener, err = net.Listen(protocol, lAddr)
   115  	}
   116  	if err != nil {
   117  		log.Panic(err)
   118  	}
   119  
   120  	intAddr, err := NewNetAddressString(lAddr)
   121  	if err != nil {
   122  		log.Panic(err)
   123  	}
   124  
   125  	// Actual listener local IP & port
   126  	listenerIP, listenerPort := splitHostPort(listener.Addr().String())
   127  	log.Info("Local listener", " ip:", listenerIP, " port:", listenerPort)
   128  
   129  	// Determine external address...
   130  	var extAddr *NetAddress
   131  	var upnpMap bool
   132  	if !skipUPNP && (lAddrIP == "" || lAddrIP == "0.0.0.0") {
   133  		extAddr, err = getUPNPExternalAddress(lAddrPort, listenerPort)
   134  		upnpMap = err == nil
   135  		log.WithFields(log.Fields{"module": logModule, "err": err}).Info("get UPNP external address")
   136  	}
   137  
   138  	// Get the IPv4 available
   139  	if extAddr == nil {
   140  		if ip, err := ExternalIPv4(); err != nil {
   141  			log.WithFields(log.Fields{"module": logModule, "err": err}).Warning("get ipv4 external address")
   142  			log.Panic("get ipv4 external address fail!")
   143  		} else {
   144  			extAddr = NewNetAddressIPPort(net.ParseIP(ip), uint16(lAddrPort))
   145  			log.WithFields(log.Fields{"module": logModule, "addr": extAddr}).Info("get ipv4 external address success")
   146  		}
   147  	}
   148  
   149  	dl := &DefaultListener{
   150  		listener:    listener,
   151  		intAddr:     intAddr,
   152  		extAddr:     extAddr,
   153  		connections: make(chan net.Conn, numBufferedConnections),
   154  	}
   155  	dl.BaseService = *cmn.NewBaseService(nil, "DefaultListener", dl)
   156  	dl.Start() // Started upon construction
   157  	if upnpMap {
   158  		return dl, true
   159  	}
   160  
   161  	conn, err := net.DialTimeout("tcp", extAddr.String(), 3*time.Second)
   162  	if err != nil {
   163  		return dl, false
   164  	}
   165  	conn.Close()
   166  	return dl, true
   167  }
   168  
   169  //OnStart start listener
   170  func (l *DefaultListener) OnStart() error {
   171  	l.BaseService.OnStart()
   172  	go l.listenRoutine()
   173  	return nil
   174  }
   175  
   176  //OnStop stop listener
   177  func (l *DefaultListener) OnStop() {
   178  	l.BaseService.OnStop()
   179  	l.listener.Close()
   180  }
   181  
   182  //listenRoutine Accept connections and pass on the channel
   183  func (l *DefaultListener) listenRoutine() {
   184  	for {
   185  		conn, err := l.listener.Accept()
   186  		if !l.IsRunning() {
   187  			break // Go to cleanup
   188  		}
   189  		// listener wasn't stopped,
   190  		// yet we encountered an error.
   191  		if err != nil {
   192  			log.Panic(err)
   193  		}
   194  		l.connections <- conn
   195  	}
   196  	// Cleanup
   197  	close(l.connections)
   198  }
   199  
   200  //Connections a channel of inbound connections. It gets closed when the listener closes.
   201  func (l *DefaultListener) Connections() <-chan net.Conn {
   202  	return l.connections
   203  }
   204  
   205  //InternalAddress listener internal address
   206  func (l *DefaultListener) InternalAddress() *NetAddress {
   207  	return l.intAddr
   208  }
   209  
   210  //ExternalAddress listener external address for remote peer dial
   211  func (l *DefaultListener) ExternalAddress() *NetAddress {
   212  	return l.extAddr
   213  }
   214  
   215  // NetListener the returned listener is already Accept()'ing. So it's not suitable to pass into http.Serve().
   216  func (l *DefaultListener) NetListener() net.Listener {
   217  	return l.listener
   218  }
   219  
   220  //String string of default listener
   221  func (l *DefaultListener) String() string {
   222  	return fmt.Sprintf("Listener(@%v)", l.extAddr)
   223  }