OSDN Git Service

Merge pull request #4 from Bytom/develop
[bytom/bytom.git] / p2p / listener.go
1 package p2p
2
3 import (
4         "fmt"
5         "net"
6         "strconv"
7         "time"
8
9         "github.com/bytom/p2p/upnp"
10         cmn "github.com/tendermint/tmlibs/common"
11         "github.com/tendermint/tmlibs/log"
12 )
13
14 type Listener interface {
15         Connections() <-chan net.Conn
16         InternalAddress() *NetAddress
17         ExternalAddress() *NetAddress
18         String() string
19         Stop() bool
20 }
21
22 // Implements Listener
23 type DefaultListener struct {
24         cmn.BaseService
25
26         listener    net.Listener
27         intAddr     *NetAddress
28         extAddr     *NetAddress
29         connections chan net.Conn
30 }
31
32 const (
33         numBufferedConnections = 10
34         defaultExternalPort    = 8770
35         tryListenSeconds       = 5
36 )
37
38 func splitHostPort(addr string) (host string, port int) {
39         host, portStr, err := net.SplitHostPort(addr)
40         if err != nil {
41                 cmn.PanicSanity(err)
42         }
43         port, err = strconv.Atoi(portStr)
44         if err != nil {
45                 cmn.PanicSanity(err)
46         }
47         return host, port
48 }
49
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)
54
55         // Create listener
56         var listener net.Listener
57         var err error
58         for i := 0; i < tryListenSeconds; i++ {
59                 listener, err = net.Listen(protocol, lAddr)
60                 if err == nil {
61                         break
62                 } else if i < tryListenSeconds-1 {
63                         time.Sleep(time.Second * 1)
64                 }
65         }
66         if err != nil {
67                 cmn.PanicCrisis(err)
68         }
69         // Actual listener local IP & port
70         listenerIP, listenerPort := splitHostPort(listener.Addr().String())
71         logger.Info("Local listener", "ip", listenerIP, "port", listenerPort)
72
73         // Determine internal address...
74         var intAddr *NetAddress
75         intAddr, err = NewNetAddressString(lAddr)
76         if err != nil {
77                 cmn.PanicCrisis(err)
78         }
79
80         // Determine external address...
81         var extAddr *NetAddress
82         if !skipUPNP {
83                 // If the lAddrIP is INADDR_ANY, try UPnP
84                 if lAddrIP == "" || lAddrIP == "0.0.0.0" {
85                         extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger)
86                 }
87         }
88         // Otherwise just use the local address...
89         if extAddr == nil {
90                 extAddr = getNaiveExternalAddress(listenerPort)
91         }
92         if extAddr == nil {
93                 cmn.PanicCrisis("Could not determine external address!")
94         }
95
96         dl := &DefaultListener{
97                 listener:    listener,
98                 intAddr:     intAddr,
99                 extAddr:     extAddr,
100                 connections: make(chan net.Conn, numBufferedConnections),
101         }
102         dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
103         dl.Start() // Started upon construction
104         return dl
105 }
106
107 func (l *DefaultListener) OnStart() error {
108         l.BaseService.OnStart()
109         go l.listenRoutine()
110         return nil
111 }
112
113 func (l *DefaultListener) OnStop() {
114         l.BaseService.OnStop()
115         l.listener.Close()
116 }
117
118 // Accept connections and pass on the channel
119 func (l *DefaultListener) listenRoutine() {
120         for {
121                 conn, err := l.listener.Accept()
122
123                 if !l.IsRunning() {
124                         break // Go to cleanup
125                 }
126
127                 // listener wasn't stopped,
128                 // yet we encountered an error.
129                 if err != nil {
130                         cmn.PanicCrisis(err)
131                 }
132
133                 l.connections <- conn
134         }
135
136         // Cleanup
137         close(l.connections)
138         for _ = range l.connections {
139                 // Drain
140         }
141 }
142
143 // A channel of inbound connections.
144 // It gets closed when the listener closes.
145 func (l *DefaultListener) Connections() <-chan net.Conn {
146         return l.connections
147 }
148
149 func (l *DefaultListener) InternalAddress() *NetAddress {
150         return l.intAddr
151 }
152
153 func (l *DefaultListener) ExternalAddress() *NetAddress {
154         return l.extAddr
155 }
156
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 {
160         return l.listener
161 }
162
163 func (l *DefaultListener) String() string {
164         return fmt.Sprintf("Listener(@%v)", l.extAddr)
165 }
166
167 /* external address helpers */
168
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()
173         if err != nil {
174                 logger.Info("Could not perform UPNP discover", "error", err)
175                 return nil
176         }
177
178         ext, err := nat.GetExternalAddress()
179         if err != nil {
180                 logger.Info("Could not get UPNP external address", "error", err)
181                 return nil
182         }
183
184         // UPnP can't seem to get the external port, so let's just be explicit.
185         if externalPort == 0 {
186                 externalPort = defaultExternalPort
187         }
188
189         externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0)
190         if err != nil {
191                 logger.Info("Could not add UPNP port mapping", "error", err)
192                 return nil
193         }
194
195         logger.Info("Got UPNP external address", "address", ext)
196         return NewNetAddressIPPort(ext, uint16(externalPort))
197 }
198
199 // TODO: use syscalls: http://pastebin.com/9exZG4rh
200 func getNaiveExternalAddress(port int) *NetAddress {
201         addrs, err := net.InterfaceAddrs()
202         if err != nil {
203                 cmn.PanicCrisis(cmn.Fmt("Could not fetch interface addresses: %v", err))
204         }
205
206         for _, a := range addrs {
207                 ipnet, ok := a.(*net.IPNet)
208                 if !ok {
209                         continue
210                 }
211                 v4 := ipnet.IP.To4()
212                 if v4 == nil || v4[0] == 127 {
213                         continue
214                 } // loopback
215                 return NewNetAddressIPPort(ipnet.IP, uint16(port))
216         }
217         return nil
218 }