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

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

9
// Protocol is a Multiaddr protocol description structure.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10
type Protocol struct {
11 12 13 14 15 16
	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
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17 18 19 20 21 22
}

// replicating table here to:
// 1. avoid parsing the csv
// 2. ensuring errors in the csv don't screw up code.
// 3. changing a number has to happen in two places.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
23
const (
24 25 26 27 28
	P_IP4   = 4
	P_TCP   = 6
	P_UDP   = 17
	P_DCCP  = 33
	P_IP6   = 41
Marten Seemann's avatar
Marten Seemann committed
29
	P_QUIC  = 81
30 31 32
	P_SCTP  = 132
	P_UTP   = 301
	P_UDT   = 302
jbenet's avatar
jbenet committed
33
	P_UNIX  = 400
34 35 36
	P_IPFS  = 421
	P_HTTP  = 480
	P_HTTPS = 443
37
	P_ONION = 444
38 39 40 41 42
)

// These are special sizes
const (
	LengthPrefixedVarSize = -1
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
43 44
)

45
// Protocols is the list of multiaddr protocols supported by this module.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
46
var Protocols = []Protocol{
47 48 49 50 51
	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},
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
52
	// these require varint:
53 54 55 56
	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},
Marten Seemann's avatar
Marten Seemann committed
57
	Protocol{P_QUIC, 0, "quic", CodeToVarint(P_QUIC), false, nil},
58 59 60 61
	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},
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
62 63
}

Jeromy's avatar
Jeromy committed
64 65 66 67 68 69 70 71 72 73 74 75 76 77
func AddProtocol(p Protocol) error {
	for _, pt := range Protocols {
		if pt.Code == p.Code {
			return fmt.Errorf("protocol code %d already taken by %q", p.Code, pt.Name)
		}
		if pt.Name == p.Name {
			return fmt.Errorf("protocol by the name %q already exists", p.Name)
		}
	}

	Protocols = append(Protocols, p)
	return nil
}

78
// ProtocolWithName returns the Protocol description with given string name.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79
func ProtocolWithName(s string) Protocol {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
80 81 82 83 84
	for _, p := range Protocols {
		if p.Name == s {
			return p
		}
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85
	return Protocol{}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
86 87
}

88
// ProtocolWithCode returns the Protocol description with given protocol code.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89
func ProtocolWithCode(c int) Protocol {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
90 91 92 93 94
	for _, p := range Protocols {
		if p.Code == c {
			return p
		}
	}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95
	return Protocol{}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
96
}
97

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
// ProtocolsWithString returns a slice of protocols matching given string.
func ProtocolsWithString(s string) ([]Protocol, error) {
	s = strings.Trim(s, "/")
	sp := strings.Split(s, "/")
	if len(sp) == 0 {
		return nil, nil
	}

	t := make([]Protocol, len(sp))
	for i, name := range sp {
		p := ProtocolWithName(name)
		if p.Code == 0 {
			return nil, fmt.Errorf("no protocol with name: %s", name)
		}
		t[i] = p
	}
	return t, nil
}

117 118 119 120 121 122 123 124 125
// CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte {
	buf := make([]byte, (num/7)+1) // varint package is uint64
	n := binary.PutUvarint(buf, uint64(num))
	return buf[:n]
}

// VarintToCode converts a varint-encoded []byte to an integer protocol code
func VarintToCode(buf []byte) int {
126 127 128 129
	num, _, err := ReadVarintCode(buf)
	if err != nil {
		panic(err)
	}
130 131 132 133 134
	return num
}

// ReadVarintCode reads a varint code from the beginning of buf.
// returns the code, and the number of bytes read.
135
func ReadVarintCode(buf []byte) (int, int, error) {
136 137
	num, n := binary.Uvarint(buf)
	if n < 0 {
138
		return 0, 0, fmt.Errorf("varints larger than uint64 not yet supported")
139
	}
140
	return int(num), n, nil
141
}