Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Transocoder functionality #42

Merged
merged 2 commits into from
Dec 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 8 additions & 150 deletions codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,8 @@ package multiaddr

import (
"bytes"
"encoding/base32"
"encoding/binary"
"errors"
"fmt"
"net"
"strconv"
"strings"

mh "github.com/multiformats/go-multihash"
)

func stringToBytes(s string) ([]byte, error) {
Expand Down Expand Up @@ -50,7 +43,10 @@ func stringToBytes(s string) ([]byte, error) {
sp = []string{"/" + strings.Join(sp, "/")}
}

a, err := addressStringToBytes(p, sp[0])
if p.Transcoder == nil {
return nil, fmt.Errorf("no transcoder for %s protocol", p.Name)
}
a, err := p.Transcoder.StringToBytes(sp[0])
if err != nil {
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
}
Expand Down Expand Up @@ -122,7 +118,10 @@ func bytesToString(b []byte) (ret string, err error) {
return "", fmt.Errorf("invalid value for size")
}

a, err := addressBytesToString(p, b[:size])
if p.Transcoder == nil {
return "", fmt.Errorf("no transcoder for %s protocol", p.Name)
}
a, err := p.Transcoder.BytesToString(b[:size])
if err != nil {
return "", err
}
Expand Down Expand Up @@ -181,144 +180,3 @@ func bytesSplit(b []byte) ([][]byte, error) {

return ret, nil
}

func addressStringToBytes(p Protocol, s string) ([]byte, error) {
switch p.Code {

case P_IP4: // ipv4
i := net.ParseIP(s).To4()
if i == nil {
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
}
return i, nil

case P_IP6: // ipv6
i := net.ParseIP(s).To16()
if i == nil {
return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
}
return i, nil

// tcp udp dccp sctp
case P_TCP, P_UDP, P_DCCP, P_SCTP:
i, err := strconv.Atoi(s)
if err != nil {
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err)
}
if i >= 65536 {
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "greater than 65536")
}
b := make([]byte, 2)
binary.BigEndian.PutUint16(b, uint16(i))
return b, nil

case P_ONION:
addr := strings.Split(s, ":")
if len(addr) != 2 {
return nil, fmt.Errorf("failed to parse %s addr: %s does not contain a port number.", p.Name, s)
}

// onion address without the ".onion" substring
if len(addr[0]) != 16 {
return nil, fmt.Errorf("failed to parse %s addr: %s not a Tor onion address.", p.Name, s)
}
onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0]))
if err != nil {
return nil, fmt.Errorf("failed to decode base32 %s addr: %s %s", p.Name, s, err)
}

// onion port number
i, err := strconv.Atoi(addr[1])
if err != nil {
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, err)
}
if i >= 65536 {
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port greater than 65536")
}
if i < 1 {
return nil, fmt.Errorf("failed to parse %s addr: %s", p.Name, "port less than 1")
}

onionPortBytes := make([]byte, 2)
binary.BigEndian.PutUint16(onionPortBytes, uint16(i))
bytes := []byte{}
bytes = append(bytes, onionHostBytes...)
bytes = append(bytes, onionPortBytes...)
return bytes, nil

case P_IPFS: // ipfs
// the address is a varint prefixed multihash string representation
m, err := mh.FromB58String(s)
if err != nil {
return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err)
}
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)
}

func addressBytesToString(p Protocol, b []byte) (string, error) {
switch p.Code {

// ipv4,6
case P_IP4, P_IP6:
return net.IP(b).String(), nil

// tcp udp dccp sctp
case P_TCP, P_UDP, P_DCCP, P_SCTP:
i := binary.BigEndian.Uint16(b)
return strconv.Itoa(int(i)), nil

case P_IPFS: // ipfs
// the address is a varint-prefixed multihash string representation
size, n, err := ReadVarintCode(b)
if err != nil {
return "", err
}

b = b[n:]
if len(b) != size {
return "", errors.New("inconsistent lengths")
}
m, err := mh.Cast(b)
if err != nil {
return "", err
}
return m.B58String(), nil

case P_ONION:
addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:10]))
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 "", errors.New("unknown protocol")
}
}
37 changes: 19 additions & 18 deletions protocols.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (

// Protocol is a Multiaddr protocol description structure.
type Protocol struct {
Code int
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)
Code int
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)
Transcoder Transcoder
}

// replicating table here to:
Expand Down Expand Up @@ -42,20 +43,20 @@ const (

// Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []Protocol{
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},
Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false, TranscoderIP4},
Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false, TranscoderPort},
Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false, TranscoderPort},
Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false, TranscoderPort},
Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false, TranscoderIP6},
// these require varint:
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},
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false, TranscoderPort},
Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false, TranscoderOnion},
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false, nil},
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false, nil},
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false, nil},
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false, nil},
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS), false, TranscoderIPFS},
Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true, TranscoderUnix},
}

func AddProtocol(p Protocol) error {
Expand Down
Loading