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
}