This commit is contained in:
Juan Batiz-Benet 2014-07-04 11:21:39 -07:00
parent 3855a29d4e
commit 9033141fca
4 changed files with 209 additions and 213 deletions

136
codec.go
View File

@ -1,98 +1,96 @@
package multiaddr package multiaddr
import( import (
"fmt" "encoding/binary"
"strings" "fmt"
"encoding/binary" "net"
"net" "strconv"
"strconv" "strings"
) )
func StringToBytes(s string) ([]byte, error) { func StringToBytes(s string) ([]byte, error) {
b := []byte{} b := []byte{}
sp := strings.Split(s, "/") sp := strings.Split(s, "/")
// consume first empty elem // consume first empty elem
sp = sp[1:] sp = sp[1:]
for ; len(sp) > 0 ; { for len(sp) > 0 {
p := ProtocolWithName(sp[0]) p := ProtocolWithName(sp[0])
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, byte(p.Code))
a := AddressStringToBytes(p, sp[1]) a := AddressStringToBytes(p, sp[1])
b = append(b, a...) b = append(b, a...)
sp = sp[2:] sp = sp[2:]
} }
return b, nil return b, nil
} }
func BytesToString(b []byte) (ret string, err error) { func BytesToString(b []byte) (ret string, err error) {
// panic handler, in case we try accessing bytes incorrectly. // panic handler, in case we try accessing bytes incorrectly.
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
ret = "" ret = ""
err = e.(error) err = e.(error)
} }
}() }()
s := "" s := ""
for ; len(b) > 0 ; { for len(b) > 0 {
p := ProtocolWithCode(int(b[0])) p := ProtocolWithCode(int(b[0]))
if p == nil { if p == nil {
return "", fmt.Errorf("no protocol with code %d", b[0]) return "", fmt.Errorf("no protocol with code %d", b[0])
} }
s = strings.Join([]string{s, "/", p.Name}, "") s = strings.Join([]string{s, "/", p.Name}, "")
b = b[1:] b = b[1:]
a := AddressBytesToString(p, b[:(p.Size / 8)]) a := AddressBytesToString(p, b[:(p.Size/8)])
if len(a) > 0 { if len(a) > 0 {
s = strings.Join([]string{s, "/", a}, "") s = strings.Join([]string{s, "/", a}, "")
} }
b = b[(p.Size / 8):] b = b[(p.Size / 8):]
} }
return s, nil return s, nil
} }
func AddressStringToBytes(p *Protocol, s string) []byte { func AddressStringToBytes(p *Protocol, s string) []byte {
switch p.Code { switch p.Code {
// ipv4,6 // ipv4,6
case 4, 41: case 4, 41:
return net.ParseIP(s).To4() return net.ParseIP(s).To4()
// tcp udp dccp sctp // tcp udp dccp sctp
case 6, 17, 33, 132: case 6, 17, 33, 132:
b := make([]byte, 2) b := make([]byte, 2)
i, err := strconv.Atoi(s) i, err := strconv.Atoi(s)
if err == nil { if err == nil {
binary.BigEndian.PutUint16(b, uint16(i)) binary.BigEndian.PutUint16(b, uint16(i))
} }
return b return b
} }
return []byte{} return []byte{}
} }
func AddressBytesToString(p *Protocol, b []byte) string { func AddressBytesToString(p *Protocol, b []byte) string {
switch p.Code { switch p.Code {
// ipv4,6 // ipv4,6
case 4, 41: case 4, 41:
return net.IP(b).String() return net.IP(b).String()
// tcp udp dccp sctp // tcp udp dccp sctp
case 6, 17, 33, 132: case 6, 17, 33, 132:
i := binary.BigEndian.Uint16(b) i := binary.BigEndian.Uint16(b)
return strconv.Itoa(int(i)) return strconv.Itoa(int(i))
} }
return "" return ""
} }

View File

