Commit 4525269c authored by Juan Batiz-Benet's avatar Juan Batiz-Benet

p2p/net/conn/listener: ignore certain errors

This should handle early breakages, where a failing connection
would take out the listener entirely.

There are probably other errors we should be handling here,
like secure connection failures.
parent 387c0508
package conn
import (
"fmt"
"io"
"net"
"strings"
"testing"
"time"
......@@ -103,6 +105,9 @@ func testDialer(t *testing.T, secure bool) {
if !secure {
key1 = nil
key2 = nil
t.Log("testing insecurely")
} else {
t.Log("testing securely")
}
ctx, cancel := context.WithCancel(context.Background())
......@@ -164,3 +169,89 @@ func TestDialerSecure(t *testing.T) {
// t.Skip("Skipping in favor of another test")
testDialer(t, true)
}
func testDialerCloseEarly(t *testing.T, secure bool) {
// t.Skip("Skipping in favor of another test")
p1 := tu.RandPeerNetParamsOrFatal(t)
p2 := tu.RandPeerNetParamsOrFatal(t)
key1 := p1.PrivKey
if !secure {
key1 = nil
t.Log("testing insecurely")
} else {
t.Log("testing securely")
}
ctx, cancel := context.WithCancel(context.Background())
l1, err := Listen(ctx, p1.Addr, p1.ID, key1)
if err != nil {
t.Fatal(err)
}
p1.Addr = l1.Multiaddr() // Addr has been determined by kernel.
// lol nesting
d2 := &Dialer{
LocalPeer: p2.ID,
// PrivateKey: key2, -- dont give it key. we'll just close the conn.
}
errs := make(chan error, 100)
done := make(chan struct{}, 1)
gotclosed := make(chan struct{}, 1)
go func() {
defer func() { done <- struct{}{} }()
_, err := l1.Accept()
if err != nil {
if strings.Contains(err.Error(), "closed") {
gotclosed <- struct{}{}
return
}
errs <- err
}
errs <- fmt.Errorf("got conn")
}()
c, err := d2.Dial(ctx, p1.Addr, p1.ID)
if err != nil {
errs <- err
}
c.Close() // close it early.
readerrs := func() {
for {
select {
case e := <-errs:
t.Error(e)
default:
return
}
}
}
readerrs()
l1.Close()
<-done
cancel()
readerrs()
close(errs)
select {
case <-gotclosed:
default:
t.Error("did not get closed")
}
}
// we dont do a handshake with singleConn, so cant "close early."
// func TestDialerCloseEarlyInsecure(t *testing.T) {
// // t.Skip("Skipping in favor of another test")
// testDialerCloseEarly(t, false)
// }
func TestDialerCloseEarlySecure(t *testing.T) {
// t.Skip("Skipping in favor of another test")
testDialerCloseEarly(t, true)
}
......@@ -2,13 +2,14 @@ package conn
import (
"fmt"
"io"
"net"
context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context"
ctxgroup "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
ma "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr"
manet "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multiaddr-net"
tec "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-temp-err-catcher"
ic "github.com/jbenet/go-ipfs/p2p/crypto"
peer "github.com/jbenet/go-ipfs/p2p/peer"
)
......@@ -46,25 +47,53 @@ func (l *listener) Accept() (net.Conn, error) {
// Contexts and io don't mix.
ctx := context.Background()
maconn, err := l.Listener.Accept()
if err != nil {
return nil, err
var catcher tec.TempErrCatcher
catcher.IsTemp = func(e error) bool {
// ignore connection breakages up to this point. but log them
if e == io.EOF {
log.Debugf("listener ignoring conn with EOF: %s", e)
return true
}
te, ok := e.(tec.Temporary)
if ok {
log.Debugf("listener ignoring conn with temporary err: %s", e)
return te.Temporary()
}
return false
}
c, err := newSingleConn(ctx, l.local, "", maconn)
if err != nil {
return nil, fmt.Errorf("Error accepting connection: %v", err)
}
if l.privk == nil {
log.Warning("listener %s listening INSECURELY!", l)
return c, nil
}
sc, err := newSecureConn(ctx, l.privk, c)
if err != nil {
return nil, fmt.Errorf("Error securing connection: %v", err)
for {
maconn, err := l.Listener.Accept()
if err != nil {
if catcher.IsTemporary(err) {
continue
}
return nil, err
}
c, err := newSingleConn(ctx, l.local, "", maconn)
if err != nil {
if catcher.IsTemporary(err) {
continue
}
return nil, err
}
if l.privk == nil {
log.Warning("listener %s listening INSECURELY!", l)
return c, nil
}
sc, err := newSecureConn(ctx, l.privk, c)
if err != nil {
if catcher.IsTemporary(err) {
continue
}
return nil, err
}
return sc, nil
}
return sc, nil
}
func (l *listener) Addr() net.Addr {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment