10 log "github.com/sirupsen/logrus"
11 cmn "github.com/tendermint/tmlibs/common"
13 cfg "github.com/bytom/config"
14 "github.com/bytom/errors"
15 "github.com/bytom/p2p/upnp"
19 numBufferedConnections = 10
20 defaultExternalPort = 8770
24 //Listener subset of the methods of DefaultListener
25 type Listener interface {
26 Connections() <-chan net.Conn
27 InternalAddress() *NetAddress
28 ExternalAddress() *NetAddress
34 func protocolAndAddress(listenAddr string) (string, string) {
35 p, address := "tcp", listenAddr
36 parts := strings.SplitN(address, "://", 2)
38 p, address = parts[0], parts[1]
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)
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
52 return l, cmn.Fmt("%v:%v", l.ExternalAddress().IP.String(), l.ExternalAddress().Port)
55 return l, cmn.Fmt("%v:%v", l.InternalAddress().IP.String(), l.InternalAddress().Port)
58 //getUPNPExternalAddress UPNP external address discovery & port mapping
59 func getUPNPExternalAddress(externalPort, internalPort int) (*NetAddress, error) {
60 nat, err := upnp.Discover()
62 return nil, errors.Wrap(err, "could not perform UPNP discover")
65 ext, err := nat.GetExternalAddress()
67 return nil, errors.Wrap(err, "could not perform UPNP external address")
70 if externalPort == 0 {
71 externalPort = defaultExternalPort
73 externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "bytomd tcp", 0)
75 return nil, errors.Wrap(err, "could not add tcp UPNP port mapping")
77 externalPort, err = nat.AddPortMapping("udp", externalPort, internalPort, "bytomd udp", 0)
79 return nil, errors.Wrap(err, "could not add udp UPNP port mapping")
81 return NewNetAddressIPPort(ext, uint16(externalPort)), nil
84 func getNaiveExternalAddress(port int, settleForLocal bool) *NetAddress {
85 addrs, err := net.InterfaceAddrs()
87 cmn.PanicCrisis(cmn.Fmt("Could not fetch interface addresses: %v", err))
90 for _, a := range addrs {
91 ipnet, ok := a.(*net.IPNet)
95 if v4 := ipnet.IP.To4(); v4 == nil || (!settleForLocal && v4[0] == 127) {
98 return NewNetAddressIPPort(ipnet.IP, uint16(port))
101 log.Info("Node may not be connected to internet. Settling for local address")
102 return getNaiveExternalAddress(port, true)
105 func splitHostPort(addr string) (host string, port int) {
106 host, portStr, err := net.SplitHostPort(addr)
110 port, err = strconv.Atoi(portStr)
117 //DefaultListener Implements bytomd server Listener
118 type DefaultListener struct {
121 listener net.Listener
124 connections chan net.Conn
127 //NewDefaultListener create a default listener
128 func NewDefaultListener(protocol string, lAddr string, skipUPNP bool) (Listener, bool) {
129 // Local listen IP & port
130 lAddrIP, lAddrPort := splitHostPort(lAddr)
132 listener, err := net.Listen(protocol, lAddr)
133 for i := 0; i < tryListenTimes && err != nil; i++ {
134 time.Sleep(time.Second * 1)
135 listener, err = net.Listen(protocol, lAddr)
141 intAddr, err := NewNetAddressString(lAddr)
146 // Actual listener local IP & port
147 listenerIP, listenerPort := splitHostPort(listener.Addr().String())
148 log.Info("Local listener", " ip:", listenerIP, " port:", listenerPort)
150 // Determine external address...
151 var extAddr *NetAddress
153 if !skipUPNP && (lAddrIP == "" || lAddrIP == "0.0.0.0") {
154 extAddr, err = getUPNPExternalAddress(lAddrPort, listenerPort)
156 log.WithFields(log.Fields{"module": logModule, "err": err}).Info("get UPNP external address")
160 if address := GetIP(); address.Success == true {
161 extAddr = NewNetAddressIPPort(net.ParseIP(address.IP), uint16(lAddrPort))
165 extAddr = getNaiveExternalAddress(listenerPort, false)
168 cmn.PanicCrisis("could not determine external address!")
171 dl := &DefaultListener{
175 connections: make(chan net.Conn, numBufferedConnections),
177 dl.BaseService = *cmn.NewBaseService(nil, "DefaultListener", dl)
178 dl.Start() // Started upon construction
183 conn, err := net.DialTimeout("tcp", extAddr.String(), 3*time.Second)
191 //OnStart start listener
192 func (l *DefaultListener) OnStart() error {
193 l.BaseService.OnStart()
198 //OnStop stop listener
199 func (l *DefaultListener) OnStop() {
200 l.BaseService.OnStop()
204 //listenRoutine Accept connections and pass on the channel
205 func (l *DefaultListener) listenRoutine() {
207 conn, err := l.listener.Accept()
209 break // Go to cleanup
211 // listener wasn't stopped,
212 // yet we encountered an error.
216 l.connections <- conn
222 //Connections a channel of inbound connections. It gets closed when the listener closes.
223 func (l *DefaultListener) Connections() <-chan net.Conn {
227 //InternalAddress listener internal address
228 func (l *DefaultListener) InternalAddress() *NetAddress {
232 //ExternalAddress listener external address for remote peer dial
233 func (l *DefaultListener) ExternalAddress() *NetAddress {
237 // NetListener the returned listener is already Accept()'ing. So it's not suitable to pass into http.Serve().
238 func (l *DefaultListener) NetListener() net.Listener {
242 //String string of default listener
243 func (l *DefaultListener) String() string {
244 return fmt.Sprintf("Listener(@%v)", l.extAddr)