By itself, carrier is a low-level, stateless, concurrent networking library that easily allows you to incorporate fundamental features any modern p2p application needs such as:
- cryptographic primitives (Ed25519, PoW, AES-256),
- message serialization/deserialization schemes (byte-order little endian, protobuf, msgpack),
- network timeout/error management (on dial, on receive message, on send buffer full),
- network-level atomic operations (receive-then-lock),
- and NAT traversal support (NAT-PMP, UPnP).
Out of its own low-level constructs, carrier additionally comes bundled with a high-level protocol
package comprised of a large number of production-ready, high-level protocol building blocks such as:
- handshake protocol implementations (Elliptic-Curve Diffie Hellman),
- peer routing/discovery protocol implementations (S/Kademlia),
- message broadcasting protocol implementations (S/Kademlia),
- overlay network protocol implementations (S/Kademlia),
- cryptographic identity schemes (Ed25519 w/ EdDSA signatures),
- and authenticated encryption schemes (AES-256 GCM AEAD).
Application layer can define component by themself, which is an interface as follow:
// ComponentInterface is used to proxy callbacks to a particular Component instance.
type ComponentInterface interface {
// Callback for when the network starts listening for peers.
Startup(net *Network)
// Callback for when an incoming message is received. Return true
// if the Component will intercept messages to be processed.
Receive(ctx *ComponentContext) error
// Callback for when the network stops listening for peers.
Cleanup(net *Network)
// Callback for when a peer connects to the network.
PeerConnect(client *PeerClient)
// Callback for when a peer disconnects from the network.
PeerDisconnect(client *PeerClient)
}
- When app layer implement the component interface, it can handle message dispatched from ReceiveMessage flow;
- Component can choose to deal with the message it concerns in Receive Callback.
- App layer can initial something when Startup(), and clear resource in Cleanup();
- When a Connection or Disconnection occur, PeerConnect/Disconnect will be called;
- Node start Listening with a speciall IP/Port, which will be connectd from outbound. as well, you can setup transport protocol, for example: TCP/UDP/QUIC and so on.
- Outbound connect to speciall node(IP:Port);
- Connection will be standed for Client struct, which will be managed in ConnMgr Interface;
- When remote node disconnect initiatively, or receivd an ERROR message, this node will disconnect;
- There is only ONE connection between same pair nodes;
- P2P by default encodes messages as bytes in little-endian order, and provides utility classes to assist with serializing/deserializing arbitrary Go types into bytes efficiently.
- For each message, there is a
opcode <-> message
pairing must be specified entirely up to the user in code. - User must registe an opcode for special message as follow:
type Opcode uint32
const (
UnregisteredCode Opcode = 0x00000 // 0
BytesCode Opcode = 0x00001 // 1
KeepaliveCode Opcode = 0x00002 // 2
KeepaliveResponseCode Opcode = 0x00003 // 3
ProxyResponseCode Opcode = 0x00009 // 9
PingCode Opcode = 0x0000a // 10
PongCode Opcode = 0x0000b // 11
LookupNodeRequestCode Opcode = 0x0000c // 12
LookupNodeResponseCode Opcode = 0x0000d // 13
DisconnectCode Opcode = 0x0000e // 14
ProxyRequestCode Opcode = 0x0000f // 15
MetricRequestCode Opcode = 0x00010 // 16
MetricResponseCode Opcode = 0x00011 // 17
AckResponseCode Opcode = 0x00012 // 18
ApplicationOpCodeStart Opcode = 1000
)
- When disconnect by remote peer(EOF msg received), or receiving an ERROR message connection will be destoried;
- Component's callback named Peerdisconnect Will be called foreach compoent in list;
- Relative resource will be recycled in PeerClose flow;
- User can rebuild a new connection immediatelly after disconnectiong;
- When node quit, all connection will be auto to disconnect;