From 26275ba66c54486fdc28bf75c908282b05343ee1 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 2 Mar 2017 22:00:50 -0500 Subject: [PATCH] dial seeds error handling --- .gitignore | 16 ++++++++++++++++ addrbook_test.go | 15 +++++++++------ listener.go | 6 +++++- netaddress.go | 14 +++++++++----- pex_reactor.go | 8 +++++++- switch.go | 46 ++++++++++++++++++++++++++++++++++++++++++---- switch_test.go | 10 ++++++++++ 7 files changed, 98 insertions(+), 17 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c4694b3e1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*.swp +*.swo +.bak +*.bak +.DS_Store +build/* +rpc/test/.tendermint +.debora +.tendermint +remote_dump +.revision +vendor +.vagrant +test/p2p/data/ +test/logs +.glide diff --git a/addrbook_test.go b/addrbook_test.go index d5a83da88..5eb7c0b6a 100644 --- a/addrbook_test.go +++ b/addrbook_test.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "math/rand" "testing" + + "github.com/stretchr/testify/assert" ) const addrBookStrict = true @@ -38,7 +40,7 @@ func TestEmpty(t *testing.T) { } } -func randIPv4Address() *NetAddress { +func randIPv4Address(t *testing.T) *NetAddress { for { ip := fmt.Sprintf("%v.%v.%v.%v", rand.Intn(254)+1, @@ -47,7 +49,8 @@ func randIPv4Address() *NetAddress { rand.Intn(255), ) port := rand.Intn(65535-1) + 1 - addr := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) + addr, err := NewNetAddressString(fmt.Sprintf("%v:%v", ip, port)) + assert.Nil(t, err, "error generating rand network address") if addr.Routable() { return addr } @@ -64,8 +67,8 @@ func TestSaveAddresses(t *testing.T) { src *NetAddress }{} for i := 0; i < 100; i++ { - addr := randIPv4Address() - src := randIPv4Address() + addr := randIPv4Address(t) + src := randIPv4Address(t) randAddrs = append(randAddrs, struct { addr *NetAddress src *NetAddress @@ -118,8 +121,8 @@ func TestPromoteToOld(t *testing.T) { src *NetAddress }{} for i := 0; i < 100; i++ { - addr := randIPv4Address() - src := randIPv4Address() + addr := randIPv4Address(t) + src := randIPv4Address(t) randAddrs = append(randAddrs, struct { addr *NetAddress src *NetAddress diff --git a/listener.go b/listener.go index 1d7fb9569..962c2b14c 100644 --- a/listener.go +++ b/listener.go @@ -70,7 +70,11 @@ func NewDefaultListener(protocol string, lAddr string, skipUPNP bool) Listener { log.Info("Local listener", "ip", listenerIP, "port", listenerPort) // Determine internal address... - var intAddr *NetAddress = NewNetAddressString(lAddr) + var intAddr *NetAddress + intAddr, err = NewNetAddressString(lAddr) + if err != nil { + PanicCrisis(err) + } // Determine external address... var extAddr *NetAddress diff --git a/netaddress.go b/netaddress.go index 34dc5cafb..331dc44d9 100644 --- a/netaddress.go +++ b/netaddress.go @@ -34,27 +34,31 @@ func NewNetAddress(addr net.Addr) *NetAddress { } // Also resolves the host if host is not an IP. -func NewNetAddressString(addr string) *NetAddress { +func NewNetAddressString(addr string) (*NetAddress, error) { + host, portStr, err := net.SplitHostPort(addr) if err != nil { - PanicSanity(err) + return nil, err } + ip := net.ParseIP(host) if ip == nil { if len(host) > 0 { ips, err := net.LookupIP(host) if err != nil { - PanicSanity(err) + return nil, err } ip = ips[0] } } + port, err := strconv.ParseUint(portStr, 10, 16) if err != nil { - PanicSanity(err) + return nil, err } + na := NewNetAddressIPPort(ip, uint16(port)) - return na + return na, nil } func NewNetAddressIPPort(ip net.IP, port uint16) *NetAddress { diff --git a/pex_reactor.go b/pex_reactor.go index d7ccc7613..536da3a0a 100644 --- a/pex_reactor.go +++ b/pex_reactor.go @@ -64,7 +64,12 @@ func (pexR *PEXReactor) GetChannels() []*ChannelDescriptor { // Implements Reactor func (pexR *PEXReactor) AddPeer(peer *Peer) { // Add the peer to the address book - netAddr := NewNetAddressString(peer.ListenAddr) + netAddr, err := NewNetAddressString(peer.ListenAddr) + if err != nil { + log.Warn("Error decoding message", "error", err) + return + } + if peer.IsOutbound() { if pexR.book.NeedMoreAddrs() { pexR.RequestPEX(peer) @@ -74,6 +79,7 @@ func (pexR *PEXReactor) AddPeer(peer *Peer) { // (For outbound peers, the address is already in the books) pexR.book.AddAddress(netAddr, netAddr) } + return } // Implements Reactor diff --git a/switch.go b/switch.go index 841c44f86..9ee933640 100644 --- a/switch.go +++ b/switch.go @@ -296,20 +296,58 @@ func (sw *Switch) startInitPeer(peer *Peer) { sw.addPeerToReactors(peer) // run AddPeer on each reactor } +//error type for seed errors +type SeedError struct { + seed string + err error +} + +type SeedErrors []SeedError + +func (se SeedErrors) Error() string { + var str string + for _, e := range se { + str += ("seed: " + e.seed + " error: " + e.err.Error() + "; ") + } + return str +} + // Dial a list of seeds in random order -// Spawns a go routine for each dial -func (sw *Switch) DialSeeds(seeds []string) { +func (sw *Switch) DialSeeds(seeds []string) error { + + ch := make(chan SeedError) //channel for collecting errors + passing := 0 //number of passing seeds + // permute the list, dial them in random order. perm := rand.Perm(len(seeds)) for i := 0; i < len(perm); i++ { + go func(i int) { time.Sleep(time.Duration(rand.Int63n(3000)) * time.Millisecond) j := perm[i] - addr := NewNetAddressString(seeds[j]) - sw.dialSeed(addr) + addr, err := NewNetAddressString(seeds[j]) + + if err != nil { + ch <- SeedError{seeds[j], err} + } else { + sw.dialSeed(addr) + passing++ + } }(i) } + + //collect any errors from the channel + var seedErrs SeedErrors + for { + seedErr := <-ch + seedErrs = append(seedErrs, seedErr) + if len(seedErrs)+passing == len(perm) { + break + } + } + + return seedErrs } func (sw *Switch) dialSeed(addr *NetAddress) { diff --git a/switch_test.go b/switch_test.go index 1b2ccd743..85a1e080e 100644 --- a/switch_test.go +++ b/switch_test.go @@ -8,6 +8,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + . "github.com/tendermint/go-common" cfg "github.com/tendermint/go-config" "github.com/tendermint/go-crypto" @@ -119,6 +121,14 @@ func TestSwitches(t *testing.T) { t.Errorf("Expected exactly 1 peer in s2, got %v", s2.Peers().Size()) } + //Test DialSeeds + err := s1.DialSeeds([]string{s1.NodeInfo().Network}) //"0.0.0.0:46658"}) + assert.Nil(t, err, "expected successful dial seeds") + + //Test Bad Dial Seeds + err = s1.DialSeeds([]string{"0.0.0:46658"}) + assert.NotNil(t, err, "expected unsuccessful dial seeds") + // Lets send some messages ch0Msg := "channel zero" ch1Msg := "channel foo"