From bdf3e3a444b6baa1634406bf00324e0029f16388 Mon Sep 17 00:00:00 2001 From: jbenet Date: Mon, 12 Sep 2016 02:03:41 -0400 Subject: [PATCH] added unix path protocol --- codec.go | 42 +++++++++++++++++++++++++++++++++++++++--- multiaddr.go | 2 +- multiaddr_test.go | 10 ++++++++++ protocols.csv | 2 ++ protocols.go | 27 +++++++++++++++------------ 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/codec.go b/codec.go index 2068b84..36de467 100644 --- a/codec.go +++ b/codec.go @@ -8,6 +8,7 @@ import ( "net" "strconv" "strings" + "errors" mh "github.com/jbenet/go-multihash" ) @@ -43,6 +44,12 @@ func stringToBytes(s string) ([]byte, error) { return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name) } + if p.Path { + // it's a path protocol (terminal). + // consume the rest of the address as the next component. + sp = []string{"/" + strings.Join(sp, "/")} + } + a, err := addressStringToBytes(p, sp[0]) if err != nil { return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err) @@ -134,12 +141,17 @@ func sizeForAddr(p Protocol, b []byte) (int, error) { return (p.Size / 8), nil case p.Size == 0: return 0, nil + case p.Path: + size, n, err := ReadVarintCode(b) + if err != nil { + return 0, err + } + return size + n, nil default: size, n, err := ReadVarintCode(b) if err != nil { return 0, err } - return size + n, nil } } @@ -243,6 +255,12 @@ func addressStringToBytes(p Protocol, s string) ([]byte, error) { size := CodeToVarint(len(m)) b := append(size, m...) return b, nil + + case P_UNIX: + // the address is the whole remaining string, prefixed by a varint len + size := CodeToVarint(len(s)) + b := append(size, []byte(s)...) + return b, nil } return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name) @@ -269,7 +287,7 @@ func addressBytesToString(p Protocol, b []byte) (string, error) { b = b[n:] if len(b) != size { - return "", fmt.Errorf("inconsistent lengths") + return "", errors.New("inconsistent lengths") } m, err := mh.Cast(b) if err != nil { @@ -282,7 +300,25 @@ func addressBytesToString(p Protocol, b []byte) (string, error) { port := binary.BigEndian.Uint16(b[10:12]) return addr + ":"+ strconv.Itoa(int(port)), nil + case P_UNIX: + // the address is a varint len prefixed string + size, n, err := ReadVarintCode(b) + if err != nil { + return "", err + } + + b = b[n:] + if len(b) != size { + return "", errors.New("inconsistent lengths") + } + if size == 0 { + return "", errors.New("invalid length") + } + s := string(b) + s = s[1:] // remove starting slash + return s, nil + default: - return "", fmt.Errorf("unknown protocol") + return "", errors.New("unknown protocol") } } diff --git a/multiaddr.go b/multiaddr.go index 430cb1d..41c0d0b 100644 --- a/multiaddr.go +++ b/multiaddr.go @@ -144,7 +144,7 @@ func (m *multiaddr) ValueForProtocol(code int) (string, error) { if p.Size == 0 { return "", nil } - return strings.Split(sub.String(), "/")[2], nil + return strings.SplitN(sub.String(), "/", 3)[2], nil } } diff --git a/multiaddr_test.go b/multiaddr_test.go index 3d5a835..9cd6b19 100644 --- a/multiaddr_test.go +++ b/multiaddr_test.go @@ -43,6 +43,8 @@ func TestConstructFails(t *testing.T) { "/ip4/127.0.0.1/tcp", "/ip4/127.0.0.1/ipfs", "/ip4/127.0.0.1/ipfs/tcp", + "/unix", + "/ip4/1.2.3.4/tcp/80/unix", } for _, a := range cases { @@ -81,6 +83,10 @@ func TestConstructSucceeds(t *testing.T) { "/ip4/127.0.0.1/tcp/1234/", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", + "/unix/a/b/c/d/e", + "/unix/stdio", + "/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f", + "/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio", } for _, a := range cases { @@ -353,6 +359,10 @@ func TestGetValue(t *testing.T) { assertValueForProto(t, a, P_IP4, "0.0.0.0") assertValueForProto(t, a, P_UDP, "12345") assertValueForProto(t, a, P_UTP, "") + + a = newMultiaddr(t, "/ip4/0.0.0.0/unix/a/b/c/d") // ending in a path one. + assertValueForProto(t, a, P_IP4, "0.0.0.0") + assertValueForProto(t, a, P_UNIX, "a/b/c/d") } func TestFuzzBytes(t *testing.T) { diff --git a/protocols.csv b/protocols.csv index 53b993c..996b855 100644 --- a/protocols.csv +++ b/protocols.csv @@ -1,4 +1,5 @@ code size name + 4 32 ip4 6 16 tcp 17 16 udp @@ -7,6 +8,7 @@ code size name 132 16 sctp 301 0 utp 302 0 udt +400 V unix 421 V ipfs 480 0 http 443 0 https diff --git a/protocols.go b/protocols.go index 3fe0e58..aff30dc 100644 --- a/protocols.go +++ b/protocols.go @@ -12,6 +12,7 @@ type Protocol struct { Size int // a size of -1 indicates a length-prefixed variable size Name string VCode []byte + Path bool // indicates a path protocol (eg unix, http) } // replicating table here to: @@ -27,6 +28,7 @@ const ( P_SCTP = 132 P_UTP = 301 P_UDT = 302 + P_UNIX = 400 P_IPFS = 421 P_HTTP = 480 P_HTTPS = 443 @@ -40,19 +42,20 @@ 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)}, + Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false}, + Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false}, + Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false}, + Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false}, + Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false}, // these require varint: - Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, - Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION)}, - Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, - Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, - Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, - Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS)}, - Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS)}, + Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false}, + Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false}, + Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false}, + Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false}, + Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false}, + Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false}, + Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS), false}, + Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true}, } func AddProtocol(p Protocol) error {