OSDN Git Service

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