OSDN Git Service

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