Commit 1ae13209 authored by Steven Allen's avatar Steven Allen

refactor the protocol definition files

Also use `AddProtocol` for *all* protocols (even predefined ones).
parent 66883764
package multiaddr
import (
"fmt"
"strings"
)
// These are special sizes
const (
LengthPrefixedVarSize = -1
)
// Protocol is a Multiaddr protocol description structure.
type Protocol struct {
// Name is the string representation of the protocol code. E.g., ip4,
// ip6, tcp, udp, etc.
Name string
// Code is the protocol's multicodec (a normal, non-varint number).
Code int
// VCode is a precomputed varint encoded version of Code.
VCode []byte
// Size is the size of the argument to this protocol.
//
// * Size == 0 means this protocol takes no argument.
// * Size > 0 means this protocol takes a constant sized argument.
// * Size < 0 means this protocol takes a variable length, varint
// prefixed argument.
Size int // a size of -1 indicates a length-prefixed variable size
// Path indicates a path protocol (e.g., unix). When parsing multiaddr
// strings, path protocols consume the remainder of the address instead
// of stopping at the next forward slash.
//
// Size must be LengthPrefixedVarSize.
Path bool
// Transcoder converts between the byte representation and the string
// representation of this protocol's argument (if any).
//
// This should only be non-nil if Size != 0
Transcoder Transcoder
}
var protocolsByName = map[string]Protocol{}
var protocolsByCode = map[int]Protocol{}
// Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []Protocol{}
// SwapToP2pMultiaddrs is a function to make the transition from /ipfs/...
// multiaddrs to /p2p/... multiaddrs easier
// The first stage of the rollout is to ship this package to all users so
// that all users of multiaddr can parse both /ipfs/ and /p2p/ multiaddrs
// as the same code (P_P2P). During this stage of the rollout, all addresses
// with P_P2P will continue printing as /ipfs/, so that older clients without
// the new parsing code won't break.
// Once the network has adopted the new parsing code broadly enough, users of
// multiaddr can add a call to this method to an init function in their codebase.
// This will cause any P_P2P multiaddr to print out as /p2p/ instead of /ipfs/.
// Note that the binary serialization of this multiaddr does not change at any
// point. This means that this code is not a breaking network change at any point
func SwapToP2pMultiaddrs() {
for i := range Protocols {
if Protocols[i].Code == P_P2P {
Protocols[i].Name = "p2p"
break
}
}
protoP2P.Name = "p2p"
protocolsByName["ipfs"] = protoP2P
protocolsByName["p2p"] = protoP2P
protocolsByCode[protoP2P.Code] = protoP2P
}
func AddProtocol(p Protocol) error {
if _, ok := protocolsByName[p.Name]; ok {
return fmt.Errorf("protocol by the name %q already exists", p.Name)
}
if _, ok := protocolsByCode[p.Code]; ok {
return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code)
}
if p.Size != 0 && p.Transcoder == nil {
return fmt.Errorf("protocols with arguments must define transcoders")
}
if p.Path && p.Size >= 0 {
return fmt.Errorf("path protocols must have variable-length sizes")
}
Protocols = append(Protocols, p)
protocolsByName[p.Name] = p
protocolsByCode[p.Code] = p
return nil
}
// ProtocolWithName returns the Protocol description with given string name.
func ProtocolWithName(s string) Protocol {
return protocolsByName[s]
}
// ProtocolWithCode returns the Protocol description with given protocol code.
func ProtocolWithCode(c int) Protocol {
return protocolsByCode[c]
}
// 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
}
package multiaddr
import (
"encoding/binary"
"fmt"
"math/bits"
"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.
//
......@@ -40,161 +23,126 @@ const (
P_ONION = 0x01BC
)
// These are special sizes
const (
LengthPrefixedVarSize = -1
)
// Protocols is the list of multiaddr protocols supported by this module.
var Protocols = []Protocol{
protoIP4,
protoTCP,
protoUDP,
protoDCCP,
protoIP6,
protoSCTP,
protoONION,
protoUTP,
protoUDT,
protoQUIC,
protoHTTP,
protoHTTPS,
protoP2P,
protoUNIX,
}
var (
protoIP4 = Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false, TranscoderIP4}
protoTCP = Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false, TranscoderPort}
protoUDP = Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false, TranscoderPort}
protoDCCP = Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false, TranscoderPort}
protoIP6 = Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false, TranscoderIP6}
protoIP4 = Protocol{
Name: "ip4",
Code: P_IP4,
VCode: CodeToVarint(P_IP4),
Size: 32,
Path: false,
Transcoder: TranscoderIP4,
}
protoTCP = Protocol{
Name: "tcp",
Code: P_TCP,
VCode: CodeToVarint(P_TCP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoUDP = Protocol{
Name: "udp",
Code: P_UDP,
VCode: CodeToVarint(P_UDP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoDCCP = Protocol{
Name: "dccp",
Code: P_DCCP,
VCode: CodeToVarint(P_DCCP),
Size: 16,
Path: false,
Transcoder: TranscoderPort,
}
protoIP6 = Protocol{
Name: "ip6",
Code: P_IP6,
VCode: CodeToVarint(P_IP6),
Size: 128,
Transcoder: TranscoderIP6,
}
// these require varint
protoSCTP = Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false, TranscoderPort}
protoONION = Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false, TranscoderOnion}
protoUTP = Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false, nil}
protoUDT = Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false, nil}
protoQUIC = Protocol{P_QUIC, 0, "quic", CodeToVarint(P_QUIC), false, nil}
protoHTTP = Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false, nil}
protoHTTPS = Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false, nil}
protoP2P = Protocol{P_P2P, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_P2P), false, TranscoderP2P}
protoUNIX = Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true, TranscoderUnix}
)
var protocolsByName = map[string]Protocol{}
var protocolsByCode = map[int]Protocol{}
func init() {
for _, p := range Protocols {
protocolsByName[p.Name] = p
protocolsByCode[p.Code] = p
protoSCTP = Protocol{
Name: "sctp",
Code: P_SCTP,
VCode: CodeToVarint(P_SCTP),
Size: 16,
Transcoder: TranscoderPort,
}
// explicitly set both of these
protocolsByName["p2p"] = protoP2P
protocolsByName["ipfs"] = protoP2P
}
// SwapToP2pMultiaddrs is a function to make the transition from /ipfs/...
// multiaddrs to /p2p/... multiaddrs easier
// The first stage of the rollout is to ship this package to all users so
// that all users of multiaddr can parse both /ipfs/ and /p2p/ multiaddrs
// as the same code (P_P2P). During this stage of the rollout, all addresses
// with P_P2P will continue printing as /ipfs/, so that older clients without
// the new parsing code won't break.
// Once the network has adopted the new parsing code broadly enough, users of
// multiaddr can add a call to this method to an init function in their codebase.
// This will cause any P_P2P multiaddr to print out as /p2p/ instead of /ipfs/.
// Note that the binary serialization of this multiaddr does not change at any
// point. This means that this code is not a breaking network change at any point
func SwapToP2pMultiaddrs() {
for i := range Protocols {
if Protocols[i].Code == P_P2P {
Protocols[i].Name = "p2p"
break
}
protoONION = Protocol{
Name: "onion",
Code: P_ONION,
VCode: CodeToVarint(P_ONION),
Size: 96,
Transcoder: TranscoderOnion,
}
protoP2P.Name = "p2p"
protocolsByName["ipfs"] = protoP2P
protocolsByName["p2p"] = protoP2P
protocolsByCode[protoP2P.Code] = protoP2P
}
func AddProtocol(p Protocol) error {
if _, ok := protocolsByName[p.Name]; ok {
return fmt.Errorf("protocol by the name %q already exists", p.Name)
protoUTP = Protocol{
Name: "utp",
Code: P_UTP,
VCode: CodeToVarint(P_UTP),
}
if _, ok := protocolsByCode[p.Code]; ok {
return fmt.Errorf("protocol code %d already taken by %q", p.Code, p.Code)
protoUDT = Protocol{
Name: "udt",
Code: P_UDT,
VCode: CodeToVarint(P_UDT),
}
if p.Size != 0 && p.Transcoder == nil {
return fmt.Errorf("protocols with arguments must define transcoders")
protoQUIC = Protocol{
Name: "quic",
Code: P_QUIC,
VCode: CodeToVarint(P_QUIC),
}
if p.Path && p.Size >= 0 {
return fmt.Errorf("path protocols must have variable-length sizes")
protoHTTP = Protocol{
Name: "http",
Code: P_HTTP,
VCode: CodeToVarint(P_HTTP),
}
Protocols = append(Protocols, p)
protocolsByName[p.Name] = p
protocolsByCode[p.Code] = p
return nil
}
// ProtocolWithName returns the Protocol description with given string name.
func ProtocolWithName(s string) Protocol {
return protocolsByName[s]
}
// ProtocolWithCode returns the Protocol description with given protocol code.
func ProtocolWithCode(c int) Protocol {
return protocolsByCode[c]
}
// 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
protoHTTPS = Protocol{
Name: "https",
Code: P_HTTPS,
VCode: CodeToVarint(P_HTTPS),
}
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
protoP2P = Protocol{
Name: "ipfs",
Code: P_P2P,
VCode: CodeToVarint(P_P2P),
Size: LengthPrefixedVarSize,
Transcoder: TranscoderP2P,
}
return t, nil
}
// CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte {
buf := make([]byte, bits.Len(uint(num))/7+1)
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)
protoUNIX = Protocol{
Name: "unix",
Code: P_UNIX,
VCode: CodeToVarint(P_UNIX),
Size: LengthPrefixedVarSize,
Path: true,
Transcoder: TranscoderUnix,
}
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")
func init() {
for _, p := range []Protocol{
protoIP4,
protoTCP,
protoUDP,
protoDCCP,
protoIP6,
protoSCTP,
protoONION,
protoUTP,
protoUDT,
protoQUIC,
protoHTTP,
protoHTTPS,
protoP2P,
protoUNIX,
} {
if err := AddProtocol(p); err != nil {
panic(err)
}
}
return int(num), n, nil
// explicitly set both of these
protocolsByName["p2p"] = protoP2P
protocolsByName["ipfs"] = protoP2P
}
package multiaddr
import (
"encoding/binary"
"fmt"
"math/bits"
)
// VarintSize returns the size (in bytes) of `num` encoded as a varint.
func VarintSize(num int) int {
return bits.Len(uint(num))/7 + 1
}
// CodeToVarint converts an integer to a varint-encoded []byte
func CodeToVarint(num int) []byte {
buf := make([]byte, bits.Len(uint(num))/7+1)
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
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment