2014-07-04 06:42:24 +00:00
|
|
|
package multiaddr
|
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
2015-01-18 05:12:54 +00:00
|
|
|
|
|
|
|
mh "github.com/jbenet/go-multihash"
|
2014-07-04 06:42:24 +00:00
|
|
|
)
|
|
|
|
|
2014-09-11 17:47:56 +00:00
|
|
|
func stringToBytes(s string) ([]byte, error) {
|
2014-10-11 03:40:51 +00:00
|
|
|
|
|
|
|
// consume trailing slashes
|
|
|
|
s = strings.TrimRight(s, "/")
|
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
b := []byte{}
|
|
|
|
sp := strings.Split(s, "/")
|
2014-07-04 06:42:24 +00:00
|
|
|
|
2014-09-11 17:45:20 +00:00
|
|
|
if sp[0] != "" {
|
|
|
|
return nil, fmt.Errorf("invalid multiaddr, must begin with /")
|
|
|
|
}
|
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
// consume first empty elem
|
|
|
|
sp = sp[1:]
|
2014-07-04 06:42:24 +00:00
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
for len(sp) > 0 {
|
|
|
|
p := ProtocolWithName(sp[0])
|
2015-01-09 13:37:02 +00:00
|
|
|
if p.Code == 0 {
|
2014-07-04 18:21:39 +00:00
|
|
|
return nil, fmt.Errorf("no protocol with name %s", sp[0])
|
|
|
|
}
|
2014-11-19 21:01:52 +00:00
|
|
|
b = append(b, CodeToVarint(p.Code)...)
|
|
|
|
sp = sp[1:]
|
2014-07-04 06:42:24 +00:00
|
|
|
|
2015-01-18 05:12:54 +00:00
|
|
|
if p.Size == 0 { // no length.
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(sp) < 1 {
|
|
|
|
return nil, fmt.Errorf("protocol requires address, none given: %s", p.Name)
|
|
|
|
}
|
|
|
|
a, err := addressStringToBytes(p, sp[0])
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
|
2014-11-19 21:01:52 +00:00
|
|
|
}
|
2015-01-18 05:12:54 +00:00
|
|
|
b = append(b, a...)
|
|
|
|
sp = sp[1:]
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
|
|
|
return b, nil
|
2014-07-04 06:42:24 +00:00
|
|
|
}
|
|
|
|
|
2014-09-11 17:47:56 +00:00
|
|
|
func bytesToString(b []byte) (ret string, err error) {
|
2014-07-04 18:21:39 +00:00
|
|
|
// panic handler, in case we try accessing bytes incorrectly.
|
|
|
|
defer func() {
|
|
|
|
if e := recover(); e != nil {
|
|
|
|
ret = ""
|
|
|
|
err = e.(error)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
s := ""
|
|
|
|
|
|
|
|
for len(b) > 0 {
|
2014-11-19 21:01:52 +00:00
|
|
|
|
|
|
|
code, n := ReadVarintCode(b)
|
|
|
|
b = b[n:]
|
|
|
|
p := ProtocolWithCode(code)
|
2015-01-09 13:37:02 +00:00
|
|
|
if p.Code == 0 {
|
2014-11-19 21:01:52 +00:00
|
|
|
return "", fmt.Errorf("no protocol with code %d", code)
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
|
|
|
s = strings.Join([]string{s, "/", p.Name}, "")
|
|
|
|
|
2015-01-18 05:12:54 +00:00
|
|
|
if p.Size == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
a, err := addressBytesToString(p, b[:(p.Size/8)])
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
if len(a) > 0 {
|
|
|
|
s = strings.Join([]string{s, "/", a}, "")
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
2015-01-18 05:12:54 +00:00
|
|
|
b = b[(p.Size / 8):]
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return s, nil
|
2014-07-04 06:42:24 +00:00
|
|
|
}
|
2014-07-04 06:44:09 +00:00
|
|
|
|
2014-11-05 07:20:17 +00:00
|
|
|
func bytesSplit(b []byte) (ret [][]byte, err error) {
|
|
|
|
// panic handler, in case we try accessing bytes incorrectly.
|
|
|
|
defer func() {
|
|
|
|
if e := recover(); e != nil {
|
|
|
|
ret = [][]byte{}
|
|
|
|
err = e.(error)
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
ret = [][]byte{}
|
|
|
|
for len(b) > 0 {
|
2014-11-19 21:01:52 +00:00
|
|
|
code, n := ReadVarintCode(b)
|
|
|
|
p := ProtocolWithCode(code)
|
2015-01-09 13:37:02 +00:00
|
|
|
if p.Code == 0 {
|
2014-11-05 07:20:17 +00:00
|
|
|
return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
|
|
|
|
}
|
|
|
|
|
2014-11-19 21:01:52 +00:00
|
|
|
length := n + (p.Size / 8)
|
2014-11-05 07:20:17 +00:00
|
|
|
ret = append(ret, b[:length])
|
|
|
|
b = b[length:]
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
2015-01-09 13:37:02 +00:00
|
|
|
func addressStringToBytes(p Protocol, s string) ([]byte, error) {
|
2014-07-04 18:21:39 +00:00
|
|
|
switch p.Code {
|
|
|
|
|
2014-09-13 11:47:37 +00:00
|
|
|
case P_IP4: // ipv4
|
2015-01-09 13:30:33 +00:00
|
|
|
i := net.ParseIP(s).To4()
|
|
|
|
if i == nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
|
|
|
|
}
|
|
|
|
return i, nil
|
2014-07-04 18:21:39 +00:00
|
|
|
|
2014-09-13 11:47:37 +00:00
|
|
|
case P_IP6: // ipv6
|
2015-01-09 13:30:33 +00:00
|
|
|
i := net.ParseIP(s).To16()
|
|
|
|
if i == nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
|
|
|
|
}
|
|
|
|
return i, nil
|
2014-09-13 11:47:37 +00:00
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
// tcp udp dccp sctp
|
2014-09-13 11:47:37 +00:00
|
|
|
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
2014-07-04 18:21:39 +00:00
|
|
|
i, err := strconv.Atoi(s)
|
2015-01-09 13:30:33 +00:00
|
|
|
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")
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
2015-01-09 13:30:33 +00:00
|
|
|
b := make([]byte, 2)
|
|
|
|
binary.BigEndian.PutUint16(b, uint16(i))
|
|
|
|
return b, nil
|
2015-01-18 05:12:54 +00:00
|
|
|
|
|
|
|
case P_IPFS: // ipfs
|
|
|
|
// the address is a multihash string representation
|
|
|
|
m, err := mh.FromB58String(s)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to parse ipfs addr: %s %s", s, err)
|
|
|
|
}
|
|
|
|
return []byte(m), nil
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
|
|
|
|
2015-01-09 13:30:33 +00:00
|
|
|
return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name)
|
2014-07-04 06:44:09 +00:00
|
|
|
}
|
|
|
|
|
2015-01-18 05:12:54 +00:00
|
|
|
func addressBytesToString(p Protocol, b []byte) (string, error) {
|
2014-07-04 18:21:39 +00:00
|
|
|
switch p.Code {
|
2014-07-04 06:44:09 +00:00
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
// ipv4,6
|
2014-09-13 11:47:37 +00:00
|
|
|
case P_IP4, P_IP6:
|
2015-01-18 05:12:54 +00:00
|
|
|
return net.IP(b).String(), nil
|
2014-07-04 06:44:09 +00:00
|
|
|
|
2014-07-04 18:21:39 +00:00
|
|
|
// tcp udp dccp sctp
|
2014-09-13 11:47:37 +00:00
|
|
|
case P_TCP, P_UDP, P_DCCP, P_SCTP:
|
2014-07-04 18:21:39 +00:00
|
|
|
i := binary.BigEndian.Uint16(b)
|
2015-01-18 05:12:54 +00:00
|
|
|
return strconv.Itoa(int(i)), nil
|
|
|
|
|
|
|
|
case P_IPFS: // ipfs
|
|
|
|
// the address is a multihash string representation
|
|
|
|
m, err := mh.Cast(b)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
return m.B58String(), nil
|
2014-07-04 18:21:39 +00:00
|
|
|
}
|
2014-07-04 06:44:09 +00:00
|
|
|
|
2015-01-18 05:12:54 +00:00
|
|
|
return "", fmt.Errorf("unknown protocol")
|
2014-07-04 06:44:09 +00:00
|
|
|
}
|