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.

162 lines
3.3 KiB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
  1. package p2p
  2. import (
  3. "net"
  4. "strconv"
  5. "sync/atomic"
  6. . "github.com/tendermint/tendermint/binary"
  7. . "github.com/tendermint/tendermint/common"
  8. "github.com/tendermint/tendermint/p2p/upnp"
  9. )
  10. /*
  11. Listener is part of a Server.
  12. */
  13. type Listener interface {
  14. Connections() <-chan *Connection
  15. ExternalAddress() *NetAddress
  16. Stop()
  17. }
  18. /*
  19. DefaultListener is an implementation that works on the golang network stack.
  20. */
  21. type DefaultListener struct {
  22. listener net.Listener
  23. extAddr *NetAddress
  24. connections chan *Connection
  25. stopped uint32
  26. }
  27. const (
  28. NumBufferedConnections = 10
  29. )
  30. func NewDefaultListener(protocol string, listenAddr string) Listener {
  31. listenHost, listenPortStr, err := net.SplitHostPort(listenAddr)
  32. if err != nil {
  33. panic(err)
  34. }
  35. listenPort, err := strconv.Atoi(listenPortStr)
  36. if err != nil {
  37. panic(err)
  38. }
  39. // Determine external address...
  40. var extAddr *NetAddress
  41. // If the listenHost is INADDR_ANY, try UPnP
  42. if listenHost == "" || listenHost == "0.0.0.0" {
  43. extAddr = getUPNPExternalAddress(listenPort, listenPort)
  44. }
  45. // Otherwise just use the local address...
  46. if extAddr == nil {
  47. extAddr = getNaiveExternalAddress(listenPort)
  48. }
  49. if extAddr == nil {
  50. panic("Could not determine external address!")
  51. }
  52. // Create listener
  53. listener, err := net.Listen(protocol, listenAddr)
  54. if err != nil {
  55. panic(err)
  56. }
  57. dl := &DefaultListener{
  58. listener: listener,
  59. extAddr: extAddr,
  60. connections: make(chan *Connection, NumBufferedConnections),
  61. }
  62. go dl.listenHandler()
  63. return dl
  64. }
  65. func (l *DefaultListener) listenHandler() {
  66. for {
  67. conn, err := l.listener.Accept()
  68. if atomic.LoadUint32(&l.stopped) == 1 {
  69. break // go to cleanup
  70. }
  71. // listener wasn't stopped,
  72. // yet we encountered an error.
  73. if err != nil {
  74. panic(err)
  75. }
  76. c := NewConnection(conn)
  77. l.connections <- c
  78. }
  79. // cleanup
  80. close(l.connections)
  81. for _ = range l.connections {
  82. // drain
  83. }
  84. }
  85. func (l *DefaultListener) Connections() <-chan *Connection {
  86. return l.connections
  87. }
  88. func (l *DefaultListener) ExternalAddress() *NetAddress {
  89. return l.extAddr
  90. }
  91. func (l *DefaultListener) Stop() {
  92. if atomic.CompareAndSwapUint32(&l.stopped, 0, 1) {
  93. l.listener.Close()
  94. }
  95. }
  96. /* external address helpers */
  97. // UPNP external address discovery & port mapping
  98. func getUPNPExternalAddress(externalPort, internalPort int) *NetAddress {
  99. log.Infof("Getting UPNP external address")
  100. nat, err := upnp.Discover()
  101. if err != nil {
  102. log.Infof("Could not get UPNP extrernal address: %v", err)
  103. return nil
  104. }
  105. ext, err := nat.GetExternalAddress()
  106. if err != nil {
  107. log.Infof("Could not get UPNP external address: %v", err)
  108. return nil
  109. }
  110. externalPort, err = nat.AddPortMapping("tcp", externalPort, internalPort, "tendermint", 0)
  111. if err != nil {
  112. log.Infof("Could not get UPNP external address: %v", err)
  113. return nil
  114. }
  115. log.Infof("Got UPNP external address: %v", ext)
  116. return NewNetAddressIPPort(ext, UInt16(externalPort))
  117. }
  118. // TODO: use syscalls: http://pastebin.com/9exZG4rh
  119. func getNaiveExternalAddress(port int) *NetAddress {
  120. addrs, err := net.InterfaceAddrs()
  121. if err != nil {
  122. Panicf("Unexpected error fetching interface addresses: %v", err)
  123. }
  124. for _, a := range addrs {
  125. ipnet, ok := a.(*net.IPNet)
  126. if !ok {
  127. continue
  128. }
  129. v4 := ipnet.IP.To4()
  130. if v4 == nil || v4[0] == 127 {
  131. continue
  132. } // loopback
  133. return NewNetAddressIPPort(ipnet.IP, UInt16(port))
  134. }
  135. return nil
  136. }