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

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
3
import (
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
4 5
	"fmt"
	"strings"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
6 7
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
8
type Multiaddr struct {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
9
	Bytes []byte
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
func NewMultiaddr(s string) (*Multiaddr, error) {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
13 14 15 16 17
	b, err := StringToBytes(s)
	if err != nil {
		return nil, err
	}
	return &Multiaddr{Bytes: b}, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
18
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
19 20

func (m *Multiaddr) String() (string, error) {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
21
	return BytesToString(m.Bytes)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
22 23 24 25
}

func (m *Multiaddr) Protocols() (ret []*Protocol, err error) {

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
26 27 28 29 30 31 32
	// panic handler, in case we try accessing bytes incorrectly.
	defer func() {
		if e := recover(); e != nil {
			ret = nil
			err = e.(error)
		}
	}()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
34 35 36 37 38 39 40 41 42 43 44
	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
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46 47

func (m *Multiaddr) Encapsulate(o *Multiaddr) *Multiaddr {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
48 49 50
	b := make([]byte, len(m.Bytes)+len(o.Bytes))
	b = append(m.Bytes, o.Bytes...)
	return &Multiaddr{Bytes: b}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
51 52 53
}

func (m *Multiaddr) Decapsulate(o *Multiaddr) (*Multiaddr, error) {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
54 55 56 57
	s1, err := m.String()
	if err != nil {
		return nil, err
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
58

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
59 60 61 62
	s2, err := o.String()
	if err != nil {
		return nil, err
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
63

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
64 65 66 67 68
	i := strings.LastIndex(s1, s2)
	if i < 0 {
		return nil, fmt.Errorf("%s not contained in %s", s2, s1)
	}
	return NewMultiaddr(s1[:i])
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

func (m *Multiaddr) DialArgs() (string, string, error) {
	if !m.IsThinWaist() {
		return "", "", fmt.Errorf("%s is not a 'thin waist' address.", m)
	}

	str, err := m.String()
	if err != nil {
		return "", "", err
	}

	parts := strings.Split(str, "/")[1:]
	network := parts[2]
	host := strings.Join([]string{parts[1], parts[3]}, ":")
	return network, host, nil
}

func (m *Multiaddr) IsThinWaist() bool {
	p, err := m.Protocols()
	if err != nil {
		return false
	}

	if p[0].Code != P_IP4 && p[0].Code != P_IP6 {
		return false
	}

	if p[1].Code != P_TCP && p[1].Code != P_UDP {
		return false
	}

	return true
}