Created
May 16, 2016 09:19
-
-
Save erde74/5bd7d91070791142c929258fee8d887b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module multiaddr.protocols; | |
import std.algorithm; | |
import std.bitmanip; | |
import std.conv; | |
import std.format; | |
import std.string; | |
import std.typecons; | |
// Protocol is a Multiaddr protocol description structure. | |
struct Protocol { | |
int Code; | |
int Size; // a size of -1 indicates a length-prefixed variable size | |
string Name; | |
byte[] VCode; | |
} | |
// 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. | |
enum P_IP4 = 4; | |
enum P_TCP = 6; | |
enum P_UDP = 17; | |
enum P_DCCP = 33; | |
enum P_IP6 = 41; | |
enum P_SCTP = 132; | |
enum P_UTP = 301; | |
enum P_UDT = 302; | |
enum P_IPFS = 421; | |
enum P_HTTP = 480; | |
enum P_HTTPS = 443; | |
enum P_ONION = 444; | |
// These are special sizes | |
enum LengthPrefixedVarSize = -1; | |
// Protocols is the list of multiaddr protocols supported by this module. | |
Protocol[] Protocols = [ | |
{P_IP4, 32, "ip4", CodeToVarint(P_IP4)}, | |
{P_TCP, 16, "tcp", CodeToVarint(P_TCP)}, | |
{P_UDP, 16, "udp", CodeToVarint(P_UDP)}, | |
{P_DCCP, 16, "dccp", CodeToVarint(P_DCCP)}, | |
{P_IP6, 128, "ip6", CodeToVarint(P_IP6)}, | |
// these require varint: | |
{P_SCTP, 16, "sctp", CodeToVarint(P_SCTP)}, | |
{P_ONION, 80, "onion", CodeToVarint(P_ONION)}, | |
{P_UTP, 0, "utp", CodeToVarint(P_UTP)}, | |
{P_UDT, 0, "udt", CodeToVarint(P_UDT)}, | |
{P_HTTP, 0, "http", CodeToVarint(P_HTTP)}, | |
{P_HTTPS, 0, "https", CodeToVarint(P_HTTPS)}, | |
{P_IPFS, LengthPrefixedVarSize, "ipfs", CodeToVarint(P_IPFS)}, | |
]; | |
string AddProtocol(Protocol p) { | |
foreach (pt; Protocols) { | |
if (pt.Code == p.Code) { | |
return format("protocol code %d already taken by %s", p.Code, pt.Name); | |
} | |
if (pt.Name == p.Name) { | |
return format("protocol by the name %s already exists", p.Name); | |
} | |
} | |
Protocols ~= p; | |
return null; | |
} | |
// ProtocolWithName returns the Protocol description with given string name. | |
Protocol ProtocolWithName(string s) { | |
foreach (p; Protocols) { | |
if (p.Name == s) { | |
return p; | |
} | |
} | |
return Protocol(); | |
} | |
// ProtocolWithCode returns the Protocol description with given protocol code. | |
Protocol ProtocolWithCode(int c) { | |
foreach (p; Protocols) { | |
if (p.Code == c) { | |
return p; | |
} | |
} | |
return Protocol(); | |
} | |
// ProtocolsWithString returns a slice of protocols matching given string. | |
auto ProtocolsWithString(string s) { | |
s = strip(s, '/'); | |
auto sp = split(s, "/"); | |
if (sp.length == 0) { | |
return tuple(new Protocol[0], ""); | |
} | |
auto t = new Protocol[sp.length]; | |
foreach (i, name; sp) { | |
auto p = ProtocolWithName(name); | |
if (p.Code == 0) { | |
return tuple(new Protocol[0], format("no protocol with name: %s", name)); | |
} | |
t[i] = p; | |
} | |
return tuple(t, ""); | |
} | |
// CodeToVarint converts an integer to a varint-encoded byte[] | |
auto CodeToVarint(int num) { | |
byte[long.sizeof] buf = new byte[long.sizeof]; | |
version(LittleEndian) { | |
byte[num.sizeof] b = cast(byte[])nativeToLittleEndian(num); | |
} | |
else { | |
byte[num.sizeof] b = cast(byte[])nativeToBigEndian(num); | |
} | |
buf[0 .. num.sizeof] = b[0 .. $]; | |
return buf; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment