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.

281 lines
6.6 KiB

p2p: file descriptor leaks (#3150) * close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
6 years ago
p2p: file descriptor leaks (#3150) * close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
6 years ago
p2p: file descriptor leaks (#3150) * close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
6 years ago
p2p: file descriptor leaks (#3150) * close peer's connection to avoid fd leak Fixes #2967 * rename peer#Addr to RemoteAddr * fix test * fixes after Ethan's review * bring back the check * changelog entry * write a test for switch#acceptRoutine * increase timeouts? :( * remove extra assertNPeersWithTimeout * simplify test * assert number of peers (just to be safe) * Cleanup in OnStop * run tests with verbose flag on CircleCI * spawn a reading routine to prevent connection from closing * get port from the listener random port is faster, but often results in ``` panic: listen tcp 127.0.0.1:44068: bind: address already in use [recovered] panic: listen tcp 127.0.0.1:44068: bind: address already in use goroutine 79 [running]: testing.tRunner.func1(0xc0001bd600) /usr/local/go/src/testing/testing.go:792 +0x387 panic(0x974d20, 0xc0001b0500) /usr/local/go/src/runtime/panic.go:513 +0x1b9 github.com/tendermint/tendermint/p2p.MakeSwitch(0xc0000f42a0, 0x0, 0x9fb9cc, 0x9, 0x9fc346, 0xb, 0xb42128, 0x0, 0x0, 0x0, ...) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:182 +0xa28 github.com/tendermint/tendermint/p2p.MakeConnectedSwitches(0xc0000f42a0, 0x2, 0xb42128, 0xb41eb8, 0x4f1205, 0xc0001bed80, 0x4f16ed) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/test_util.go:75 +0xf9 github.com/tendermint/tendermint/p2p.MakeSwitchPair(0xbb8d20, 0xc0001bd600, 0xb42128, 0x2f7, 0x4f16c0) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:94 +0x4c github.com/tendermint/tendermint/p2p.TestSwitches(0xc0001bd600) /home/vagrant/go/src/github.com/tendermint/tendermint/p2p/switch_test.go:117 +0x58 testing.tRunner(0xc0001bd600, 0xb42038) /usr/local/go/src/testing/testing.go:827 +0xbf created by testing.(*T).Run /usr/local/go/src/testing/testing.go:878 +0x353 exit status 2 FAIL github.com/tendermint/tendermint/p2p 0.350s ```
6 years ago
  1. package p2p
  2. import (
  3. "fmt"
  4. "net"
  5. "time"
  6. "github.com/tendermint/tendermint/crypto"
  7. "github.com/tendermint/tendermint/crypto/ed25519"
  8. cmn "github.com/tendermint/tendermint/libs/common"
  9. "github.com/tendermint/tendermint/libs/log"
  10. "github.com/tendermint/tendermint/config"
  11. "github.com/tendermint/tendermint/p2p/conn"
  12. )
  13. const testCh = 0x01
  14. //------------------------------------------------
  15. type mockNodeInfo struct {
  16. addr *NetAddress
  17. }
  18. func (ni mockNodeInfo) ID() ID { return ni.addr.ID }
  19. func (ni mockNodeInfo) NetAddress() *NetAddress { return ni.addr }
  20. func (ni mockNodeInfo) Validate() error { return nil }
  21. func (ni mockNodeInfo) CompatibleWith(other NodeInfo) error { return nil }
  22. func AddPeerToSwitch(sw *Switch, peer Peer) {
  23. sw.peers.Add(peer)
  24. }
  25. func CreateRandomPeer(outbound bool) *peer {
  26. addr, netAddr := CreateRoutableAddr()
  27. p := &peer{
  28. peerConn: peerConn{
  29. outbound: outbound,
  30. },
  31. nodeInfo: mockNodeInfo{netAddr},
  32. mconn: &conn.MConnection{},
  33. metrics: NopMetrics(),
  34. }
  35. p.SetLogger(log.TestingLogger().With("peer", addr))
  36. return p
  37. }
  38. func CreateRoutableAddr() (addr string, netAddr *NetAddress) {
  39. for {
  40. var err error
  41. addr = fmt.Sprintf("%X@%v.%v.%v.%v:26656", cmn.RandBytes(20), cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256, cmn.RandInt()%256)
  42. netAddr, err = NewNetAddressString(addr)
  43. if err != nil {
  44. panic(err)
  45. }
  46. if netAddr.Routable() {
  47. break
  48. }
  49. }
  50. return
  51. }
  52. //------------------------------------------------------------------
  53. // Connects switches via arbitrary net.Conn. Used for testing.
  54. const TEST_HOST = "localhost"
  55. // MakeConnectedSwitches returns n switches, connected according to the connect func.
  56. // If connect==Connect2Switches, the switches will be fully connected.
  57. // initSwitch defines how the i'th switch should be initialized (ie. with what reactors).
  58. // NOTE: panics if any switch fails to start.
  59. func MakeConnectedSwitches(cfg *config.P2PConfig, n int, initSwitch func(int, *Switch) *Switch, connect func([]*Switch, int, int)) []*Switch {
  60. switches := make([]*Switch, n)
  61. for i := 0; i < n; i++ {
  62. switches[i] = MakeSwitch(cfg, i, TEST_HOST, "123.123.123", initSwitch)
  63. }
  64. if err := StartSwitches(switches); err != nil {
  65. panic(err)
  66. }
  67. for i := 0; i < n; i++ {
  68. for j := i + 1; j < n; j++ {
  69. connect(switches, i, j)
  70. }
  71. }
  72. return switches
  73. }
  74. // Connect2Switches will connect switches i and j via net.Pipe().
  75. // Blocks until a connection is established.
  76. // NOTE: caller ensures i and j are within bounds.
  77. func Connect2Switches(switches []*Switch, i, j int) {
  78. switchI := switches[i]
  79. switchJ := switches[j]
  80. c1, c2 := conn.NetPipe()
  81. doneCh := make(chan struct{})
  82. go func() {
  83. err := switchI.addPeerWithConnection(c1)
  84. if err != nil {
  85. panic(err)
  86. }
  87. doneCh <- struct{}{}
  88. }()
  89. go func() {
  90. err := switchJ.addPeerWithConnection(c2)
  91. if err != nil {
  92. panic(err)
  93. }
  94. doneCh <- struct{}{}
  95. }()
  96. <-doneCh
  97. <-doneCh
  98. }
  99. func (sw *Switch) addPeerWithConnection(conn net.Conn) error {
  100. pc, err := testInboundPeerConn(conn, sw.config, sw.nodeKey.PrivKey)
  101. if err != nil {
  102. if err := conn.Close(); err != nil {
  103. sw.Logger.Error("Error closing connection", "err", err)
  104. }
  105. return err
  106. }
  107. ni, err := handshake(conn, 50*time.Millisecond, sw.nodeInfo)
  108. if err != nil {
  109. if err := conn.Close(); err != nil {
  110. sw.Logger.Error("Error closing connection", "err", err)
  111. }
  112. return err
  113. }
  114. p := newPeer(
  115. pc,
  116. MConnConfig(sw.config),
  117. ni,
  118. sw.reactorsByCh,
  119. sw.chDescs,
  120. sw.StopPeerForError,
  121. )
  122. if err = sw.addPeer(p); err != nil {
  123. pc.CloseConn()
  124. return err
  125. }
  126. return nil
  127. }
  128. // StartSwitches calls sw.Start() for each given switch.
  129. // It returns the first encountered error.
  130. func StartSwitches(switches []*Switch) error {
  131. for _, s := range switches {
  132. err := s.Start() // start switch and reactors
  133. if err != nil {
  134. return err
  135. }
  136. }
  137. return nil
  138. }
  139. func MakeSwitch(
  140. cfg *config.P2PConfig,
  141. i int,
  142. network, version string,
  143. initSwitch func(int, *Switch) *Switch,
  144. opts ...SwitchOption,
  145. ) *Switch {
  146. nodeKey := NodeKey{
  147. PrivKey: ed25519.GenPrivKey(),
  148. }
  149. nodeInfo := testNodeInfo(nodeKey.ID(), fmt.Sprintf("node%d", i))
  150. t := NewMultiplexTransport(nodeInfo, nodeKey, MConnConfig(cfg))
  151. addr := nodeInfo.NetAddress()
  152. if err := t.Listen(*addr); err != nil {
  153. panic(err)
  154. }
  155. // TODO: let the config be passed in?
  156. sw := initSwitch(i, NewSwitch(cfg, t, opts...))
  157. sw.SetLogger(log.TestingLogger().With("switch", i))
  158. sw.SetNodeKey(&nodeKey)
  159. ni := nodeInfo.(DefaultNodeInfo)
  160. for ch := range sw.reactorsByCh {
  161. ni.Channels = append(ni.Channels, ch)
  162. }
  163. nodeInfo = ni
  164. // TODO: We need to setup reactors ahead of time so the NodeInfo is properly
  165. // populated and we don't have to do those awkward overrides and setters.
  166. t.nodeInfo = nodeInfo
  167. sw.SetNodeInfo(nodeInfo)
  168. return sw
  169. }
  170. func testInboundPeerConn(
  171. conn net.Conn,
  172. config *config.P2PConfig,
  173. ourNodePrivKey crypto.PrivKey,
  174. ) (peerConn, error) {
  175. return testPeerConn(conn, config, false, false, ourNodePrivKey, nil)
  176. }
  177. func testPeerConn(
  178. rawConn net.Conn,
  179. cfg *config.P2PConfig,
  180. outbound, persistent bool,
  181. ourNodePrivKey crypto.PrivKey,
  182. originalAddr *NetAddress,
  183. ) (pc peerConn, err error) {
  184. conn := rawConn
  185. // Fuzz connection
  186. if cfg.TestFuzz {
  187. // so we have time to do peer handshakes and get set up
  188. conn = FuzzConnAfterFromConfig(conn, 10*time.Second, cfg.TestFuzzConfig)
  189. }
  190. // Encrypt connection
  191. conn, err = upgradeSecretConn(conn, cfg.HandshakeTimeout, ourNodePrivKey)
  192. if err != nil {
  193. return pc, cmn.ErrorWrap(err, "Error creating peer")
  194. }
  195. // Only the information we already have
  196. return peerConn{
  197. outbound: outbound,
  198. persistent: persistent,
  199. conn: conn,
  200. originalAddr: originalAddr,
  201. }, nil
  202. }
  203. //----------------------------------------------------------------
  204. // rand node info
  205. func testNodeInfo(id ID, name string) NodeInfo {
  206. return testNodeInfoWithNetwork(id, name, "testing")
  207. }
  208. func testNodeInfoWithNetwork(id ID, name, network string) NodeInfo {
  209. port, err := getFreePort()
  210. if err != nil {
  211. panic(err)
  212. }
  213. return DefaultNodeInfo{
  214. ProtocolVersion: defaultProtocolVersion,
  215. ID_: id,
  216. ListenAddr: fmt.Sprintf("127.0.0.1:%d", port),
  217. Network: network,
  218. Version: "1.2.3-rc0-deadbeef",
  219. Channels: []byte{testCh},
  220. Moniker: name,
  221. Other: DefaultNodeInfoOther{
  222. TxIndex: "on",
  223. RPCAddress: fmt.Sprintf("127.0.0.1:%d", port),
  224. },
  225. }
  226. }
  227. func getFreePort() (int, error) {
  228. addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
  229. if err != nil {
  230. return 0, err
  231. }
  232. l, err := net.ListenTCP("tcp", addr)
  233. if err != nil {
  234. return 0, err
  235. }
  236. defer l.Close()
  237. return l.Addr().(*net.TCPAddr).Port, nil
  238. }