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.

286 lines
7.2 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
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
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. cmn "github.com/tendermint/tendermint/libs/common"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/p2p/upnp"
  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(
  54. fullListenAddrString string,
  55. externalAddrString string,
  56. useUPnP bool,
  57. logger log.Logger) Listener {
  58. // Split protocol, address, and port.
  59. protocol, lAddr := cmn.ProtocolAndAddress(fullListenAddrString)
  60. lAddrIP, lAddrPort := splitHostPort(lAddr)
  61. // Create listener
  62. var listener net.Listener
  63. var err error
  64. for i := 0; i < tryListenSeconds; i++ {
  65. listener, err = net.Listen(protocol, lAddr)
  66. if err == nil {
  67. break
  68. } else if i < tryListenSeconds-1 {
  69. time.Sleep(time.Second * 1)
  70. }
  71. }
  72. if err != nil {
  73. panic(err)
  74. }
  75. // Actual listener local IP & port
  76. listenerIP, listenerPort := splitHostPort(listener.Addr().String())
  77. logger.Info("Local listener", "ip", listenerIP, "port", listenerPort)
  78. // Determine internal address...
  79. var intAddr *NetAddress
  80. intAddr, err = NewNetAddressStringWithOptionalID(lAddr)
  81. if err != nil {
  82. panic(err)
  83. }
  84. inAddrAny := lAddrIP == "" || lAddrIP == "0.0.0.0"
  85. // Determine external address.
  86. var extAddr *NetAddress
  87. if externalAddrString != "" {
  88. var err error
  89. extAddr, err = NewNetAddressStringWithOptionalID(externalAddrString)
  90. if err != nil {
  91. panic(fmt.Sprintf("Error in ExternalAddress: %v", err))
  92. }
  93. }
  94. // If the lAddrIP is INADDR_ANY, try UPnP.
  95. if extAddr == nil && useUPnP && inAddrAny {
  96. extAddr = getUPNPExternalAddress(lAddrPort, listenerPort, logger)
  97. }
  98. // Otherwise just use the local address.
  99. if extAddr == nil {
  100. defaultToIPv4 := inAddrAny
  101. extAddr = getNaiveExternalAddress(defaultToIPv4, listenerPort, false, logger)
  102. }
  103. if extAddr == nil {
  104. panic("Could not determine external address!")
  105. }
  106. dl := &DefaultListener{
  107. listener: listener,
  108. intAddr: intAddr,
  109. extAddr: extAddr,
  110. connections: make(chan net.Conn, numBufferedConnections),
  111. }
  112. dl.BaseService = *cmn.NewBaseService(logger, "DefaultListener", dl)
  113. err = dl.Start() // Started upon construction
  114. if err != nil {
  115. logger.Error("Error starting base service", "err", err)
  116. }
  117. return dl
  118. }
  119. // OnStart implements cmn.Service by spinning a goroutine, listening for new
  120. // connections.
  121. func (l *DefaultListener) OnStart() error {
  122. if err := l.BaseService.OnStart(); err != nil {
  123. return err
  124. }
  125. go l.listenRoutine()
  126. return nil
  127. }
  128. // OnStop implements cmn.Service by closing the listener.
  129. func (l *DefaultListener) OnStop() {
  130. l.BaseService.OnStop()
  131. l.listener.Close() // nolint: errcheck
  132. }
  133. // Accept connections and pass on the channel.
  134. func (l *DefaultListener) listenRoutine() {
  135. for {
  136. conn, err := l.listener.Accept()
  137. if !l.IsRunning() {
  138. break // Go to cleanup
  139. }
  140. // listener wasn't stopped,
  141. // yet we encountered an error.
  142. if err != nil {
  143. panic(err)
  144. }
  145. l.connections <- conn
  146. }
  147. // Cleanup
  148. close(l.connections)
  149. for range l.connections {
  150. // Drain
  151. }
  152. }
  153. // Connections returns a channel of inbound connections.
  154. // It gets closed when the listener closes.
  155. // It is the callers responsibility to close any connections received
  156. // over this channel.
  157. func (l *DefaultListener) Connections() <-chan net.Conn {
  158. return l.connections
  159. }
  160. // InternalAddress returns the internal NetAddress (address used for
  161. // listening).
  162. func (l *DefaultListener) InternalAddress() *NetAddress {
  163. return l.intAddr
  164. }
  165. // ExternalAddress returns the external NetAddress (publicly available,
  166. // determined using either UPnP or local resolver).
  167. func (l *DefaultListener) ExternalAddress() *NetAddress {
  168. return l.extAddr
  169. }
  170. // ExternalAddressHost returns the external NetAddress IP string. If an IP is
  171. // IPv6, it's wrapped in brackets ("[2001:db8:1f70::999:de8:7648:6e8]").
  172. func (l *DefaultListener) ExternalAddressHost() string {
  173. ip := l.ExternalAddress().IP
  174. if isIpv6(ip) {
  175. // Means it's ipv6, so format it with brackets
  176. return "[" + ip.String() + "]"
  177. }
  178. return ip.String()
  179. }
  180. func (l *DefaultListener) String() string {
  181. return fmt.Sprintf("Listener(@%v)", l.extAddr)
  182. }
  183. /* external address helpers */
  184. // UPNP external address discovery & port mapping
  185. func getUPNPExternalAddress(externalPort, internalPort int, logger log.Logger) *NetAddress {
  186. logger.Info("Getting UPNP external address")
  187. nat, err := upnp.Discover()
  188. if err != nil {
  189. logger.Info("Could not perform UPNP discover", "err", err)
  190. return nil
  191. }
  192. ext, err := nat.GetExternalAddress()
  193. if err != nil {
  194. logger.Info("Could not get UPNP external address", "err", err)
  195. return nil
  196. }
  197. // UPnP can't seem to get the external port, so let's just be explicit.
  198. if externalPort == 0 {
  199. externalPort = defaultExternalPort
  200. }
  201. externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0)
  202. if err != nil {
  203. logger.Info("Could not add UPNP port mapping", "err", err)
  204. return nil
  205. }
  206. logger.Info("Got UPNP external address", "address", ext)
  207. return NewNetAddressIPPort(ext, uint16(externalPort))
  208. }
  209. func isIpv6(ip net.IP) bool {
  210. v4 := ip.To4()
  211. if v4 != nil {
  212. return false
  213. }
  214. ipString := ip.String()
  215. // Extra check just to be sure it's IPv6
  216. return (strings.Contains(ipString, ":") && !strings.Contains(ipString, "."))
  217. }
  218. // TODO: use syscalls: see issue #712
  219. func getNaiveExternalAddress(defaultToIPv4 bool, port int, settleForLocal bool, logger log.Logger) *NetAddress {
  220. addrs, err := net.InterfaceAddrs()
  221. if err != nil {
  222. panic(cmn.Fmt("Could not fetch interface addresses: %v", err))
  223. }
  224. for _, a := range addrs {
  225. ipnet, ok := a.(*net.IPNet)
  226. if !ok {
  227. continue
  228. }
  229. if defaultToIPv4 || !isIpv6(ipnet.IP) {
  230. v4 := ipnet.IP.To4()
  231. if v4 == nil || (!settleForLocal && v4[0] == 127) {
  232. // loopback
  233. continue
  234. }
  235. } else if !settleForLocal && ipnet.IP.IsLoopback() {
  236. // IPv6, check for loopback
  237. continue
  238. }
  239. return NewNetAddressIPPort(ipnet.IP, uint16(port))
  240. }
  241. // try again, but settle for local
  242. logger.Info("Node may not be connected to internet. Settling for local address")
  243. return getNaiveExternalAddress(defaultToIPv4, port, true, logger)
  244. }