go-multiaddr/protocols.go

139 lines
3.5 KiB
Go
Raw Normal View History

2014-07-03 23:42:24 -07:00
package multiaddr
2014-11-19 13:01:52 -08:00
import (
"encoding/binary"
2015-01-09 05:51:16 -08:00
"fmt"
"strings"
2014-11-19 13:01:52 -08:00
)
2014-09-11 10:47:56 -07:00
// Protocol is a Multiaddr protocol description structure.
2014-07-03 23:42:24 -07:00
type Protocol struct {
2014-11-19 13:01:52 -08:00
Code int
2015-01-17 21:12:54 -08:00
Size int // a size of -1 indicates a length-prefixed variable size
2014-11-19 13:01:52 -08:00
Name string
VCode []byte
2016-09-12 02:03:41 -04:00
Path bool // indicates a path protocol (eg unix, http)
2014-07-03 23:42:24 -07:00
}
// 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.
2014-07-07 01:25:20 -07:00
const (
2015-01-17 21:12:54 -08:00
P_IP4 = 4
P_TCP = 6
P_UDP = 17
P_DCCP = 33
P_IP6 = 41
P_SCTP = 132
P_UTP = 301
P_UDT = 302
2016-09-12 02:03:41 -04:00
P_UNIX = 400
2015-01-17 21:12:54 -08:00
P_IPFS = 421
P_HTTP = 480
P_HTTPS = 443
P_ONION = 444
2015-01-17 21:12:54 -08:00
)
// These are special sizes
const (
LengthPrefixedVarSize = -1
2014-07-07 01:25:20 -07:00
)
2014-09-11 10:47:56 -07:00
// Protocols is the list of multiaddr protocols supported by this module.
2015-01-09 05:37:02 -08:00
var Protocols = []Protocol{
2016-09-12 02:03:41 -04:00
Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false},
Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false},
Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false},
Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false},
Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false},
2014-07-04 11:21:39 -07:00
// these require varint:
2016-09-12 02:03:41 -04:00
Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false},
Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false},
Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false},
Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false},
Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false},
Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false},
Protocol{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS), false},
Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true},
2014-07-03 23:42:24 -07:00
}
2016-01-17 01:04:37 -08:00
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
}
2014-09-11 10:47:56 -07:00
// ProtocolWithName returns the Protocol description with given string name.
2015-01-09 05:37:02 -08:00
func ProtocolWithName(s string) Protocol {
2014-07-04 11:21:39 -07:00
for _, p := range Protocols {
if p.Name == s {
return p
}
}
2015-01-09 05:37:02 -08:00
return Protocol{}
2014-07-03 23:42:24 -07:00
}
2014-09-11 10:47:56 -07:00
// ProtocolWithCode returns the Protocol description with given protocol code.
2015-01-09 05:37:02 -08:00
func ProtocolWithCode(c int) Protocol {
2014-07-04 11:21:39 -07:00
for _, p := range Protocols {
if p.Code == c {
return p
}
}
2015-01-09 05:37:02 -08:00
return Protocol{}
2014-07-03 23:42:24 -07:00
}
2014-11-19 13:01:52 -08:00
2015-01-09 05:51:16 -08:00
// 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
}
2014-11-19 13:01:52 -08:00
// 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 {
num, _, err := ReadVarintCode(buf)
if err != nil {
panic(err)
}
2014-11-19 13:01:52 -08:00
return num
}
// ReadVarintCode reads a varint code from the beginning of buf.
// returns the code, and the number of bytes read.
func ReadVarintCode(buf []byte) (int, int, error) {
2014-11-19 13:01:52 -08:00
num, n := binary.Uvarint(buf)
if n < 0 {
return 0, 0, fmt.Errorf("varints larger than uint64 not yet supported")
2014-11-19 13:01:52 -08:00
}
return int(num), n, nil
2014-11-19 13:01:52 -08:00
}