@ -1,69 +1,69 @@
package multiaddr package multiaddr
import ( import (
"fmt" "fmt"
"strings" "strings"
) )
type Multiaddr struct { type Multiaddr struct {
Bytes []byte Bytes []byte
} }
func NewMultiaddr(s string) (*Multiaddr, error) { func NewMultiaddr(s string) (*Multiaddr, error) {
b, err := StringToBytes(s) b, err := StringToBytes(s)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Multiaddr{Bytes: b}, nil return &Multiaddr{Bytes: b}, nil
} }
func (m *Multiaddr) String() (string, error) { func (m *Multiaddr) String() (string, error) {
return BytesToString(m.Bytes) return BytesToString(m.Bytes)
} }
func (m *Multiaddr) Protocols() (ret []*Protocol, err error) { func (m *Multiaddr) Protocols() (ret []*Protocol, err error) {
// panic handler, in case we try accessing bytes incorrectly. // panic handler, in case we try accessing bytes incorrectly.
defer func() { defer func() {
if e := recover(); e != nil { if e := recover(); e != nil {
ret = nil ret = nil
err = e.(error) err = e.(error)
} }
}() }()
ps := []*Protocol{} ps := []*Protocol{}
b := m.Bytes[:] b := m.Bytes[:]
for ; len(b) > 0 ; { for len(b) > 0 {
p := ProtocolWithCode(int(b[0])) p := ProtocolWithCode(int(b[0]))
if p == nil { if p == nil {
return nil, fmt.Errorf("no protocol with code %d", b[0]) return nil, 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[1+(p.Size/8):]
} }
return ps, nil return ps, nil
} }
func (m *Multiaddr) Encapsulate(o *Multiaddr) *Multiaddr { func (m *Multiaddr) Encapsulate(o *Multiaddr) *Multiaddr {
b := make([]byte, len(m.Bytes) + len(o.Bytes)) b := make([]byte, len(m.Bytes)+len(o.Bytes))
b = append(m.Bytes, o.Bytes...) b = append(m.Bytes, o.Bytes...)
return &Multiaddr{Bytes: b} return &Multiaddr{Bytes: b}
} }
func (m *Multiaddr) Decapsulate(o *Multiaddr) (*Multiaddr, error) { func (m *Multiaddr) Decapsulate(o *Multiaddr) (*Multiaddr, error) {
s1, err := m.String() s1, err := m.String()
if err != nil { if err != nil {
return nil, err return nil, err
} }
s2, err := o.String() s2, err := o.String()
if err != nil { if err != nil {
return nil, err return nil, err
} }
i := strings.LastIndex(s1, s2) i := strings.LastIndex(s1, s2)
if i < 0 { if i < 0 {
return nil, fmt.Errorf("%s not contained in %s", s2, s1) return nil, fmt.Errorf("%s not contained in %s", s2, s1)
} }
return NewMultiaddr(s1[:i]) return NewMultiaddr(s1[:i])
} }

View File

@ -1,111 +1,109 @@
package multiaddr package multiaddr
import ( import (
"bytes" "bytes"
"testing" "encoding/hex"
"encoding/hex" "testing"
) )
func TestStringToBytes(t *testing.T) { func TestStringToBytes(t *testing.T) {
testString := func(s string, h string) { testString := func(s string, h string) {
b1, err := hex.DecodeString(h) b1, err := hex.DecodeString(h)
if err != nil { if err != nil {
t.Error("failed to decode hex", h) t.Error("failed to decode hex", h)
} }
b2, err := StringToBytes(s) b2, err := StringToBytes(s)
if err != nil { if err != nil {
t.Error("failed to convert", s) t.Error("failed to convert", s)
} }
if !bytes.Equal(b1, b2) { if !bytes.Equal(b1, b2) {
t.Error("failed to convert", s, "to", b1, "got", b2) t.Error("failed to convert", s, "to", b1, "got", b2)
} }
} }
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
} }
func TestBytesToString(t *testing.T) { func TestBytesToString(t *testing.T) {
testString := func(s1 string, h string) { testString := func(s1 string, h string) {
b, err := hex.DecodeString(h) b, err := hex.DecodeString(h)
if err != nil { if err != nil {
t.Error("failed to decode hex", h) t.Error("failed to decode hex", h)
} }
s2, err := BytesToString(b) s2, err := BytesToString(b)
if err != nil { if err != nil {
t.Error("failed to convert", b) t.Error("failed to convert", b)
} }
if s1 != s2 { if s1 != s2 {
t.Error("failed to convert", b, "to", s1, "got", s2) t.Error("failed to convert", b, "to", s1, "got", s2)
} }
} }
testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2") testString("/ip4/127.0.0.1/udp/1234", "047f0000011104d2")
} }
func TestProtocols(t *testing.T) { func TestProtocols(t *testing.T) {
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
if err != nil { if err != nil {
t.Error("failed to construct", "/ip4/127.0.0.1/udp/1234") t.Error("failed to construct", "/ip4/127.0.0.1/udp/1234")
} }
ps, err := m.Protocols() ps, err := m.Protocols()
if err != nil { if err != nil {
t.Error("failed to get protocols", "/ip4/127.0.0.1/udp/1234") t.Error("failed to get protocols", "/ip4/127.0.0.1/udp/1234")
} }
if ps[0] != ProtocolWithName("ip4") { if ps[0] != ProtocolWithName("ip4") {
t.Error(ps[0], ProtocolWithName("ip4")) t.Error(ps[0], ProtocolWithName("ip4"))
t.Error("failed to get ip4 protocol") t.Error("failed to get ip4 protocol")
} }
if ps[1] != ProtocolWithName("udp") { if ps[1] != ProtocolWithName("udp") {
t.Error(ps[1], ProtocolWithName("udp")) t.Error(ps[1], ProtocolWithName("udp"))
t.Error("failed to get udp protocol") t.Error("failed to get udp protocol")
} }
} }
func TestEncapsulate(t *testing.T) { func TestEncapsulate(t *testing.T) {
m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234") m, err := NewMultiaddr("/ip4/127.0.0.1/udp/1234")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
m2, err := NewMultiaddr("/udp/5678") m2, err := NewMultiaddr("/udp/5678")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
b := m.Encapsulate(m2) b := m.Encapsulate(m2)
if s, _ := b.String(); s != "/ip4/127.0.0.1/udp/1234/udp/5678" { if s, _ := b.String(); s != "/ip4/127.0.0.1/udp/1234/udp/5678" {
t.Error("encapsulate /ip4/127.0.0.1/udp/1234/udp/5678 failed.", s) t.Error("encapsulate /ip4/127.0.0.1/udp/1234/udp/5678 failed.", s)
} }
m3, _ := NewMultiaddr("/udp/5678") m3, _ := NewMultiaddr("/udp/5678")
c, err := b.Decapsulate(m3) c, err := b.Decapsulate(m3)
if err != nil { if err != nil {
t.Error("decapsulate /udp failed.", err) t.Error("decapsulate /udp failed.", err)
} }
if s, _ := c.String(); s != "/ip4/127.0.0.1/udp/1234" { if s, _ := c.String(); s != "/ip4/127.0.0.1/udp/1234" {
t.Error("decapsulate /udp failed.", "/ip4/127.0.0.1/udp/1234", s) t.Error("decapsulate /udp failed.", "/ip4/127.0.0.1/udp/1234", s)
} }
m4, _ := NewMultiaddr("/ip4/127.0.0.1") m4, _ := NewMultiaddr("/ip4/127.0.0.1")
d, err := c.Decapsulate(m4) d, err := c.Decapsulate(m4)
if err != nil { if err != nil {
t.Error("decapsulate /ip4 failed.", err) t.Error("decapsulate /ip4 failed.", err)
} }
if s, _ := d.String(); s != "" { if s, _ := d.String(); s != "" {
t.Error("decapsulate /ip4 failed.", "/", s) t.Error("decapsulate /ip4 failed.", "/", s)
} }
} }

View File

@ -1,9 +1,9 @@
package multiaddr package multiaddr
type Protocol struct { type Protocol struct {
Code int Code int
Size int Size int
Name string Name string
} }
// replicating table here to: // replicating table here to:
@ -12,31 +12,31 @@ type Protocol struct {
// 3. changing a number has to happen in two places. // 3. changing a number has to happen in two places.
var Protocols = []*Protocol{ var Protocols = []*Protocol{
&Protocol{4, 32, "ip4"}, &Protocol{4, 32, "ip4"},
&Protocol{6, 16, "tcp"}, &Protocol{6, 16, "tcp"},
&Protocol{17, 16, "udp"}, &Protocol{17, 16, "udp"},
&Protocol{33, 16, "dccp"}, &Protocol{33, 16, "dccp"},
&Protocol{41, 128, "ip6"}, &Protocol{41, 128, "ip6"},
// these require varint: // these require varint:
&Protocol{132, 16, "sctp"}, &Protocol{132, 16, "sctp"},
// {480, 0, "http"}, // {480, 0, "http"},
// {443, 0, "https"}, // {443, 0, "https"},
} }
func ProtocolWithName(s string) *Protocol { func ProtocolWithName(s string) *Protocol {
for _, p := range(Protocols) { for _, p := range Protocols {
if p.Name == s { if p.Name == s {
return p return p
} }
} }
return nil return nil
} }
func ProtocolWithCode(c int) *Protocol { func ProtocolWithCode(c int) *Protocol {
for _, p := range(Protocols) { for _, p := range Protocols {
if p.Code == c { if p.Code == c {
return p return p
} }
} }
return nil return nil
} }