implement varints + add utp, udt

This commit is contained in:
Juan Batiz-Benet 2014-11-19 13:01:52 -08:00
parent 62a88e015e
commit 59f6cfc921
5 changed files with 74 additions and 26 deletions

View File

@ -28,12 +28,14 @@ func stringToBytes(s string) ([]byte, error) {
if p == nil { if p == nil {
return nil, fmt.Errorf("no protocol with name %s", sp[0]) return nil, fmt.Errorf("no protocol with name %s", sp[0])
} }
b = append(b, byte(p.Code)) b = append(b, CodeToVarint(p.Code)...)
sp = sp[1:]
a := addressStringToBytes(p, sp[1]) if p.Size > 0 {
b = append(b, a...) a := addressStringToBytes(p, sp[0])
b = append(b, a...)
sp = sp[2:] sp = sp[1:]
}
} }
return b, nil return b, nil
} }
@ -50,18 +52,22 @@ func bytesToString(b []byte) (ret string, err error) {
s := "" s := ""
for len(b) > 0 { for len(b) > 0 {
p := ProtocolWithCode(int(b[0]))
code, n := ReadVarintCode(b)
b = b[n:]
p := ProtocolWithCode(code)
if p == nil { if p == nil {
return "", fmt.Errorf("no protocol with code %d", b[0]) return "", fmt.Errorf("no protocol with code %d", code)
} }
s = strings.Join([]string{s, "/", p.Name}, "") s = strings.Join([]string{s, "/", p.Name}, "")
b = b[1:]
a := addressBytesToString(p, b[:(p.Size/8)]) if p.Size > 0 {
if len(a) > 0 { a := addressBytesToString(p, b[:(p.Size/8)])
s = strings.Join([]string{s, "/", a}, "") if len(a) > 0 {
s = strings.Join([]string{s, "/", a}, "")
}
b = b[(p.Size / 8):]
} }
b = b[(p.Size / 8):]
} }
return s, nil return s, nil
@ -78,12 +84,13 @@ func bytesSplit(b []byte) (ret [][]byte, err error) {
ret = [][]byte{} ret = [][]byte{}
for len(b) > 0 { for len(b) > 0 {
p := ProtocolWithCode(int(b[0])) code, n := ReadVarintCode(b)
p := ProtocolWithCode(code)
if p == nil { if p == nil {
return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0]) return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
} }
length := 1 + (p.Size / 8) length := n + (p.Size / 8)
ret = append(ret, b[:length]) ret = append(ret, b[:length])
b = b[length:] b = b[length:]
} }

View File

@ -67,14 +67,15 @@ func (m *multiaddr) Protocols() []*Protocol {
ps := []*Protocol{} ps := []*Protocol{}
b := m.bytes[:] b := m.bytes[:]
for len(b) > 0 { for len(b) > 0 {
p := ProtocolWithCode(int(b[0])) code, n := ReadVarintCode(b)
p := ProtocolWithCode(code)
if p == nil { if p == nil {
// this is a panic (and not returning err) because this should've been // this is a panic (and not returning err) because this should've been
// caught on constructing the Multiaddr // caught on constructing the Multiaddr
panic(fmt.Errorf("no protocol with code %d", b[0])) panic(fmt.Errorf("no protocol with code %d", b[0]))
} }
ps = append(ps, p) ps = append(ps, p)
b = b[1+(p.Size/8):] b = b[n+(p.Size/8):]
} }
return ps return ps
} }

View File

@ -68,6 +68,8 @@ func TestStringToBytes(t *testing.T) {
} }
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
} }
func TestBytesToString(t *testing.T) { func TestBytesToString(t *testing.T) {
@ -89,6 +91,8 @@ func TestBytesToString(t *testing.T) {
} }
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
testString("/ip4/127.0.0.1/tcp/4321", "047f0000010610e1")
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
} }
func TestBytesSplitAndJoin(t *testing.T) { func TestBytesSplitAndJoin(t *testing.T) {
@ -96,7 +100,7 @@ func TestBytesSplitAndJoin(t *testing.T) {
testString := func(s string, res []string) { testString := func(s string, res []string) {
m, err := NewMultiaddr(s) m, err := NewMultiaddr(s)
if err != nil { if err != nil {
t.Error("failed to convert", s) t.Fatal("failed to convert", s, err)
} }
split := Split(m) split := Split(m)
@ -132,6 +136,8 @@ func TestBytesSplitAndJoin(t *testing.T) {
testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"}) testString("/ip4/1.2.3.4/udp/1234", []string{"/ip4/1.2.3.4", "/udp/1234"})
testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2", testString("/ip4/1.2.3.4/tcp/1/ip4/2.3.4.5/udp/2",
[]string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"}) []string{"/ip4/1.2.3.4", "/tcp/1", "/ip4/2.3.4.5", "/udp/2"})
testString("/ip4/1.2.3.4/utp/ip4/2.3.4.5/udp/2/udt",
[]string{"/ip4/1.2.3.4", "/utp", "/ip4/2.3.4.5", "/udp/2", "/udt"})
} }
func TestProtocols(t *testing.T) { func TestProtocols(t *testing.T) {

View File

@ -5,5 +5,7 @@ code size name
33 16 dccp 33 16 dccp
41 128 ip6 41 128 ip6
132 16 sctp 132 16 sctp
301 0 udt
302 0 utp
480 0 http 480 0 http
443 0 https 443 0 https

1 code size name
5 33 16 dccp
6 41 128 ip6
7 132 16 sctp
8 301 0 udt
9 302 0 utp
10 480 0 http
11 443 0 https

View File

@ -1,10 +1,15 @@
package multiaddr package multiaddr
import (
"encoding/binary"
)
// Protocol is a Multiaddr protocol description structure. // Protocol is a Multiaddr protocol description structure.
type Protocol struct { type Protocol struct {
Code int Code int
Size int Size int
Name string Name string
VCode []byte
} }
// replicating table here to: // replicating table here to:
@ -18,17 +23,21 @@ const (
P_DCCP = 33 P_DCCP = 33
P_IP6 = 41 P_IP6 = 41
P_SCTP = 132 P_SCTP = 132
P_UTP = 301
P_UDT = 302
) )
// Protocols is the list of multiaddr protocols supported by this module. // Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []*Protocol{ var Protocols = []*Protocol{
&Protocol{P_IP4, 32, "ip4"}, &Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4)},
&Protocol{P_TCP, 16, "tcp"}, &Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP)},
&Protocol{P_UDP, 16, "udp"}, &Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP)},
&Protocol{P_DCCP, 16, "dccp"}, &Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)},
&Protocol{P_IP6, 128, "ip6"}, &Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6)},
// these require varint: // these require varint:
&Protocol{P_SCTP, 16, "sctp"}, &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"}, // {480, 0, "http"},
// {443, 0, "https"}, // {443, 0, "https"},
} }
@ -52,3 +61,26 @@ func ProtocolWithCode(c int) *Protocol {
} }
return nil return nil
} }
// CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte {
buf := make([]byte, (num/7)+1) // varint package is uint64
n := binary.PutUvarint(buf, uint64(num))
return buf[:n]
}
// VarintToCode converts a varint-encoded []byte to an integer protocol code
func VarintToCode(buf []byte) int {
num, _ := ReadVarintCode(buf)
return num
}
// ReadVarintCode reads a varint code from the beginning of buf.
// returns the code, and the number of bytes read.
func ReadVarintCode(buf []byte) (int, int) {
num, n := binary.Uvarint(buf)
if n < 0 {
panic("varints larger than uint64 not yet supported")
}
return int(num), n
}