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 {
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])
b = append(b, a...)
sp = sp[2:]
if p.Size > 0 {
a := addressStringToBytes(p, sp[0])
b = append(b, a...)
sp = sp[1:]
}
}
return b, nil
}
@ -50,18 +52,22 @@ func bytesToString(b []byte) (ret string, err error) {
s := ""
for len(b) > 0 {
p := ProtocolWithCode(int(b[0]))
code, n := ReadVarintCode(b)
b = b[n:]
p := ProtocolWithCode(code)
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}, "")
b = b[1:]
a := addressBytesToString(p, b[:(p.Size/8)])
if len(a) > 0 {
s = strings.Join([]string{s, "/", a}, "")
if p.Size > 0 {
a := addressBytesToString(p, b[:(p.Size/8)])
if len(a) > 0 {
s = strings.Join([]string{s, "/", a}, "")
}
b = b[(p.Size / 8):]
}
b = b[(p.Size / 8):]
}
return s, nil
@ -78,12 +84,13 @@ func bytesSplit(b []byte) (ret [][]byte, err error) {
ret = [][]byte{}
for len(b) > 0 {
p := ProtocolWithCode(int(b[0]))
code, n := ReadVarintCode(b)
p := ProtocolWithCode(code)
if p == nil {
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])
b = b[length:]
}

View File

@ -67,14 +67,15 @@ func (m *multiaddr) Protocols() []*Protocol {
ps := []*Protocol{}
b := m.bytes[:]
for len(b) > 0 {
p := ProtocolWithCode(int(b[0]))
code, n := ReadVarintCode(b)
p := ProtocolWithCode(code)
if p == nil {
// 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]))
}
ps = append(ps, p)
b = b[1+(p.Size/8):]
b = b[n+(p.Size/8):]
}
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/tcp/4321", "047f0000010610e1")
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
}
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/tcp/4321", "047f0000010610e1")
testString("/ip4/127.0.0.1/udp/1234/ip4/127.0.0.1/tcp/4321", "047f0000011104d2047f0000010610e1")
}
func TestBytesSplitAndJoin(t *testing.T) {
@ -96,7 +100,7 @@ func TestBytesSplitAndJoin(t *testing.T) {
testString := func(s string, res []string) {
m, err := NewMultiaddr(s)
if err != nil {
t.Error("failed to convert", s)
t.Fatal("failed to convert", s, err)
}
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/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) {

View File

@ -5,5 +5,7 @@ code size name
33 16 dccp
41 128 ip6
132 16 sctp
301 0 udt
302 0 utp
480 0 http
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
import (
"encoding/binary"
)
// Protocol is a Multiaddr protocol description structure.
type Protocol struct {
Code int
Size int
Name string
Code int
Size int
Name string
VCode []byte
}
// replicating table here to:
@ -18,17 +23,21 @@ const (
P_DCCP = 33
P_IP6 = 41
P_SCTP = 132
P_UTP = 301
P_UDT = 302
)
// Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []*Protocol{
&Protocol{P_IP4, 32, "ip4"},
&Protocol{P_TCP, 16, "tcp"},
&Protocol{P_UDP, 16, "udp"},
&Protocol{P_DCCP, 16, "dccp"},
&Protocol{P_IP6, 128, "ip6"},
&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"},
&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"},
}
@ -52,3 +61,26 @@ func ProtocolWithCode(c int) *Protocol {
}
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
}