mirror of
https://github.com/logos-messaging/go-multiaddr.git
synced 2026-01-04 05:53:05 +00:00
Merge pull request #73 from multiformats/feat/better-protocol
add protocol by code map
This commit is contained in:
commit
d6ad8896de
6
codec.go
6
codec.go
@ -155,12 +155,6 @@ func sizeForAddr(p Protocol, b []byte) (skip, size int, err error) {
|
|||||||
return 0, (p.Size / 8), nil
|
return 0, (p.Size / 8), nil
|
||||||
case p.Size == 0:
|
case p.Size == 0:
|
||||||
return 0, 0, nil
|
return 0, 0, nil
|
||||||
case p.Path:
|
|
||||||
size, n, err := ReadVarintCode(b)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, err
|
|
||||||
}
|
|
||||||
return n, size, nil
|
|
||||||
default:
|
default:
|
||||||
size, n, err := ReadVarintCode(b)
|
size, n, err := ReadVarintCode(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
129
protocol.go
Normal file
129
protocol.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
275
protocols.go
275
protocols.go
@ -1,22 +1,5 @@
|
|||||||
package multiaddr
|
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
|
// You **MUST** register your multicodecs with
|
||||||
// https://github.com/multiformats/multicodec before adding them here.
|
// https://github.com/multiformats/multicodec before adding them here.
|
||||||
//
|
//
|
||||||
@ -40,156 +23,126 @@ const (
|
|||||||
P_ONION = 0x01BC
|
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 (
|
var (
|
||||||
protoIP4 = Protocol{P_IP4, 32, "ip4", CodeToVarint(P_IP4), false, TranscoderIP4}
|
protoIP4 = Protocol{
|
||||||
protoTCP = Protocol{P_TCP, 16, "tcp", CodeToVarint(P_TCP), false, TranscoderPort}
|
Name: "ip4",
|
||||||
protoUDP = Protocol{P_UDP, 16, "udp", CodeToVarint(P_UDP), false, TranscoderPort}
|
Code: P_IP4,
|
||||||
protoDCCP = Protocol{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP), false, TranscoderPort}
|
VCode: CodeToVarint(P_IP4),
|
||||||
protoIP6 = Protocol{P_IP6, 128, "ip6", CodeToVarint(P_IP6), false, TranscoderIP6}
|
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
|
// these require varint
|
||||||
protoSCTP = Protocol{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP), false, TranscoderPort}
|
protoSCTP = Protocol{
|
||||||
protoONION = Protocol{P_ONION, 96, "onion", CodeToVarint(P_ONION), false, TranscoderOnion}
|
Name: "sctp",
|
||||||
protoUTP = Protocol{P_UTP, 0, "utp", CodeToVarint(P_UTP), false, nil}
|
Code: P_SCTP,
|
||||||
protoUDT = Protocol{P_UDT, 0, "udt", CodeToVarint(P_UDT), false, nil}
|
VCode: CodeToVarint(P_SCTP),
|
||||||
protoQUIC = Protocol{P_QUIC, 0, "quic", CodeToVarint(P_QUIC), false, nil}
|
Size: 16,
|
||||||
protoHTTP = Protocol{P_HTTP, 0, "http", CodeToVarint(P_HTTP), false, nil}
|
Transcoder: TranscoderPort,
|
||||||
protoHTTPS = Protocol{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS), false, nil}
|
}
|
||||||
protoP2P = Protocol{P_P2P, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_P2P), false, TranscoderP2P}
|
protoONION = Protocol{
|
||||||
protoUNIX = Protocol{P_UNIX, LengthPrefixedVarSize, "unix", CodeToVarint(P_UNIX), true, TranscoderUnix}
|
Name: "onion",
|
||||||
|
Code: P_ONION,
|
||||||
|
VCode: CodeToVarint(P_ONION),
|
||||||
|
Size: 96,
|
||||||
|
Transcoder: TranscoderOnion,
|
||||||
|
}
|
||||||
|
protoUTP = Protocol{
|
||||||
|
Name: "utp",
|
||||||
|
Code: P_UTP,
|
||||||
|
VCode: CodeToVarint(P_UTP),
|
||||||
|
}
|
||||||
|
protoUDT = Protocol{
|
||||||
|
Name: "udt",
|
||||||
|
Code: P_UDT,
|
||||||
|
VCode: CodeToVarint(P_UDT),
|
||||||
|
}
|
||||||
|
protoQUIC = Protocol{
|
||||||
|
Name: "quic",
|
||||||
|
Code: P_QUIC,
|
||||||
|
VCode: CodeToVarint(P_QUIC),
|
||||||
|
}
|
||||||
|
protoHTTP = Protocol{
|
||||||
|
Name: "http",
|
||||||
|
Code: P_HTTP,
|
||||||
|
VCode: CodeToVarint(P_HTTP),
|
||||||
|
}
|
||||||
|
protoHTTPS = Protocol{
|
||||||
|
Name: "https",
|
||||||
|
Code: P_HTTPS,
|
||||||
|
VCode: CodeToVarint(P_HTTPS),
|
||||||
|
}
|
||||||
|
protoP2P = Protocol{
|
||||||
|
Name: "ipfs",
|
||||||
|
Code: P_P2P,
|
||||||
|
VCode: CodeToVarint(P_P2P),
|
||||||
|
Size: LengthPrefixedVarSize,
|
||||||
|
Transcoder: TranscoderP2P,
|
||||||
|
}
|
||||||
|
protoUNIX = Protocol{
|
||||||
|
Name: "unix",
|
||||||
|
Code: P_UNIX,
|
||||||
|
VCode: CodeToVarint(P_UNIX),
|
||||||
|
Size: LengthPrefixedVarSize,
|
||||||
|
Path: true,
|
||||||
|
Transcoder: TranscoderUnix,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var ProtocolsByName = map[string]Protocol{}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, p := range Protocols {
|
for _, p := range []Protocol{
|
||||||
ProtocolsByName[p.Name] = p
|
protoIP4,
|
||||||
|
protoTCP,
|
||||||
|
protoUDP,
|
||||||
|
protoDCCP,
|
||||||
|
protoIP6,
|
||||||
|
protoSCTP,
|
||||||
|
protoONION,
|
||||||
|
protoUTP,
|
||||||
|
protoUDT,
|
||||||
|
protoQUIC,
|
||||||
|
protoHTTP,
|
||||||
|
protoHTTPS,
|
||||||
|
protoP2P,
|
||||||
|
protoUNIX,
|
||||||
|
} {
|
||||||
|
if err := AddProtocol(p); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// explicitly set both of these
|
// explicitly set both of these
|
||||||
ProtocolsByName["p2p"] = protoP2P
|
protocolsByName["p2p"] = protoP2P
|
||||||
ProtocolsByName["ipfs"] = 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protoP2P.Name = "p2p"
|
|
||||||
|
|
||||||
ProtocolsByName["ipfs"] = protoP2P
|
|
||||||
ProtocolsByName["p2p"] = protoP2P
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
ProtocolsByName[p.Name] = 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 {
|
|
||||||
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, 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
|
|
||||||
}
|
}
|
||||||
|
|||||||
38
varint.go
Normal file
38
varint.go
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user