OSDN Git Service

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