You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
6.7 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package p2p
  2. import (
  3. "fmt"
  4. "net"
  5. "strconv"
  6. "strings"
  7. "time"
  8. "github.com/tendermint/tendermint/p2p/upnp"
  9. cmn "github.com/tendermint/tendermint/libs/common"
  10. "github.com/tendermint/tendermint/libs/log"
  11. )
  12. // Listener is a network listener for stream-oriented protocols, providing
  13. // convenient methods to get listener's internal and external addresses.
  14. // Clients are supposed to read incoming connections from a channel, returned
  15. // by Connections() method.
  16. type Listener interface {
  17. Connections() <-chan net.Conn
  18. InternalAddress() *NetAddress
  19. ExternalAddress() *NetAddress
  20. ExternalAddressHost() string
  21. String() string
  22. Stop() error
  23. }
  24. // DefaultListener is a cmn.Service, running net.Listener underneath.
  25. // Optionally, UPnP is used upon calling NewDefaultListener to resolve external
  26. // address.
  27. type DefaultListener struct {
  28. cmn.BaseService
  29. listener net.Listener
  30. intAddr *NetAddress
  31. extAddr *NetAddress
  32. connections chan net.Conn
  33. }
  34. var _ Listener = (*DefaultListener)(nil)
  35. const (
  36. numBufferedConnections = 10
  37. defaultExternalPort = 8770
  38. tryListenSeconds = 5
  39. )
  40. func splitHostPort(addr string) (host string, port int) {
  41. host, portStr, err := net.SplitHostPort(addr)
  42. if err != nil {
  43. panic(err)
  44. }
  45. port, err = strconv.Atoi(portStr)
  46. if err != nil {
  47. panic(err)
  48. }
  49. return host, port
  50. }
  51. // NewDefaultListener creates a new DefaultListener on lAddr, optionally trying
  52. // to determine external address using UPnP.
  53. func NewDefaultListener(protocol string, lAddr string, UPNP bool, logger log.Logger) Listener {
  54. // Local listen IP & port
  55. lAddrIP, lAddrPort := splitHostPort(lAddr)
  56. // Create listener
  57. var listener net.Listener
  58. var err error
  59. for i := 0; i < tryListenSeconds; i++ {
  60. listener, err = net.Listen(protocol, lAddr)
  61. if err == nil {
  62. break
  63. } else if i < tryListenSeconds-1 {
  64. time.Sleep(time.Second * 1)
  65. }
  66. }
  67. if err != nil {
  68. panic(err)
  69. }
  70. // Actual listener local IP & port
  71. listenerIP, listenerPort := splitHostPort(listener.Addr().String())
  72. logger.Info("Local listener", "ip", listenerIP, "port", listenerPort)
  73. // Determine internal address...
  74. var intAddr *NetAddress
  75. intAddr, err = NewNetAddressStringWithOptionalID(lAddr)
  76. if err != nil {
  77. panic(err)
  78. }
  79. // Determine external address...
  80. var extAddr *NetAddress
  81. if UPNP {
  82. // If the lAddrIP is INADDR_ANY, try UPnP
  83. if lAddrIP == "" || lAddrIP == "0.0.0.0" {
  84. extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger)
  85. }
  86. }
  87. // Otherwise just use the local address...
  88. if extAddr == nil {
  89. extAddr = getNaiveExternalAddress(listenerPort, false, logger)
  90. }
  91. if extAddr == nil {
  92. panic("Could not determine external address!")
  93. }
  94. dl := &DefaultListener{
  95. listener: listener,
  96. intAddr: intAddr,
  97. extAddr: extAddr,
  98. connections: make(chan net.Conn, numBufferedConnections),
  99. }
  100. dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
  101. err = dl.Start() // Started upon construction
  102. if err != nil {
  103. logger.Error("Error starting base service", "err", err)
  104. }
  105. return dl
  106. }
  107. // OnStart implements cmn.Service by spinning a goroutine, listening for new
  108. // connections.
  109. func (l *DefaultListener) OnStart() error {
  110. if err := l.BaseService.OnStart(); err != nil {
  111. return err
  112. }
  113. go l.listenRoutine()
  114. return nil
  115. }
  116. // OnStop implements cmn.Service by closing the listener.
  117. func (l *DefaultListener) OnStop() {
  118. l.BaseService.OnStop()
  119. l.listener.Close() // nolint: errcheck
  120. }
  121. // Accept connections and pass on the channel
  122. func (l *DefaultListener) listenRoutine() {
  123. for {
  124. conn, err := l.listener.Accept()
  125. if !l.IsRunning() {
  126. break // Go to cleanup
  127. }
  128. // listener wasn't stopped,
  129. // yet we encountered an error.
  130. if err != nil {
  131. panic(err)
  132. }
  133. l.connections <- conn
  134. }
  135. // Cleanup
  136. close(l.connections)
  137. for range l.connections {
  138. // Drain
  139. }
  140. }
  141. // Connections returns a channel of inbound connections.
  142. // It gets closed when the listener closes.
  143. func (l *DefaultListener) Connections() <-chan net.Conn {
  144. return l.connections
  145. }
  146. // InternalAddress returns the internal NetAddress (address used for
  147. // listening).
  148. func (l *DefaultListener) InternalAddress() *NetAddress {
  149. return l.intAddr
  150. }
  151. // ExternalAddress returns the external NetAddress (publicly available,
  152. // determined using either UPnP or local resolver).
  153. func (l *DefaultListener) ExternalAddress() *NetAddress {
  154. return l.extAddr
  155. }
  156. // ExternalAddressHost returns the external NetAddress IP string. If an IP is
  157. // IPv6, it's wrapped in brackets ("[2001:db8:1f70::999:de8:7648:6e8]").
  158. func (l *DefaultListener) ExternalAddressHost() string {
  159. ip := l.ExternalAddress().IP
  160. if isIpv6(ip) {
  161. // Means it's ipv6, so format it with brackets
  162. return "[" + ip.String() + "]"
  163. }
  164. return ip.String()
  165. }
  166. func (l *DefaultListener) String() string {
  167. return fmt.Sprintf("Listener(@%v)", l.extAddr)
  168. }
  169. /* external address helpers */
  170. // UPNP external address discovery & port mapping
  171. func getUPNPExternalAddress(externalPort, internalPort int, logger log.Logger) *NetAddress {
  172. logger.Info("Getting UPNP external address")
  173. nat, err := upnp.Discover()
  174. if err != nil {
  175. logger.Info("Could not perform UPNP discover", "err", err)
  176. return nil
  177. }
  178. ext, err := nat.GetExternalAddress()
  179. if err != nil {
  180. logger.Info("Could not get UPNP external address", "err", err)
  181. return nil
  182. }
  183. // UPnP can't seem to get the external port, so let's just be explicit.
  184. if externalPort == 0 {
  185. externalPort = defaultExternalPort
  186. }
  187. externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0)
  188. if err != nil {
  189. logger.Info("Could not add UPNP port mapping", "err", err)
  190. return nil
  191. }
  192. logger.Info("Got UPNP external address", "address", ext)
  193. return NewNetAddressIPPort(ext, uint16(externalPort))
  194. }
  195. func isIpv6(ip net.IP) bool {
  196. v4 := ip.To4()
  197. if v4 != nil {
  198. return false
  199. }
  200. ipString := ip.String()
  201. // Extra check just to be sure it's IPv6
  202. return (strings.Contains(ipString, ":") && !strings.Contains(ipString, "."))
  203. }
  204. // TODO: use syscalls: see issue #712
  205. func getNaiveExternalAddress(port int, settleForLocal bool, logger log.Logger) *NetAddress {
  206. addrs, err := net.InterfaceAddrs()
  207. if err != nil {
  208. panic(cmn.Fmt("Could not fetch interface addresses: %v", err))
  209. }
  210. for _, a := range addrs {
  211. ipnet, ok := a.(*net.IPNet)
  212. if !ok {
  213. continue
  214. }
  215. if !isIpv6(ipnet.IP) {
  216. v4 := ipnet.IP.To4()
  217. if v4 == nil || (!settleForLocal && v4[0] == 127) {
  218. // loopback
  219. continue
  220. }
  221. } else if !settleForLocal && ipnet.IP.IsLoopback() {
  222. // IPv6, check for loopback
  223. continue
  224. }
  225. return NewNetAddressIPPort(ipnet.IP, uint16(port))
  226. }
  227. // try again, but settle for local
  228. logger.Info("Node may not be connected to internet. Settling for local address")
  229. return getNaiveExternalAddress(port, true, logger)
  230. }