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

View File

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

View File

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

View File

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