mirror of
https://github.com/waku-org/go-multiaddr.git
synced 2025-02-23 19:48:18 +00:00
add Transocoder functionality
Allowing multiaddr extensions to have data with
This commit is contained in:
parent
0de18dfd80
commit
1919305418
158
codec.go
158
codec.go
@ -2,15 +2,8 @@ package multiaddr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base32"
|
|
||||||
"encoding/binary"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
mh "github.com/multiformats/go-multihash"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func stringToBytes(s string) ([]byte, error) {
|
func stringToBytes(s string) ([]byte, error) {
|
||||||
@ -50,7 +43,10 @@ func stringToBytes(s string) ([]byte, error) {
|
|||||||
sp = []string{"/" + strings.Join(sp, "/")}
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
||||||
}
|
}
|
||||||
@ -122,7 +118,10 @@ func bytesToString(b []byte) (ret string, err error) {
|
|||||||
return "", fmt.Errorf("invalid value for size")
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -181,144 +180,3 @@ func bytesSplit(b []byte) ([][]byte, error) {
|
|||||||
|
|
||||||
return ret, nil
|
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
protocols.go
37
protocols.go
@ -8,11 +8,12 @@ import (
|
|||||||
|
|
||||||
// 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 // a size of -1 indicates a length-prefixed variable size
|
Size int // a size of -1 indicates a length-prefixed variable size
|
||||||
Name string
|
Name string
|
||||||
VCode []byte
|
VCode []byte
|
||||||
Path bool // indicates a path protocol (eg unix, http)
|
Path bool // indicates a path protocol (eg unix, http)
|
||||||
|
Transcoder Transcoder
|
||||||
}
|
}
|
||||||
|
|
||||||
// replicating table here to:
|
// replicating table here to:
|
||||||
@ -42,20 +43,20 @@ const (
|
|||||||
|
|
||||||
// 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", CodeToVarint(P_IP4), false},
|
Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false, TranscoderIP4},
|
||||||
Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false},
|
Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false, TranscoderPort},
|
||||||
Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false},
|
Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false, TranscoderPort},
|
||||||
Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false},
|
Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false, TranscoderPort},
|
||||||
Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false},
|
Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false, TranscoderIP6},
|
||||||
// these require varint:
|
// these require varint:
|
||||||
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false},
|
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false, TranscoderPort},
|
||||||
Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false},
|
Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false, TranscoderOnion},
|
||||||
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false},
|
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false, nil},
|
||||||
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false},
|
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false, nil},
|
||||||
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false},
|
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false, nil},
|
||||||
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false},
|
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false, nil},
|
||||||
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS), false},
|
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS), false, TranscoderIPFS},
|
||||||
Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true},
|
Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true, TranscoderUnix},
|
||||||
}
|
}
|
||||||
|
|
||||||
func AddProtocol(p Protocol) error {
|
func AddProtocol(p Protocol) error {
|
||||||
|
175
transcoders.go
Normal file
175
transcoders.go
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package multiaddr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/base32"
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
mh "github.com/multiformats/go-multihash"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Transcoder interface {
|
||||||
|
StringToBytes(string) ([]byte, error)
|
||||||
|
BytesToString([]byte) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type twrp struct {
|
||||||
|
strtobyte func(string) ([]byte, error)
|
||||||
|
bytetostr func([]byte) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t twrp) StringToBytes(s string) ([]byte, error) {
|
||||||
|
return t.strtobyte(s)
|
||||||
|
}
|
||||||
|
func (t twrp) BytesToString(b []byte) (string, error) {
|
||||||
|
return t.bytetostr(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderIP4 = (Transcoder)(twrp{ip4StB, ipBtS})
|
||||||
|
var TranscoderIP6 = (Transcoder)(twrp{ip6StB, ipBtS})
|
||||||
|
|
||||||
|
func ip4StB(s string) ([]byte, error) {
|
||||||
|
i := net.ParseIP(s).To4()
|
||||||
|
if i == nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ip6StB(s string) ([]byte, error) {
|
||||||
|
i := net.ParseIP(s).To16()
|
||||||
|
if i == nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
|
||||||
|
}
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipBtS(b []byte) (string, error) {
|
||||||
|
return net.IP(b).String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderPort = (Transcoder)(twrp{portStB, portBtS})
|
||||||
|
|
||||||
|
func portStB(s string) ([]byte, error) {
|
||||||
|
i, err := strconv.Atoi(s)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse port addr: %s", err)
|
||||||
|
}
|
||||||
|
if i >= 65536 {
|
||||||
|
return nil, fmt.Errorf("failed to parse port addr: %s", "greater than 65536")
|
||||||
|
}
|
||||||
|
b := make([]byte, 2)
|
||||||
|
binary.BigEndian.PutUint16(b, uint16(i))
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func portBtS(b []byte) (string, error) {
|
||||||
|
i := binary.BigEndian.Uint16(b)
|
||||||
|
return strconv.Itoa(int(i)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderOnion = (Transcoder)(twrp{onionStB, onionBtS})
|
||||||
|
|
||||||
|
func onionStB(s string) ([]byte, error) {
|
||||||
|
addr := strings.Split(s, ":")
|
||||||
|
if len(addr) != 2 {
|
||||||
|
return nil, fmt.Errorf("failed to parse onion addr: %s does not contain a port number.", s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// onion address without the ".onion" substring
|
||||||
|
if len(addr[0]) != 16 {
|
||||||
|
return nil, fmt.Errorf("failed to parse onion addr: %s not a Tor onion address.", s)
|
||||||
|
}
|
||||||
|
onionHostBytes, err := base32.StdEncoding.DecodeString(strings.ToUpper(addr[0]))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode base32 onion addr: %s %s", s, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// onion port number
|
||||||
|
i, err := strconv.Atoi(addr[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse onion addr: %s", err)
|
||||||
|
}
|
||||||
|
if i >= 65536 {
|
||||||
|
return nil, fmt.Errorf("failed to parse onion addr: %s", "port greater than 65536")
|
||||||
|
}
|
||||||
|
if i < 1 {
|
||||||
|
return nil, fmt.Errorf("failed to parse onion addr: %s", "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
|
||||||
|
}
|
||||||
|
|
||||||
|
func onionBtS(b []byte) (string, error) {
|
||||||
|
addr := strings.ToLower(base32.StdEncoding.EncodeToString(b[0:10]))
|
||||||
|
port := binary.BigEndian.Uint16(b[10:12])
|
||||||
|
return addr + ":" + strconv.Itoa(int(port)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderIPFS = (Transcoder)(twrp{ipfsStB, ipfsBtS})
|
||||||
|
|
||||||
|
func ipfsStB(s string) ([]byte, error) {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
func ipfsBtS(b []byte) (string, error) {
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
var TranscoderUnix = (Transcoder)(twrp{unixStB, unixBtS})
|
||||||
|
|
||||||
|
func unixStB(s string) ([]byte, error) {
|
||||||
|
// the address is the whole remaining string, prefixed by a varint len
|
||||||
|
size := CodeToVarint(len(s))
|
||||||
|
b := append(size, []byte(s)...)
|
||||||
|
return b, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func unixBtS(b []byte) (string, error) {
|
||||||
|
// 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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user