From 19a5f088d53551a917dc5e0620db7242c331ce9d Mon Sep 17 00:00:00 2001 From: Juan Batiz-Benet Date: Fri, 9 Jan 2015 05:51:51 -0800 Subject: [PATCH] updated multiaddr --- Godeps/Godeps.json | 4 +- .../github.com/jbenet/go-multiaddr/README.md | 6 +- .../github.com/jbenet/go-multiaddr/codec.go | 44 +++++--- .../jbenet/go-multiaddr/interface.go | 2 +- .../jbenet/go-multiaddr/multiaddr.go | 6 +- .../jbenet/go-multiaddr/multiaddr_test.go | 101 +++++++++++++++++- .../jbenet/go-multiaddr/protocols.go | 47 +++++--- p2p/net/conn/dial.go | 2 +- 8 files changed, 174 insertions(+), 38 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 6aa0e7ad0..727313151 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -122,8 +122,8 @@ }, { "ImportPath": "github.com/jbenet/go-multiaddr", - "Comment": "0.1.2-30-g99cf3ed", - "Rev": "99cf3edc711751cf7b43505fac0e3913f6b9a75c" + "Comment": "0.1.2-34-g0d7b54b", + "Rev": "0d7b54ba432fda14bac37cdad717bd6270eacc85" }, { "ImportPath": "github.com/jbenet/go-multiaddr-net", diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md index f2545485d..42c23fff8 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/README.md @@ -28,9 +28,9 @@ m2.Equal(m1) ```go // get the multiaddr protocol description objects addr.Protocols() -// []*Protocol{ -// &Protocol{ Code: 4, Name: 'ip4', Size: 32}, -// &Protocol{ Code: 17, Name: 'udp', Size: 16}, +// []Protocol{ +// Protocol{ Code: 4, Name: 'ip4', Size: 32}, +// Protocol{ Code: 17, Name: 'udp', Size: 16}, // } ``` diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go index cc8a2ed99..03502e9dd 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/codec.go @@ -25,14 +25,20 @@ func stringToBytes(s string) ([]byte, error) { for len(sp) > 0 { p := ProtocolWithName(sp[0]) - if p == nil { + if p.Code == 0 { return nil, fmt.Errorf("no protocol with name %s", sp[0]) } b = append(b, CodeToVarint(p.Code)...) sp = sp[1:] if p.Size > 0 { - a := addressStringToBytes(p, sp[0]) + if len(sp) < 1 { + return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name) + } + a, err := addressStringToBytes(p, sp[0]) + if err != nil { + return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err) + } b = append(b, a...) sp = sp[1:] } @@ -56,7 +62,7 @@ func bytesToString(b []byte) (ret string, err error) { code, n := ReadVarintCode(b) b = b[n:] p := ProtocolWithCode(code) - if p == nil { + if p.Code == 0 { return "", fmt.Errorf("no protocol with code %d", code) } s = strings.Join([]string{s, "/", p.Name}, "") @@ -86,7 +92,7 @@ func bytesSplit(b []byte) (ret [][]byte, err error) { for len(b) > 0 { code, n := ReadVarintCode(b) p := ProtocolWithCode(code) - if p == nil { + if p.Code == 0 { return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0]) } @@ -98,29 +104,41 @@ func bytesSplit(b []byte) (ret [][]byte, err error) { return ret, nil } -func addressStringToBytes(p *Protocol, s string) []byte { +func addressStringToBytes(p Protocol, s string) ([]byte, error) { switch p.Code { case P_IP4: // ipv4 - return net.ParseIP(s).To4() + i := net.ParseIP(s).To4() + if i == nil { + return nil, fmt.Errorf("failed to parse ip4 addr: %s", s) + } + return i, nil case P_IP6: // ipv6 - return net.ParseIP(s).To16() + i := net.ParseIP(s).To16() + if i == nil { + return nil, fmt.Errorf("failed to parse ip6 addr: %s", s) + } + return i, nil // tcp udp dccp sctp case P_TCP, P_UDP, P_DCCP, P_SCTP: - b := make([]byte, 2) i, err := strconv.Atoi(s) - if err == nil { - binary.BigEndian.PutUint16(b, uint16(i)) + if err != nil { + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err) } - return b + if i >= 65536 { + return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536") + } + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, uint16(i)) + return b, nil } - return []byte{} + return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name) } -func addressBytesToString(p *Protocol, b []byte) string { +func addressBytesToString(p Protocol, b []byte) string { switch p.Code { // ipv4,6 diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go index 6f57625a3..512cb623f 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/interface.go @@ -26,7 +26,7 @@ type Multiaddr interface { // Protocols returns the list of Protocols this Multiaddr includes // will panic if protocol code incorrect (and bytes accessed incorrectly) - Protocols() []*Protocol + Protocols() []Protocol // Encapsulate wraps this Multiaddr around another. For example: // diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go index 3071fa9a7..373c2c193 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr.go @@ -54,7 +54,7 @@ func (m *multiaddr) String() string { // Protocols returns the list of protocols this Multiaddr has. // will panic in case we access bytes incorrectly. -func (m *multiaddr) Protocols() []*Protocol { +func (m *multiaddr) Protocols() []Protocol { // panic handler, in case we try accessing bytes incorrectly. defer func() { @@ -64,12 +64,12 @@ func (m *multiaddr) Protocols() []*Protocol { } }() - ps := []*Protocol{} + ps := []Protocol{} b := m.bytes[:] for len(b) > 0 { code, n := ReadVarintCode(b) p := ProtocolWithCode(code) - if p == nil { + if p.Code == 0 { // this is a panic (and not returning err) because this should've been // caught on constructing the Multiaddr panic(fmt.Errorf("no protocol with code %d", b[0])) diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go index 15e2be0b6..654589764 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/multiaddr_test.go @@ -14,6 +14,63 @@ func newMultiaddr(t *testing.T, a string) Multiaddr { return m } +func TestConstructFails(t *testing.T) { + cases := []string{ + "/ip4", + "/ip4/::1", + "/ip4/fdpsofodsajfdoisa", + "/ip6", + "/udp", + "/tcp", + "/sctp", + "/udp/65536", + "/tcp/65536", + "/udp/1234/sctp", + "/udp/1234/udt/1234", + "/udp/1234/utp/1234", + "/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa", + "/ip4/127.0.0.1/udp", + "/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa", + "/ip4/127.0.0.1/tcp", + } + + for _, a := range cases { + if _, err := NewMultiaddr(a); err == nil { + t.Errorf("should have failed: %s", a) + } + } +} + +func TestConstructSucceeds(t *testing.T) { + cases := []string{ + "/ip4/1.2.3.4", + "/ip4/0.0.0.0", + "/ip6/::1", + "/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", + "/udp/0", + "/tcp/0", + "/sctp/0", + "/udp/1234", + "/tcp/1234", + "/sctp/1234", + "/udp/65535", + "/tcp/65535", + "/udp/1234/sctp/1234", + "/udp/1234/udt", + "/udp/1234/utp", + "/ip4/127.0.0.1/udp/1234", + "/ip4/127.0.0.1/udp/0", + "/ip4/127.0.0.1/tcp/1234", + "/ip4/127.0.0.1/tcp/1234/", + } + + for _, a := range cases { + if _, err := NewMultiaddr(a); err != nil { + t.Errorf("should have succeeded: %s", a) + } + } +} + func TestEqual(t *testing.T) { m1 := newMultiaddr(t, "/ip4/127.0.0.1/udp/1234") m2 := newMultiaddr(t, "/ip4/127.0.0.1/tcp/1234") @@ -147,18 +204,58 @@ func TestProtocols(t *testing.T) { } ps := m.Protocols() - if ps[0] != ProtocolWithName("ip4") { + if ps[0].Code != ProtocolWithName("ip4").Code { t.Error(ps[0], ProtocolWithName("ip4")) t.Error("failed to get ip4 protocol") } - if ps[1] != ProtocolWithName("udp") { + if ps[1].Code != ProtocolWithName("udp").Code { t.Error(ps[1], ProtocolWithName("udp")) t.Error("failed to get udp protocol") } } +func TestProtocolsWithString(t *testing.T) { + pwn := ProtocolWithName + good := map[string][]Protocol{ + "/ip4": []Protocol{pwn("ip4")}, + "/ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")}, + "ip4/tcp/udp/ip6": []Protocol{pwn("ip4"), pwn("tcp"), pwn("udp"), pwn("ip6")}, + "////////ip4/tcp": []Protocol{pwn("ip4"), pwn("tcp")}, + "ip4/udp/////////": []Protocol{pwn("ip4"), pwn("udp")}, + "////////ip4/tcp////////": []Protocol{pwn("ip4"), pwn("tcp")}, + } + + for s, ps1 := range good { + ps2, err := ProtocolsWithString(s) + if err != nil { + t.Error("ProtocolsWithString(%s) should have succeeded", s) + } + + for i, ps1p := range ps1 { + ps2p := ps2[i] + if ps1p.Code != ps2p.Code { + t.Errorf("mismatch: %s != %s, %s", ps1p.Name, ps2p.Name, s) + } + } + } + + bad := []string{ + "dsijafd", // bogus proto + "/ip4/tcp/fidosafoidsa", // bogus proto + "////////ip4/tcp/21432141/////////", // bogus proto + "////////ip4///////tcp/////////", // empty protos in between + } + + for _, s := range bad { + if _, err := ProtocolsWithString(s); err == nil { + t.Error("ProtocolsWithString(%s) should have failed", s) + } + } + +} + func TestEncapsulate(t *testing.T) { m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") if err != nil { diff --git a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go index 49051be25..eaddc615e 100644 --- a/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go +++ b/Godeps/_workspace/src/github.com/jbenet/go-multiaddr/protocols.go @@ -2,6 +2,8 @@ package multiaddr import ( "encoding/binary" + "fmt" + "strings" ) // Protocol is a Multiaddr protocol description structure. @@ -28,38 +30,57 @@ const ( ) // Protocols is the list of multiaddr protocols supported by this module. -var Protocols = []*Protocol{ - &Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4)}, - &Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP)}, - &Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP)}, - &Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)}, - &Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, +var Protocols = []Protocol{ + Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4)}, + Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP)}, + Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP)}, + Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)}, + Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, // these require varint: - &Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, - &Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, - &Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, + Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, + Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, + Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, // {480, 0, "http"}, // {443, 0, "https"}, } // ProtocolWithName returns the Protocol description with given string name. -func ProtocolWithName(s string) *Protocol { +func ProtocolWithName(s string) Protocol { for _, p := range Protocols { if p.Name == s { return p } } - return nil + return Protocol{} } // ProtocolWithCode returns the Protocol description with given protocol code. -func ProtocolWithCode(c int) *Protocol { +func ProtocolWithCode(c int) Protocol { for _, p := range Protocols { if p.Code == c { return p } } - return nil + return Protocol{} +} + +// ProtocolsWithString returns a slice of protocols matching given string. +func ProtocolsWithString(s string) ([]Protocol, error) { + s = strings.Trim(s, "/") + sp := strings.Split(s, "/") + if len(sp) == 0 { + return nil, nil + } + + t := make([]Protocol, len(sp)) + for i, name := range sp { + p := ProtocolWithName(name) + if p.Code == 0 { + return nil, fmt.Errorf("no protocol with name: %s", name) + } + t[i] = p + } + return t, nil } // CodeToVarint converts an integer to a varint-encoded []byte diff --git a/p2p/net/conn/dial.go b/p2p/net/conn/dial.go index 1294f2241..d63fb0258 100644 --- a/p2p/net/conn/dial.go +++ b/p2p/net/conn/dial.go @@ -100,7 +100,7 @@ func MultiaddrProtocolsMatch(a, b ma.Multiaddr) bool { } for i, api := range ap { - if api != bp[i] { + if api.Code != bp[i].Code { return false } }