codec.go 3.05 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2
package multiaddr

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
3 4 5 6 7 8
import (
	"encoding/binary"
	"fmt"
	"net"
	"strconv"
	"strings"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9 10
)

11
func stringToBytes(s string) ([]byte, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12 13 14 15

	// consume trailing slashes
	s = strings.TrimRight(s, "/")

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
16 17
	b := []byte{}
	sp := strings.Split(s, "/")
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18

19 20 21 22
	if sp[0] != "" {
		return nil, fmt.Errorf("invalid multiaddr, must begin with /")
	}

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
23 24
	// consume first empty elem
	sp = sp[1:]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
25

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
26 27
	for len(sp) > 0 {
		p := ProtocolWithName(sp[0])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
28
		if p.Code == 0 {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
29 30
			return nil, fmt.Errorf("no protocol with name %s", sp[0])
		}
31 32
		b = append(b, CodeToVarint(p.Code)...)
		sp = sp[1:]
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33

34
		if p.Size > 0 {
35 36 37 38 39 40 41
			if len(sp) < 1 {
				return nil, fmt.Errorf("protocol requires address, none given: %s", sp)
			}
			a, err := addressStringToBytes(p, sp[0])
			if err != nil {
				return nil, fmt.Errorf("failed to parse %s: %s %s", p.Name, sp[0], err)
			}
42 43 44
			b = append(b, a...)
			sp = sp[1:]
		}
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
45 46
	}
	return b, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47 48
}

49
func bytesToString(b []byte) (ret string, err error) {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
50 51 52 53 54 55 56 57 58 59 60
	// 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 {
61 62 63 64

		code, n := ReadVarintCode(b)
		b = b[n:]
		p := ProtocolWithCode(code)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
65
		if p.Code == 0 {
66
			return "", fmt.Errorf("no protocol with code %d", code)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
67 68 69
		}
		s = strings.Join([]string{s, "/", p.Name}, "")

70 71 72 73 74 75
		if p.Size > 0 {
			a := addressBytesToString(p, b[:(p.Size/8)])
			if len(a) > 0 {
				s = strings.Join([]string{s, "/", a}, "")
			}
			b = b[(p.Size / 8):]
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
76 77 78 79
		}
	}

	return s, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
80
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
82 83 84 85 86 87 88 89 90 91 92
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 {
93 94
		code, n := ReadVarintCode(b)
		p := ProtocolWithCode(code)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95
		if p.Code == 0 {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96 97 98
			return [][]byte{}, fmt.Errorf("no protocol with code %d", b[0])
		}

99
		length := n + (p.Size / 8)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
100 101 102 103 104 105 106
		ret = append(ret, b[:length])
		b = b[length:]
	}

	return ret, nil
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
107
func addressStringToBytes(p Protocol, s string) ([]byte, error) {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
108 109
	switch p.Code {

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
110
	case P_IP4: // ipv4
111 112 113 114 115
		i := net.ParseIP(s).To4()
		if i == nil {
			return nil, fmt.Errorf("failed to parse ip4 addr: %s", s)
		}
		return i, nil
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
116

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
117
	case P_IP6: // ipv6
118 119 120 121 122
		i := net.ParseIP(s).To16()
		if i == nil {
			return nil, fmt.Errorf("failed to parse ip6 addr: %s", s)
		}
		return i, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
123

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
124
	// tcp udp dccp sctp
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
125
	case P_TCP, P_UDP, P_DCCP, P_SCTP:
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
126
		i, err := strconv.Atoi(s)
127 128 129 130 131
		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")
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
132
		}
133 134 135
		b := make([]byte, 2)
		binary.BigEndian.PutUint16(b, uint16(i))
		return b, nil
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
136 137
	}

138
	return []byte{}, fmt.Errorf("failed to parse %s addr: unknown", p.Name)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
139 140
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
141
func addressBytesToString(p Protocol, b []byte) string {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
142
	switch p.Code {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
143

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
144
	// ipv4,6
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
145
	case P_IP4, P_IP6:
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
146
		return net.IP(b).String()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
147

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
148
	// tcp udp dccp sctp
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
149
	case P_TCP, P_UDP, P_DCCP, P_SCTP:
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
150 151 152
		i := binary.BigEndian.Uint16(b)
		return strconv.Itoa(int(i))
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
153

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
154
	return ""
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
155
}