143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
package multiaddr
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Protocol is a Multiaddr protocol description structure.
|
|
type Protocol struct {
|
|
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
|
|
}
|
|
|
|
// You **MUST** register your multicodecs with
|
|
// https://github.com/multiformats/multicodec before adding them here.
|
|
//
|
|
// TODO: Use a single source of truth for all multicodecs instead of
|
|
// distributing them like this...
|
|
const (
|
|
P_IP4 = 0x0004
|
|
P_TCP = 0x0006
|
|
P_UDP = 0x0111
|
|
P_DCCP = 0x0021
|
|
P_IP6 = 0x0029
|
|
P_QUIC = 0x01CC
|
|
P_SCTP = 0x0084
|
|
P_UDT = 0x012D
|
|
P_UTP = 0x012E
|
|
P_UNIX = 0x0190
|
|
P_IPFS = 0x01A5
|
|
P_HTTP = 0x01E0
|
|
P_HTTPS = 0x01BB
|
|
P_ONION = 0x01BC
|
|
)
|
|
|
|
// These are special sizes
|
|
const (
|
|
LengthPrefixedVarSize = -1
|
|
)
|
|
|
|
// Protocols is the list of multiaddr protocols supported by this module.
|
|
var Protocols = []Protocol{
|
|
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},
|
|
// these require varint:
|
|
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},
|
|
Protocol{P_QUIC, 0, "quic", CodeToVarint(P_QUIC), false, nil},
|
|
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},
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// ProtocolWithName returns the Protocol description with given string name.
|
|
func ProtocolWithName(s string) Protocol {
|
|
for _, p := range Protocols {
|
|
if p.Name == s {
|
|
return p
|
|
}
|
|
}
|
|
return Protocol{}
|
|
}
|
|
|
|
// ProtocolWithCode returns the Protocol description with given protocol code.
|
|
func ProtocolWithCode(c int) Protocol {
|
|
for _, p := range Protocols {
|
|
if p.Code == c {
|
|
return p
|
|
}
|
|
}
|
|
return Protocol{}
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
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) {
|
|
num, n := binary.Uvarint(buf)
|
|
if n < 0 {
|
|
return 0, 0, fmt.Errorf("varints larger than uint64 not yet supported")
|
|
}
|
|
return int(num), n, nil
|
|
}
|