@cryptotaxi247 / kubo / commits / 393842e24

much simpler net

- removed ctxcloser - removed multiconn - focused on netio

Juan Batiz-Benet committed Dec 14, 2014 at 14:14 UTC 393842e24569ed6c3ced3490f2f42433f1ed71a8
12 files changed +202 -1053
net/conn/conn.go
+5 -16
@@ -13,17 +13,14 @@ import (
13
14 peer "github.com/jbenet/go-ipfs/peer"
15 u "github.com/jbenet/go-ipfs/util"
16 - ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
16 + eventlog "github.com/jbenet/go-ipfs/util/eventlog"
17 )
18
19 -var log = u.Logger("conn")
19 +var log = eventlog.Logger("conn")
20
21 const (
22 // MaxMessageSize is the size of the largest single message. (4MB)
23 MaxMessageSize = 1 << 22
24 -
25 - // HandshakeTimeout for when nodes first connect
26 - HandshakeTimeout = time.Second * 5
24 )
25
26 // ReleaseBuffer puts the given byte array back into the buffer pool,
@@ -39,13 +36,10 @@ type singleConn struct {
36 remote peer.Peer
37 maconn manet.Conn
38 msgrw msgio.ReadWriteCloser
42 -
43 - ctxc.ContextCloser
39 }
40
41 // newConn constructs a new connection
47 -func newSingleConn(ctx context.Context, local, remote peer.Peer,
48 - maconn manet.Conn) (Conn, error) {
42 +func newSingleConn(ctx context.Context, local, remote peer.Peer, maconn manet.Conn) (Conn, error) {
43
44 conn := &singleConn{
45 local: local,
@@ -53,14 +47,10 @@ func newSingleConn(ctx context.Context, local, remote peer.Peer,
47 maconn: maconn,
48 msgrw: msgio.NewReadWriter(maconn),
49 }
56 -
57 - conn.ContextCloser = ctxc.NewContextCloser(ctx, conn.close)
58 -
50 log.Debugf("newSingleConn %p: %v to %v", conn, local, remote)
51
52 // version handshake
62 - ctxT, _ := context.WithTimeout(ctx, HandshakeTimeout)
63 - if err := Handshake1(ctxT, conn); err != nil {
53 + if err := Handshake1(ctx, conn); err != nil {
54 conn.Close()
55 return nil, fmt.Errorf("Handshake1 failed: %s", err)
56 }
@@ -70,9 +60,8 @@ func newSingleConn(ctx context.Context, local, remote peer.Peer,
60 }
61
62 // close is the internal close function, called by ContextCloser.Close
73 -func (c *singleConn) close() error {
63 +func (c *singleConn) Close() error {
64 log.Debugf("%s closing Conn with %s", c.local, c.remote)
75 -
65 // close underlying connection
66 return c.msgrw.Close()
67 }
net/conn/conn_test.go
+30 -52
@@ -13,73 +13,51 @@ import (
13 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
14 )
15
16 -func TestClose(t *testing.T) {
17 - // t.Skip("Skipping in favor of another test")
18 -
19 - ctx, cancel := context.WithCancel(context.Background())
20 - c1, c2 := setupConn(t, ctx, "/ip4/127.0.0.1/tcp/5534", "/ip4/127.0.0.1/tcp/5545")
21 -
22 - select {
23 - case <-c1.Closed():
24 - t.Fatal("done before close")
25 - case <-c2.Closed():
26 - t.Fatal("done before close")
27 - default:
16 +func testOneSendRecv(t *testing.T, c1, c2 Conn) {
17 + m1 := []byte("hello")
18 + if err := c1.WriteMsg(m1); err != nil {
19 + t.Fatal(err)
20 }
29 -
30 - c1.Close()
31 -
32 - select {
33 - case <-c1.Closed():
34 - default:
35 - t.Fatal("not done after cancel")
21 + m2, err := c2.ReadMsg()
22 + if err != nil {
23 + t.Fatal(err)
24 }
37 -
38 - c2.Close()
39 -
40 - select {
41 - case <-c2.Closed():
42 - default:
43 - t.Fatal("not done after cancel")
25 + if !bytes.Equal(m1, m2) {
26 + t.Fatal("failed to send: %s %s", m1, m2)
27 }
28 +}
29
46 - cancel() // close the listener :P
30 +func testNotOneSendRecv(t *testing.T, c1, c2 Conn) {
31 + m1 := []byte("hello")
32 + if err := c1.WriteMsg(m1); err == nil {
33 + t.Fatal("write should have failed", err)
34 + }
35 + _, err := c2.ReadMsg()
36 + if err == nil {
37 + t.Fatal("read should have failed", err)
38 + }
39 }
40
49 -func TestCancel(t *testing.T) {
41 +func TestClose(t *testing.T) {
42 // t.Skip("Skipping in favor of another test")
43
52 - ctx, cancel := context.WithCancel(context.Background())
44 + ctx := context.Background()
45 c1, c2 := setupConn(t, ctx, "/ip4/127.0.0.1/tcp/5534", "/ip4/127.0.0.1/tcp/5545")
46
55 - select {
56 - case <-c1.Closed():
57 - t.Fatal("done before close")
58 - case <-c2.Closed():
59 - t.Fatal("done before close")
60 - default:
61 - }
47 + testOneSendRecv(t, c1, c2)
48 + testOneSendRecv(t, c2, c1)
49
50 c1.Close()
64 - c2.Close()
65 - cancel() // listener
66 -
67 - // wait to ensure other goroutines run and close things.
68 - <-time.After(time.Microsecond * 10)
69 - // test that cancel called Close.
51
71 - select {
72 - case <-c1.Closed():
73 - default:
74 - t.Fatal("not done after cancel")
75 - }
52 + time.After(200 * time.Millisecond)
53 + testNotOneSendRecv(t, c1, c2)
54 + testNotOneSendRecv(t, c2, c1)
55
77 - select {
78 - case <-c2.Closed():
79 - default:
80 - t.Fatal("not done after cancel")
81 - }
56 + c2.Close()
57
58 + time.After(20000 * time.Millisecond)
59 + testNotOneSendRecv(t, c1, c2)
60 + testNotOneSendRecv(t, c2, c1)
61 }
62
63 func TestCloseLeak(t *testing.T) {
net/conn/dial.go
+14 -1
@@ -4,7 +4,6 @@ import (
4 "strings"
5
6 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
7 -
7 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
8 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
9
@@ -67,11 +66,25 @@ func (d *Dialer) DialAddr(ctx context.Context, raddr ma.Multiaddr, remote peer.P
66 return nil, err
67 }
68
69 + select {
70 + case <-ctx.Done():
71 + maconn.Close()
72 + return nil, err
73 + default:
74 + }
75 +
76 c, err := newSingleConn(ctx, d.LocalPeer, remote, maconn)
77 if err != nil {
78 return nil, err
79 }
80
81 + select {
82 + case <-ctx.Done():
83 + c.Close()
84 + return nil, err
85 + default:
86 + }
87 +
88 // return c, nil
89 return newSecureConn(ctx, c, d.Peerstore)
90 }
net/conn/dial_test.go
+24 -11
@@ -33,16 +33,19 @@ func setupPeer(addr string) (peer.Peer, error) {
33
34 func echoListen(ctx context.Context, listener Listener) {
35 for {
36 - select {
37 - case <-ctx.Done():
38 - return
39 - case c := <-listener.Accept():
40 - go echo(ctx, c)
36 + c, err := listener.Accept()
37 + if err != nil {
38 + select {
39 + case <-ctx.Done():
40 + return
41 + default:
42 + }
43 }
44 + go echo(c.(Conn))
45 }
46 }
47
45 -func echo(ctx context.Context, c Conn) {
48 +func echo(c Conn) {
49 io.Copy(c, c)
50 }
51
@@ -78,14 +81,24 @@ func setupConn(t *testing.T, ctx context.Context, a1, a2 string) (a, b Conn) {
81 LocalPeer: p2,
82 }
83
81 - c2, err := d2.Dial(ctx, "tcp", p1)
84 + var c2 Conn
85 +
86 + done := make(chan struct{})
87 + go func() {
88 + c2, err = d2.Dial(ctx, "tcp", p1)
89 + if err != nil {
90 + t.Fatal("error dialing peer", err)
91 + }
92 + done <- struct{}{}
93 + }()
94 +
95 + c1, err := l1.Accept()
96 if err != nil {
83 - t.Fatal("error dialing peer", err)
97 + t.Fatal("failed to accept")
98 }
99 + <-done
100
86 - c1 := <-l1.Accept()
87 -
88 - return c1, c2
101 + return c1.(Conn), c2
102 }
103
104 func TestDialer(t *testing.T) {
net/conn/handshake.go
+33 -37
@@ -6,8 +6,9 @@ import (
6 handshake "github.com/jbenet/go-ipfs/net/handshake"
7 hspb "github.com/jbenet/go-ipfs/net/handshake/pb"
8
9 + ggprotoio "code.google.com/p/gogoprotobuf/io"
10 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
10 - proto "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
11 + ps "github.com/jbenet/go-peerstream"
12 )
13
14 // Handshake1 exchanges local and remote versions and compares them
@@ -16,30 +17,31 @@ func Handshake1(ctx context.Context, c Conn) error {
17 rpeer := c.RemotePeer()
18 lpeer := c.LocalPeer()
19
19 - var remoteH, localH *hspb.Handshake1
20 - localH = handshake.Handshake1Msg()
20 + // setup up protobuf io
21 + maxSize := 4096
22 + r := ggprotoio.NewDelimitedReader(c, maxSize)
23 + w := ggprotoio.NewDelimitedWriter(c)
24 + localH := handshake.Handshake1Msg()
25 + remoteH := new(hspb.Handshake1)
26
22 - myVerBytes, err := proto.Marshal(localH)
23 - if err != nil {
24 - return err
25 - }
26 -
27 - if err := CtxWriteMsg(ctx, c, myVerBytes); err != nil {
27 + // send the outgoing handshake message
28 + if err := w.WriteMsg(localH); err != nil {
29 return err
30 }
31 log.Debugf("%p sent my version (%s) to %s", c, localH, rpeer)
32 + log.Event(ctx, "handshake1Sent", lpeer)
33
32 - data, err := CtxReadMsg(ctx, c)
33 - if err != nil {
34 - return err
34 + select {
35 + case <-ctx.Done():
36 + return ctx.Err()
37 + default:
38 }
39
37 - remoteH = new(hspb.Handshake1)
38 - err = proto.Unmarshal(data, remoteH)
39 - if err != nil {
40 - return fmt.Errorf("could not decode remote version: %q", err)
40 + if err := r.ReadMsg(remoteH); err != nil {
41 + return fmt.Errorf("could not receive remote version: %q", err)
42 }
43 log.Debugf("%p received remote version (%s) from %s", c, remoteH, rpeer)
44 + log.Event(ctx, "handshake1Received", lpeer)
45
46 if err := handshake.Handshake1Compatible(localH, remoteH); err != nil {
47 log.Infof("%s (%s) incompatible version with %s (%s)", lpeer, localH, rpeer, remoteH)
@@ -51,36 +53,30 @@ func Handshake1(ctx context.Context, c Conn) error {
53 }
54
55 // Handshake3 exchanges local and remote service information
54 -func Handshake3(ctx context.Context, c Conn) (*handshake.Handshake3Result, error) {
56 +func Handshake3(ctx context.Context, stream ps.Stream, c Conn) (*handshake.Handshake3Result, error) {
57 rpeer := c.RemotePeer()
58 lpeer := c.LocalPeer()
59
58 - // setup + send the message to remote
59 - var remoteH, localH *hspb.Handshake3
60 - localH = handshake.Handshake3Msg(lpeer, c.RemoteMultiaddr())
61 - localB, err := proto.Marshal(localH)
62 - if err != nil {
63 - return nil, err
64 - }
60 + // setup up protobuf io
61 + maxSize := 4096
62 + r := ggprotoio.NewDelimitedReader(stream, maxSize)
63 + w := ggprotoio.NewDelimitedWriter(stream)
64 + localH := handshake.Handshake3Msg(lpeer, c.RemoteMultiaddr())
65 + remoteH := new(hspb.Handshake3)
66
66 - if err := CtxWriteMsg(ctx, c, localB); err != nil {
67 + // setup + send the message to remote
68 + if err := w.WriteMsg(localH); err != nil {
69 return nil, err
70 }
69 - log.Debugf("Handshake1: sent to %s", rpeer)
71 + log.Debugf("Handshake3: sent to %s", rpeer)
72 + log.Event(ctx, "handshake3Sent", lpeer, rpeer)
73
74 // wait + listen for response
72 - remoteB, err := CtxReadMsg(ctx, c)
73 - if err != nil {
74 - return nil, err
75 + if err := r.ReadMsg(remoteH); err != nil {
76 + return nil, fmt.Errorf("Handshake3 could not receive remote msg: %q", err)
77 }
76 -
77 - remoteH = new(hspb.Handshake3)
78 - err = proto.Unmarshal(remoteB, remoteH)
79 - if err != nil {
80 - return nil, fmt.Errorf("Handshake3 could not decode remote msg: %q", err)
81 - }
82 -
83 - log.Debugf("Handshake3 received from %s", rpeer)
78 + log.Debugf("Handshake3: received from %s", rpeer)
79 + log.Event(ctx, "handshake3Received", lpeer, rpeer)
80
81 // actually update our state based on the new knowledge
82 res, err := handshake.Handshake3Update(lpeer, rpeer, remoteH)
net/conn/interface.go
+7 -94
@@ -1,15 +1,13 @@
1 package conn
2
3 import (
4 - "errors"
4 + "io"
5 "net"
6 "time"
7
8 peer "github.com/jbenet/go-ipfs/peer"
9 u "github.com/jbenet/go-ipfs/util"
10 - ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
10
12 - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
11 msgio "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-msgio"
12 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 )
@@ -20,9 +18,6 @@ type Map map[u.Key]Conn
18 // Conn is a generic message-based Peer-to-Peer connection.
19 type Conn interface {
20
23 - // implement ContextCloser too!
24 - ctxc.ContextCloser
25 -
21 // ID is an identifier unique to this connection.
22 ID() string
23
@@ -47,6 +42,7 @@ type Conn interface {
42
43 msgio.Reader
44 msgio.Writer
45 + io.Closer
46 }
47
48 // Dialer is an object that can open connections. We could have a "convenience"
@@ -67,9 +63,12 @@ type Dialer struct {
63 type Listener interface {
64
65 // Accept waits for and returns the next connection to the listener.
70 - Accept() <-chan Conn
66 + Accept() (net.Conn, error)
67 +
68 + // Addr is the local address
69 + Addr() net.Addr
70
72 - // Multiaddr is the identity of the local Peer.
71 + // Multiaddr is the local multiaddr address
72 Multiaddr() ma.Multiaddr
73
74 // LocalPeer is the identity of the local Peer.
@@ -84,89 +83,3 @@ type Listener interface {
83 // Any blocked Accept operations will be unblocked and return errors.
84 Close() error
85 }
87 -
88 -// CtxRead is a function that Reads from a connection while respecting a
89 -// Context. Though it cannot cancel the read per-se (as not all Connections
90 -// implement SetTimeout, and a CancelFunc can't be predicted), at least it
91 -// doesn't hang. The Read will eventually return and the goroutine will exit.
92 -func CtxRead(ctx context.Context, c Conn, buf []byte) (n int, err error) {
93 - done := make(chan struct{})
94 - go func() {
95 - n, err = c.Read(buf)
96 - close(done)
97 - }()
98 -
99 - select {
100 - case <-ctx.Done():
101 - return 0, ctx.Err()
102 -
103 - case <-c.Closing():
104 - return 0, errors.New("remote connection closed")
105 -
106 - case <-done:
107 - return n, err
108 - }
109 -}
110 -
111 -// CtxReadMsg is a function that Reads from a connection while respecting a
112 -// Context. See CtxRead.
113 -func CtxReadMsg(ctx context.Context, c Conn) (msg []byte, err error) {
114 - done := make(chan struct{})
115 - go func() {
116 - msg, err = c.ReadMsg()
117 - close(done)
118 - }()
119 -
120 - select {
121 - case <-ctx.Done():
122 - return msg, ctx.Err()
123 -
124 - case <-c.Closing():
125 - return msg, errors.New("remote connection closed")
126 -
127 - case <-done:
128 - return msg, err
129 - }
130 -}
131 -
132 -// CtxWrite is a function that Writes to a connection while respecting a
133 -// Context. See CtxRead.
134 -func CtxWrite(ctx context.Context, c Conn, buf []byte) (n int, err error) {
135 - done := make(chan struct{})
136 - go func() {
137 - n, err = c.Read(buf)
138 - close(done)
139 - }()
140 -
141 - select {
142 - case <-ctx.Done():
143 - return 0, ctx.Err()
144 -
145 - case <-c.Closing():
146 - return 0, errors.New("remote connection closed")
147 -
148 - case <-done:
149 - return n, err
150 - }
151 -}
152 -
153 -// CtxWriteMsg is a function that Writes to a connection while respecting a
154 -// Context. See CtxRead.
155 -func CtxWriteMsg(ctx context.Context, c Conn, buf []byte) (err error) {
156 - done := make(chan struct{})
157 - go func() {
158 - err = c.WriteMsg(buf)
159 - close(done)
160 - }()
161 -
162 - select {
163 - case <-ctx.Done():
164 - return ctx.Err()
165 -
166 - case <-c.Closing():
167 - return errors.New("remote connection closed")
168 -
169 - case <-done:
170 - return err
171 - }
172 -}
net/conn/listen.go
+47 -81
@@ -2,24 +2,21 @@ package conn
2
3 import (
4 "fmt"
5 + "net"
6
7 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
8 ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
9 manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
10
11 peer "github.com/jbenet/go-ipfs/peer"
11 - ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
12 )
13
14 // listener is an object that can accept connections. It implements Listener
15 type listener struct {
16 - manet.Listener
17 -
18 - // chansize is the size of the internal channels for concurrency
19 - chansize int
16 + notSecure bool
17 + notSecureIMeanIt bool
18
21 - // channel of incoming conections
22 - conns chan Conn
19 + manet.Listener
20
21 // Local multiaddr to listen on
22 maddr ma.Multiaddr
@@ -29,79 +26,49 @@ type listener struct {
26
27 // Peerstore is the set of peers we know about locally
28 peers peer.Peerstore
32 -
33 - // Context for children Conn
34 - ctx context.Context
35 -
36 - // embedded ContextCloser
37 - ctxc.ContextCloser
29 }
30
40 -// disambiguate
31 func (l *listener) Close() error {
42 - return l.ContextCloser.Close()
43 -}
44 -
45 -// close called by ContextCloser.Close
46 -func (l *listener) close() error {
32 log.Infof("listener closing: %s %s", l.local, l.maddr)
33 return l.Listener.Close()
34 }
35
51 -func (l *listener) listen() {
52 - defer l.Children().Done()
53 -
54 - // handle at most chansize concurrent handshakes
55 - sem := make(chan struct{}, l.chansize)
36 +// Accept waits for and returns the next connection to the listener.
37 +// Note that unfortunately this
38 +func (l *listener) Accept() (net.Conn, error) {
39
57 - // handle is a goroutine work function that handles the handshake.
58 - // it's here only so that accepting new connections can happen quickly.
59 - handle := func(maconn manet.Conn) {
60 - defer func() { <-sem }() // release
40 + // listeners dont have contexts. given changes dont make sense here anymore
41 + // note that the parent of listener will Close, which will interrupt all io.
42 + // Contexts and io don't mix.
43 + ctx := context.Background()
44
62 - c, err := newSingleConn(l.ctx, l.local, nil, maconn)
63 - if err != nil {
64 - log.Errorf("Error accepting connection: %v", err)
65 - return
66 - }
45 + maconn, err := l.Listener.Accept()
46 + if err != nil {
47 + return nil, err
48 + }
49
68 - // if insecure:
69 - // l.conns <- c
50 + c, err := newSingleConn(ctx, l.local, nil, maconn)
51 + if err != nil {
52 + return nil, fmt.Errorf("Error accepting connection: %v", err)
53 + }
54
71 - // if secure
72 - sc, err := newSecureConn(l.ctx, c, l.peers)
55 + if l.Secure() {
56 + sc, err := newSecureConn(ctx, c, l.peers)
57 if err != nil {
74 - log.Errorf("Error securing connection: %v", err)
75 - return
58 + return nil, fmt.Errorf("Error securing connection: %v", err)
59 }
77 - l.conns <- sc
60 + return sc, nil
61 }
62
80 - for {
81 - log.Infof("swarm listening on %s -- %v\n", l.Multiaddr(), l.Listener)
82 - maconn, err := l.Listener.Accept()
83 - if err != nil {
84 -
85 - // if closing, we should exit.
86 - select {
87 - case <-l.Closing():
88 - return // done.
89 - default:
90 - }
91 -
92 - log.Errorf("Failed to accept connection: %v", err)
93 - continue
94 - }
63 + return c, nil
64 +}
65
96 - sem <- struct{}{} // acquire
97 - go handle(maconn)
98 - }
66 +func (l *listener) Secure() bool {
67 + return !(l.notSecure && l.notSecureIMeanIt)
68 }
69
101 -// Accept waits for and returns the next connection to the listener.
102 -// Note that unfortunately this
103 -func (l *listener) Accept() <-chan Conn {
104 - return l.conns
70 +func (l *listener) Addr() net.Addr {
71 + return l.Listener.Addr()
72 }
73
74 // Multiaddr is the identity of the local Peer.
@@ -121,6 +88,16 @@ func (l *listener) Peerstore() peer.Peerstore {
88 return l.peers
89 }
90
91 +func (l *listener) Loggable() map[string]interface{} {
92 + return map[string]interface{}{
93 + "listener": map[string]interface{}{
94 + "peer": l.LocalPeer(),
95 + "address": l.Multiaddr(),
96 + "secure": l.Secure(),
97 + },
98 + }
99 +}
100 +
101 // Listen listens on the particular multiaddr, with given peer and peerstore.
102 func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.Peerstore) (Listener, error) {
103
@@ -129,27 +106,16 @@ func Listen(ctx context.Context, addr ma.Multiaddr, local peer.Peer, peers peer.
106 return nil, fmt.Errorf("Failed to listen on %s: %s", addr, err)
107 }
108
132 - // todo make this a variable
133 - chansize := 10
134 -
109 l := &listener{
136 - Listener: ml,
137 - maddr: addr,
138 - peers: peers,
139 - local: local,
140 - conns: make(chan Conn, chansize),
141 - chansize: chansize,
142 - ctx: ctx,
110 + Listener: ml,
111 + maddr: addr,
112 + peers: peers,
113 + local: local,
114 + notSecure: false,
115 + notSecureIMeanIt: false,
116 }
117
145 - // need a separate context to use for the context closer.
146 - // This is because the parent context will be given to all connections too,
147 - // and if we close the listener, the connections shouldn't share the fate.
148 - ctx2, _ := context.WithCancel(ctx)
149 - l.ContextCloser = ctxc.NewContextCloser(ctx2, l.close)
150 -
151 - l.Children().Add(1)
152 - go l.listen()
153 -
118 + log.Infof("swarm listening on %s\n", l.Multiaddr())
119 + log.Event(ctx, "swarmListen", l)
120 return l, nil
121 }
net/conn/multiconn.go deleted
-351
@@ -1,351 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "errors"
5 - "fmt"
6 - "net"
7 - "sync"
8 - "time"
9 -
10 - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
11 - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
12 -
13 - peer "github.com/jbenet/go-ipfs/peer"
14 - u "github.com/jbenet/go-ipfs/util"
15 - ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
16 -)
17 -
18 -// MultiConnMap is for shorthand
19 -type MultiConnMap map[u.Key]*MultiConn
20 -
21 -// MultiConn represents a single connection to another Peer (IPFS Node).
22 -type MultiConn struct {
23 -
24 - // connections, mapped by a string, which uniquely identifies the connection.
25 - // this string is: /addr1/peer1/addr2/peer2 (peers ordered lexicographically)
26 - conns map[string]Conn
27 -
28 - local peer.Peer
29 - remote peer.Peer
30 -
31 - // fan-in
32 - fanIn chan []byte
33 -
34 - // for adding/removing connections concurrently
35 - sync.RWMutex
36 - ctxc.ContextCloser
37 -}
38 -
39 -// NewMultiConn constructs a new connection
40 -func NewMultiConn(ctx context.Context, local, remote peer.Peer, conns []Conn) (*MultiConn, error) {
41 -
42 - c := &MultiConn{
43 - local: local,
44 - remote: remote,
45 - conns: map[string]Conn{},
46 - fanIn: make(chan []byte),
47 - }
48 -
49 - // must happen before Adds / fanOut
50 - c.ContextCloser = ctxc.NewContextCloser(ctx, c.close)
51 -
52 - if conns != nil && len(conns) > 0 {
53 - c.Add(conns...)
54 - }
55 -
56 - return c, nil
57 -}
58 -
59 -// Add adds given Conn instances to multiconn.
60 -func (c *MultiConn) Add(conns ...Conn) {
61 - c.Lock()
62 - defer c.Unlock()
63 -
64 - for _, c2 := range conns {
65 - log.Debugf("MultiConn: adding %s", c2)
66 - if c.LocalPeer() != c2.LocalPeer() || c.RemotePeer() != c2.RemotePeer() {
67 - log.Error(c2)
68 - c.Unlock() // ok to unlock (to log). panicing.
69 - log.Error(c)
70 - // log.Errorf("c.LocalPeer: %s %p", c.LocalPeer(), c.LocalPeer())
71 - // log.Errorf("c2.LocalPeer: %s %p", c2.LocalPeer(), c2.LocalPeer())
72 - // log.Errorf("c.RemotePeer: %s %p", c.RemotePeer(), c.RemotePeer())
73 - // log.Errorf("c2.RemotePeer: %s %p", c2.RemotePeer(), c2.RemotePeer())
74 - c.Lock() // gotta relock to avoid lock panic from deferring.
75 - panic("connection addresses mismatch")
76 - }
77 -
78 - c.conns[c2.ID()] = c2
79 - c.Children().Add(1)
80 - c2.Children().Add(1) // yep, on the child too.
81 - go c.fanInSingle(c2)
82 - log.Debugf("MultiConn: added %s", c2)
83 - }
84 -}
85 -
86 -// Remove removes given Conn instances from multiconn.
87 -func (c *MultiConn) Remove(conns ...Conn) {
88 -
89 - // first remove them to avoid sending any more messages through it.
90 - {
91 - c.Lock()
92 - for _, c1 := range conns {
93 - c2, found := c.conns[c1.ID()]
94 - if !found {
95 - panic("Conn not in MultiConn")
96 - }
97 - if c1 != c2 {
98 - panic("different Conn objects for same id.")
99 - }
100 -
101 - delete(c.conns, c2.ID())
102 - }
103 - c.Unlock()
104 - }
105 -
106 - // close all in parallel, but wait for all to be done closing.
107 - CloseConns(conns...)
108 -}
109 -
110 -// CloseConns closes multiple connections in parallel, and waits for all
111 -// to finish closing.
112 -func CloseConns(conns ...Conn) {
113 - var wg sync.WaitGroup
114 - for _, child := range conns {
115 -
116 - select {
117 - case <-child.Closed(): // if already closed, continue
118 - continue
119 - default:
120 - }
121 -
122 - wg.Add(1)
123 - go func(child Conn) {
124 - child.Close()
125 - wg.Done()
126 - }(child)
127 - }
128 - wg.Wait()
129 -}
130 -
131 -// fanInSingle Reads from a connection, and sends to the fanIn.
132 -// waits for child to close and reclaims resources
133 -func (c *MultiConn) fanInSingle(child Conn) {
134 - // cleanup all data associated with this child Connection.
135 - defer func() {
136 - log.Debugf("closing: %s", child)
137 -
138 - // in case it still is in the map, remove it.
139 - c.Lock()
140 - delete(c.conns, child.ID())
141 - connLen := len(c.conns)
142 - c.Unlock()
143 -
144 - c.Children().Done()
145 - child.Children().Done()
146 -
147 - if connLen == 0 {
148 - c.Close() // close self if all underlying children are gone?
149 - }
150 - }()
151 -
152 - for {
153 - msg, err := child.ReadMsg()
154 - if err != nil {
155 - log.Warning(err)
156 - return
157 - }
158 -
159 - select {
160 - case <-c.Closing(): // multiconn closing
161 - return
162 -
163 - case <-child.Closing(): // child closing
164 - return
165 -
166 - case c.fanIn <- msg:
167 - }
168 - }
169 -}
170 -
171 -// close is the internal close function, called by ContextCloser.Close
172 -func (c *MultiConn) close() error {
173 - log.Debugf("%s closing Conn with %s", c.local, c.remote)
174 -
175 - // get connections
176 - c.RLock()
177 - conns := make([]Conn, 0, len(c.conns))
178 - for _, c := range c.conns {
179 - conns = append(conns, c)
180 - }
181 - c.RUnlock()
182 -
183 - // close underlying connections
184 - CloseConns(conns...)
185 - close(c.fanIn)
186 - return nil
187 -}
188 -
189 -// BestConn is the best connection in this MultiConn
190 -func (c *MultiConn) BestConn() Conn {
191 - c.RLock()
192 - defer c.RUnlock()
193 -
194 - var id1 string
195 - var c1 Conn
196 - for id2, c2 := range c.conns {
197 - if id1 == "" || id1 < id2 {
198 - id1 = id2
199 - c1 = c2
200 - }
201 - }
202 - return c1
203 -}
204 -
205 -// ID is an identifier unique to this connection.
206 -// In MultiConn, this is all the children IDs XORed together.
207 -func (c *MultiConn) ID() string {
208 - c.RLock()
209 - defer c.RUnlock()
210 -
211 - ids := []byte(nil)
212 - for i := range c.conns {
213 - if ids == nil {
214 - ids = []byte(i)
215 - } else {
216 - ids = u.XOR(ids, []byte(i))
217 - }
218 - }
219 -
220 - return string(ids)
221 -}
222 -
223 -func (c *MultiConn) getConns() []Conn {
224 - c.RLock()
225 - defer c.RUnlock()
226 - var conns []Conn
227 - for _, c := range c.conns {
228 - conns = append(conns, c)
229 - }
230 - return conns
231 -}
232 -
233 -func (c *MultiConn) String() string {
234 - return String(c, "MultiConn")
235 -}
236 -
237 -func (c *MultiConn) LocalAddr() net.Addr {
238 - bc := c.BestConn()
239 - if bc == nil {
240 - return nil
241 - }
242 - return bc.LocalAddr()
243 -}
244 -
245 -func (c *MultiConn) RemoteAddr() net.Addr {
246 - bc := c.BestConn()
247 - if bc == nil {
248 - return nil
249 - }
250 - return bc.RemoteAddr()
251 -}
252 -
253 -func (c *MultiConn) SetDeadline(t time.Time) error {
254 - bc := c.BestConn()
255 - if bc == nil {
256 - return nil
257 - }
258 - return bc.SetDeadline(t)
259 -}
260 -
261 -func (c *MultiConn) SetReadDeadline(t time.Time) error {
262 - bc := c.BestConn()
263 - if bc == nil {
264 - return nil
265 - }
266 - return bc.SetReadDeadline(t)
267 -}
268 -
269 -func (c *MultiConn) SetWriteDeadline(t time.Time) error {
270 - bc := c.BestConn()
271 - if bc == nil {
272 - return nil
273 - }
274 - return bc.SetWriteDeadline(t)
275 -}
276 -
277 -// LocalMultiaddr is the Multiaddr on this side
278 -func (c *MultiConn) LocalMultiaddr() ma.Multiaddr {
279 - bc := c.BestConn()
280 - if bc == nil {
281 - return nil
282 - }
283 - return bc.LocalMultiaddr()
284 -}
285 -
286 -// RemoteMultiaddr is the Multiaddr on the remote side
287 -func (c *MultiConn) RemoteMultiaddr() ma.Multiaddr {
288 - bc := c.BestConn()
289 - if bc == nil {
290 - return nil
291 - }
292 - return bc.RemoteMultiaddr()
293 -}
294 -
295 -// LocalPeer is the Peer on this side
296 -func (c *MultiConn) LocalPeer() peer.Peer {
297 - return c.local
298 -}
299 -
300 -// RemotePeer is the Peer on the remote side
301 -func (c *MultiConn) RemotePeer() peer.Peer {
302 - return c.remote
303 -}
304 -
305 -// Read reads data, net.Conn style
306 -func (c *MultiConn) Read(buf []byte) (int, error) {
307 - return 0, errors.New("multiconn does not support Read. use ReadMsg")
308 -}
309 -
310 -// Write writes data, net.Conn style
311 -func (c *MultiConn) Write(buf []byte) (int, error) {
312 - bc := c.BestConn()
313 - if bc == nil {
314 - return 0, errors.New("no best connection")
315 - }
316 - return bc.Write(buf)
317 -}
318 -
319 -func (c *MultiConn) NextMsgLen() (int, error) {
320 - bc := c.BestConn()
321 - if bc == nil {
322 - return 0, errors.New("no best connection")
323 - }
324 - return bc.NextMsgLen()
325 -}
326 -
327 -// ReadMsg reads data, net.Conn style
328 -func (c *MultiConn) ReadMsg() ([]byte, error) {
329 - next, ok := <-c.fanIn
330 - if !ok {
331 - return nil, fmt.Errorf("multiconn closed")
332 - }
333 - return next, nil
334 -}
335 -
336 -// WriteMsg writes data, net.Conn style
337 -func (c *MultiConn) WriteMsg(buf []byte) error {
338 - bc := c.BestConn()
339 - if bc == nil {
340 - return errors.New("no best connection")
341 - }
342 - return bc.WriteMsg(buf)
343 -}
344 -
345 -// ReleaseMsg releases a buffer
346 -func (c *MultiConn) ReleaseMsg(m []byte) {
347 - // here, we dont know where it came from. hm.
348 - for _, c := range c.getConns() {
349 - c.ReleaseMsg(m)
350 - }
351 -}
net/conn/multiconn_test.go deleted
-338
@@ -1,338 +0,0 @@
1 -package conn
2 -
3 -import (
4 - "fmt"
5 - "sync"
6 - "testing"
7 - "time"
8 -
9 - peer "github.com/jbenet/go-ipfs/peer"
10 -
11 - context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
12 - ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
13 -)
14 -
15 -func tcpAddr(t *testing.T, port int) ma.Multiaddr {
16 - tcp, err := ma.NewMultiaddr(tcpAddrString(port))
17 - if err != nil {
18 - t.Fatal(err)
19 - }
20 - return tcp
21 -}
22 -
23 -func tcpAddrString(port int) string {
24 - return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)
25 -}
26 -
27 -type msg struct {
28 - sent bool
29 - received bool
30 - payload string
31 -}
32 -
33 -func (m *msg) Sent(t *testing.T) {
34 - if m.sent {
35 - t.Fatal("sent msg at incorrect state:", m)
36 - }
37 - m.sent = true
38 -}
39 -
40 -func (m *msg) Received(t *testing.T) {
41 - if m.received {
42 - t.Fatal("received msg at incorrect state:", m)
43 - }
44 - m.received = true
45 -}
46 -
47 -type msgMap struct {
48 - sent int
49 - recv int
50 - msgs map[string]*msg
51 -}
52 -
53 -func (mm *msgMap) Sent(t *testing.T, payload string) {
54 - mm.msgs[payload].Sent(t)
55 - mm.sent++
56 -}
57 -
58 -func (mm *msgMap) Received(t *testing.T, payload string) {
59 - mm.msgs[payload].Received(t)
60 - mm.recv++
61 -}
62 -
63 -func (mm *msgMap) CheckDone(t *testing.T) {
64 - if mm.sent != len(mm.msgs) {
65 - t.Fatal("failed to send all msgs", mm.sent, len(mm.msgs))
66 - }
67 -
68 - if mm.sent != len(mm.msgs) {
69 - t.Fatal("failed to send all msgs", mm.sent, len(mm.msgs))
70 - }
71 -}
72 -
73 -func genMessages(num int, tag string) *msgMap {
74 - msgs := &msgMap{msgs: map[string]*msg{}}
75 - for i := 0; i < num; i++ {
76 - s := fmt.Sprintf("Message #%d -- %s", i, tag)
77 - msgs.msgs[s] = &msg{payload: s}
78 - }
79 - return msgs
80 -}
81 -
82 -func setupMultiConns(t *testing.T, ctx context.Context) (a, b *MultiConn) {
83 -
84 - log.Info("Setting up peers")
85 - p1, err := setupPeer(tcpAddrString(11000))
86 - if err != nil {
87 - t.Fatal("error setting up peer", err)
88 - }
89 -
90 - p2, err := setupPeer(tcpAddrString(12000))
91 - if err != nil {
92 - t.Fatal("error setting up peer", err)
93 - }
94 -
95 - // peerstores
96 - p1ps := peer.NewPeerstore()
97 - p2ps := peer.NewPeerstore()
98 - p1ps.Add(p1)
99 - p2ps.Add(p2)
100 -
101 - // listeners
102 - listen := func(addr ma.Multiaddr, p peer.Peer, ps peer.Peerstore) Listener {
103 - l, err := Listen(ctx, addr, p, ps)
104 - if err != nil {
105 - t.Fatal(err)
106 - }
107 - return l
108 - }
109 -
110 - log.Info("Setting up listeners")
111 - p1l := listen(p1.Addresses()[0], p1, p1ps)
112 - p2l := listen(p2.Addresses()[0], p2, p2ps)
113 -
114 - // dialers
115 - p1d := &Dialer{Peerstore: p1ps, LocalPeer: p1}
116 - p2d := &Dialer{Peerstore: p2ps, LocalPeer: p2}
117 -
118 - dial := func(d *Dialer, dst peer.Peer) <-chan Conn {
119 - cc := make(chan Conn)
120 - go func() {
121 - c, err := d.Dial(ctx, "tcp", dst)
122 - if err != nil {
123 - t.Fatal("error dialing peer", err)
124 - }
125 - cc <- c
126 - }()
127 - return cc
128 - }
129 -
130 - // connect simultaneously
131 - log.Info("Connecting...")
132 - p1dc := dial(p1d, p2)
133 - p2dc := dial(p2d, p1)
134 -
135 - c12a := <-p1l.Accept()
136 - c12b := <-p1dc
137 - c21a := <-p2l.Accept()
138 - c21b := <-p2dc
139 -
140 - log.Info("Ok, making multiconns")
141 - c1, err := NewMultiConn(ctx, p1, p2, []Conn{c12a, c12b})
142 - if err != nil {
143 - t.Fatal(err)
144 - }
145 -
146 - c2, err := NewMultiConn(ctx, p2, p1, []Conn{c21a, c21b})
147 - if err != nil {
148 - t.Fatal(err)
149 - }
150 -
151 - p1l.Close()
152 - p2l.Close()
153 -
154 - log.Info("did you make multiconns?")
155 - return c1, c2
156 -}
157 -
158 -func TestMulticonnSend(t *testing.T) {
159 - if testing.Short() {
160 - t.SkipNow()
161 - }
162 -
163 - log.Info("TestMulticonnSend")
164 - ctx := context.Background()
165 - ctxC, cancel := context.WithCancel(ctx)
166 -
167 - c1, c2 := setupMultiConns(t, ctx)
168 -
169 - log.Info("gen msgs")
170 - num := 100
171 - msgsFrom1 := genMessages(num, "from p1 to p2")
172 - msgsFrom2 := genMessages(num, "from p2 to p1")
173 -
174 - var wg sync.WaitGroup
175 -
176 - send := func(c *MultiConn, msgs *msgMap) {
177 - defer wg.Done()
178 -
179 - for _, m := range msgs.msgs {
180 - log.Info("send: %s", m.payload)
181 - c.WriteMsg([]byte(m.payload))
182 - msgs.Sent(t, m.payload)
183 - <-time.After(time.Microsecond * 10)
184 - }
185 - }
186 -
187 - recv := func(ctx context.Context, c *MultiConn, msgs *msgMap) {
188 - defer wg.Done()
189 -
190 - for {
191 - select {
192 - default:
193 - case <-ctx.Done():
194 - return
195 - }
196 -
197 - payload, err := c.ReadMsg()
198 - if err != nil {
199 - panic(err)
200 - }
201 -
202 - msgs.Received(t, string(payload))
203 - log.Info("recv: %s", payload)
204 - if msgs.recv == len(msgs.msgs) {
205 - return
206 - }
207 - }
208 -
209 - }
210 -
211 - log.Info("msg send + recv")
212 -
213 - wg.Add(4)
214 - go send(c1, msgsFrom1)
215 - go send(c2, msgsFrom2)
216 - go recv(ctxC, c1, msgsFrom2)
217 - go recv(ctxC, c2, msgsFrom1)
218 - wg.Wait()
219 - cancel()
220 - c1.Close()
221 - c2.Close()
222 -
223 - msgsFrom1.CheckDone(t)
224 - msgsFrom2.CheckDone(t)
225 - <-time.After(100 * time.Millisecond)
226 -}
227 -
228 -func TestMulticonnSendUnderlying(t *testing.T) {
229 - if testing.Short() {
230 - t.SkipNow()
231 - }
232 -
233 - log.Info("TestMulticonnSendUnderlying")
234 - ctx := context.Background()
235 - ctxC, cancel := context.WithCancel(ctx)
236 -
237 - c1, c2 := setupMultiConns(t, ctx)
238 -
239 - log.Info("gen msgs")
240 - num := 100
241 - msgsFrom1 := genMessages(num, "from p1 to p2")
242 - msgsFrom2 := genMessages(num, "from p2 to p1")
243 -
244 - var wg sync.WaitGroup
245 -
246 - send := func(c *MultiConn, msgs *msgMap) {
247 - defer wg.Done()
248 -
249 - conns := make([]Conn, 0, len(c.conns))
250 - for _, c1 := range c.conns {
251 - conns = append(conns, c1)
252 - }
253 -
254 - i := 0
255 - for _, m := range msgs.msgs {
256 - log.Info("send: %s", m.payload)
257 - switch i % 3 {
258 - case 0:
259 - conns[0].WriteMsg([]byte(m.payload))
260 - case 1:
261 - conns[1].WriteMsg([]byte(m.payload))
262 - case 2:
263 - c.WriteMsg([]byte(m.payload))
264 - }
265 - msgs.Sent(t, m.payload)
266 - <-time.After(time.Microsecond * 10)
267 - i++
268 - }
269 - }
270 -
271 - recv := func(ctx context.Context, c *MultiConn, msgs *msgMap) {
272 - defer wg.Done()
273 -
274 - for {
275 - select {
276 - default:
277 - case <-ctx.Done():
278 - return
279 - }
280 -
281 - payload, err := c.ReadMsg()
282 - if err != nil {
283 - panic(err)
284 - }
285 -
286 - msgs.Received(t, string(payload))
287 - log.Info("recv: %s", payload)
288 - if msgs.recv == len(msgs.msgs) {
289 - return
290 - }
291 - }
292 -
293 - }
294 -
295 - log.Info("msg send + recv")
296 -
297 - wg.Add(4)
298 - go send(c1, msgsFrom1)
299 - go send(c2, msgsFrom2)
300 - go recv(ctxC, c1, msgsFrom2)
301 - go recv(ctxC, c2, msgsFrom1)
302 - wg.Wait()
303 - cancel()
304 - c1.Close()
305 - c2.Close()
306 -
307 - msgsFrom1.CheckDone(t)
308 - msgsFrom2.CheckDone(t)
309 -}
310 -
311 -func TestMulticonnClose(t *testing.T) {
312 - // t.Skip("fooo")
313 -
314 - log.Info("TestMulticonnSendUnderlying")
315 - ctx := context.Background()
316 - c1, c2 := setupMultiConns(t, ctx)
317 -
318 - for _, c := range c1.getConns() {
319 - c.Close()
320 - }
321 -
322 - for _, c := range c2.getConns() {
323 - c.Close()
324 - }
325 -
326 - timeout := time.After(100 * time.Millisecond)
327 - select {
328 - case <-c1.Closed():
329 - case <-timeout:
330 - t.Fatal("timeout")
331 - }
332 -
333 - select {
334 - case <-c2.Closed():
335 - case <-timeout:
336 - t.Fatal("timeout")
337 - }
338 -}
net/conn/secure_conn.go
+1 -6
@@ -10,7 +10,6 @@ import (
10
11 secio "github.com/jbenet/go-ipfs/crypto/secio"
12 peer "github.com/jbenet/go-ipfs/peer"
13 - ctxc "github.com/jbenet/go-ipfs/util/ctxcloser"
13 )
14
15 // secureConn wraps another Conn object with an encrypted channel.
@@ -24,8 +23,6 @@ type secureConn struct {
23
24 // secure Session
25 session secio.Session
27 -
28 - ctxc.ContextCloser
26 }
27
28 // newConn constructs a new connection
@@ -43,13 +40,11 @@ func newSecureConn(ctx context.Context, insecure Conn, peers peer.Peerstore) (Co
40 session: session,
41 secure: session.ReadWriter(),
42 }
46 - conn.ContextCloser = ctxc.NewContextCloser(ctx, conn.close)
43 log.Debugf("newSecureConn: %v to %v handshake success!", conn.LocalPeer(), conn.RemotePeer())
44 return conn, nil
45 }
46
51 -// close is called by ContextCloser
52 -func (c *secureConn) close() error {
47 +func (c *secureConn) Close() error {
48 if err := c.secure.Close(); err != nil {
49 c.insecure.Close()
50 return err
net/conn/secure_conn_test.go
+41 -63
@@ -15,93 +15,65 @@ import (
15 context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
16 )
17
18 -func setupSecureConn(t *testing.T, c Conn) Conn {
18 +func setupSecureConn(t *testing.T, ctx context.Context, c Conn) (Conn, error) {
19 c, ok := c.(*secureConn)
20 if ok {
21 - return c
21 + return c, nil
22 }
23
24 // shouldn't happen, because dial + listen already return secure conns.
25 - s, err := newSecureConn(c.Context(), c, peer.NewPeerstore())
25 + s, err := newSecureConn(ctx, c, peer.NewPeerstore())
26 if err != nil {
27 - t.Fatal(err)
27 + return nil, err
28 }
29 - return s
29 + return s, nil
30 }
31
32 func TestSecureClose(t *testing.T) {
33 // t.Skip("Skipping in favor of another test")
34
35 - ctx, cancel := context.WithCancel(context.Background())
35 + ctx := context.Background()
36 c1, c2 := setupConn(t, ctx, "/ip4/127.0.0.1/tcp/6634", "/ip4/127.0.0.1/tcp/6645")
37
38 - c1 = setupSecureConn(t, c1)
39 - c2 = setupSecureConn(t, c2)
40 -
41 - select {
42 - case <-c1.Closed():
43 - t.Fatal("done before close")
44 - case <-c2.Closed():
45 - t.Fatal("done before close")
46 - default:
38 + c1, err1 := setupSecureConn(t, ctx, c1)
39 + c2, err2 := setupSecureConn(t, ctx, c2)
40 + if err1 != nil {
41 + t.Fatal(err1)
42 }
48 -
49 - c1.Close()
50 -
51 - select {
52 - case <-c1.Closed():
53 - default:
54 - t.Fatal("not done after close")
43 + if err2 != nil {
44 + t.Fatal(err2)
45 }
46
57 - c2.Close()
47 + testOneSendRecv(t, c1, c2)
48 + testOneSendRecv(t, c2, c1)
49
59 - select {
60 - case <-c2.Closed():
61 - default:
62 - t.Fatal("not done after close")
63 - }
50 + c1.Close()
51 +
52 + testNotOneSendRecv(t, c1, c2)
53 + testNotOneSendRecv(t, c2, c1)
54
65 - cancel() // close the listener :P
55 }
56
68 -func TestSecureCancel(t *testing.T) {
57 +func TestSecureCancelHandshake(t *testing.T) {
58 // t.Skip("Skipping in favor of another test")
59
71 - ctx, cancel := context.WithCancel(context.Background())
60 + ctx := context.Background()
61 c1, c2 := setupConn(t, ctx, "/ip4/127.0.0.1/tcp/6634", "/ip4/127.0.0.1/tcp/6645")
62
74 - c1 = setupSecureConn(t, c1)
75 - c2 = setupSecureConn(t, c2)
76 -
77 - select {
78 - case <-c1.Closed():
79 - t.Fatal("done before close")
80 - case <-c2.Closed():
81 - t.Fatal("done before close")
82 - default:
83 - }
84 -
85 - c1.Close()
86 - c2.Close()
87 - cancel() // listener
88 -
89 - // wait to ensure other goroutines run and close things.
90 - <-time.After(time.Microsecond * 10)
91 - // test that cancel called Close.
92 -
93 - select {
94 - case <-c1.Closed():
95 - default:
96 - t.Fatal("not done after cancel")
97 - }
98 -
99 - select {
100 - case <-c2.Closed():
101 - default:
102 - t.Fatal("not done after cancel")
103 - }
63 + done := make(chan struct{})
64 + go func() {
65 + _, err1 := setupSecureConn(t, ctx, c1)
66 + _, err2 := setupSecureConn(t, ctx, c2)
67 + if err1 == nil {
68 + t.Fatal(err1)
69 + }
70 + if err2 == nil {
71 + t.Fatal(err2)
72 + }
73 + done <- struct{}{}
74 + }()
75
76 + <-done
77 }
78
79 func TestSecureCloseLeak(t *testing.T) {
@@ -122,8 +94,14 @@ func TestSecureCloseLeak(t *testing.T) {
94 ctx, cancel := context.WithCancel(context.Background())
95 c1, c2 := setupConn(t, ctx, "/ip4/127.0.0.1/tcp/"+a1, "/ip4/127.0.0.1/tcp/"+a2)
96
125 - c1 = setupSecureConn(t, c1)
126 - c2 = setupSecureConn(t, c2)
97 + c1, err1 := setupSecureConn(t, ctx, c1)
98 + c2, err2 := setupSecureConn(t, ctx, c2)
99 + if err1 != nil {
100 + t.Fatal(err1)
101 + }
102 + if err2 != nil {
103 + t.Fatal(err2)
104 + }
105
106 for i := 0; i < num; i++ {
107 b1 := []byte("beep")
util/multierr/multierr.go
-3
@@ -23,8 +23,5 @@ func (e *Error) Error() string {
23 }
24
25 func New(errs ...error) *Error {
26 - if len(errs) == 0 {
27 - return nil
28 - }
26 return &Error{errs}
27 }