9 "github.com/bytom/p2p/upnp"
10 cmn "github.com/tendermint/tmlibs/common"
11 "github.com/tendermint/tmlibs/log"
14 type Listener interface {
15 Connections() <-chan net.Conn
16 InternalAddress() *NetAddress
17 ExternalAddress() *NetAddress
22 // Implements Listener
23 type DefaultListener struct {
29 connections chan net.Conn
33 numBufferedConnections = 10
34 defaultExternalPort = 8770
38 func splitHostPort(addr string) (host string, port int) {
39 host, portStr, err := net.SplitHostPort(addr)
43 port, err = strconv.Atoi(portStr)
50 // skipUPNP: If true, does not try getUPNPExternalAddress()
51 func NewDefaultListener(protocol string, lAddr string, skipUPNP bool, logger log.Logger) Listener {
52 // Local listen IP & port
53 lAddrIP, lAddrPort := splitHostPort(lAddr)
56 var listener net.Listener
58 for i := 0; i < tryListenSeconds; i++ {
59 listener, err = net.Listen(protocol, lAddr)
62 } else if i < tryListenSeconds-1 {
63 time.Sleep(time.Second * 1)
69 // Actual listener local IP & port
70 listenerIP, listenerPort := splitHostPort(listener.Addr().String())
71 logger.Info("Local listener", "ip", listenerIP, "port", listenerPort)
73 // Determine internal address...
74 var intAddr *NetAddress
75 intAddr, err = NewNetAddressString(lAddr)
80 // Determine external address...
81 var extAddr *NetAddress
83 // If the lAddrIP is INADDR_ANY, try UPnP
84 if lAddrIP == "" || lAddrIP == "0.0.0.0" {
85 extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger)
88 // Otherwise just use the local address...
90 extAddr = getNaiveExternalAddress(listenerPort)
93 cmn.PanicCrisis("Could not determine external address!")
96 dl := &DefaultListener{
100 connections: make(chan net.Conn, numBufferedConnections),
102 dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
103 dl.Start() // Started upon construction
107 func (l *DefaultListener) OnStart() error {
108 l.BaseService.OnStart()
113 func (l *DefaultListener) OnStop() {
114 l.BaseService.OnStop()
118 // Accept connections and pass on the channel
119 func (l *DefaultListener) listenRoutine() {
121 conn, err := l.listener.Accept()
124 break // Go to cleanup
127 // listener wasn't stopped,
128 // yet we encountered an error.
133 l.connections <- conn
138 for _ = range l.connections {
143 // A channel of inbound connections.
144 // It gets closed when the listener closes.
145 func (l *DefaultListener) Connections() <-chan net.Conn {
149 func (l *DefaultListener) InternalAddress() *NetAddress {
153 func (l *DefaultListener) ExternalAddress() *NetAddress {
157 // NOTE: The returned listener is already Accept()'ing.
158 // So it's not suitable to pass into http.Serve().
159 func (l *DefaultListener) NetListener() net.Listener {
163 func (l *DefaultListener) String() string {
164 return fmt.Sprintf("Listener(@%v)", l.extAddr)
167 /* external address helpers */
169 // UPNP external address discovery & port mapping
170 func getUPNPExternalAddress(externalPort, internalPort int, logger log.Logger) *NetAddress {
171 logger.Info("Getting UPNP external address")
172 nat, err := upnp.Discover()
174 logger.Info("Could not perform UPNP discover", "error", err)
178 ext, err := nat.GetExternalAddress()
180 logger.Info("Could not get UPNP external address", "error", err)
184 // UPnP can't seem to get the external port, so let's just be explicit.
185 if externalPort == 0 {
186 externalPort = defaultExternalPort
189 externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0)
191 logger.Info("Could not add UPNP port mapping", "error", err)
195 logger.Info("Got UPNP external address", "address", ext)
196 return NewNetAddressIPPort(ext, uint16(externalPort))
199 // TODO: use syscalls: http://pastebin.com/9exZG4rh
200 func getNaiveExternalAddress(port int) *NetAddress {
201 addrs, err := net.InterfaceAddrs()
203 cmn.PanicCrisis(cmn.Fmt("Could not fetch interface addresses: %v", err))
206 for _, a := range addrs {
207 ipnet, ok := a.(*net.IPNet)
212 if v4 == nil || v4[0] == 127 {
215 return NewNetAddressIPPort(ipnet.IP, uint16(port))