DisktroNet Documentation

DisktroNet

A modular P2P connectivity toolkit that provides identity, discovery, transport orchestration, NAT traversal, and relay capabilities for building robust peer-to-peer applications.

🔐

Identity & Discovery

Create peer identities with keystore support and discover peers via mDNS and bootstrap mechanisms.

🌐

Transport Orchestration

Intelligent connection management with direct TCP, UDP hole punching, and relay fallback.

🔒

Security

Pluggable handshake mechanisms including TLS support for secure communication.

📊

Observability

Comprehensive metrics and monitoring hooks for debugging and performance analysis.

Requirements

  • Go 1.22+
  • Windows/macOS/Linux

Quick Start

Get started with DisktroNet in just a few lines of code:

package main

import (
    "context"
    "fmt"
    "disktronet/internal/p2p/config"
)

func main() {
    ctx := context.Background()
    id, _ := config.NewIdentity(ctx, config.Options{
        Host: "localhost", 
        Port: 9000, 
        Type: "client"
    })
    fmt.Println("PeerID:", id.PeerID) // Base58BTC encoded
}

📦 Installation

Clone the repository and run the examples:

git clone https://github.com/jaywantadh/DisktroNet.git
cd DisktroNet
go run ./examples/connmanager

Architecture

DisktroNet follows a modular architecture with clear separation of concerns:

1

ConnManager

Manages connection pooling and ensures live connections

2

NATOrchestrator

Orchestrates connectivity modes in order of preference

3

Direct TCP

Attempts direct connection first

4

UDP Punch

Falls back to UDP hole punching

5

Relay

Uses relay as final fallback

Key Components

🔧 Transport Layer

  • Connection management with pooling
  • NAT traversal orchestration
  • UDP hole punching
  • STUN client for external IP discovery

🔍 Discovery

  • mDNS for local peer discovery
  • Bootstrap mechanisms
  • Static and DNS-based peer lists

🔄 Relay

  • TCP-based circuit relay
  • Framed message protocol
  • Session management
  • Keepalive and idle timeout

🛡️ Security

  • Pluggable handshake interface
  • TLS implementation
  • Certificate validation

Development Phases

DisktroNet is developed in progressive phases, each building upon the previous:

1

Identity & Discovery

Create peer identities, manage keystores, and discover peers through mDNS and bootstrap mechanisms.

Features

  • Peer identity creation and management
  • Keystore support (PEM and RAW seed formats)
  • mDNS advertising and discovery
  • Bootstrap peer discovery
Example: Creating Identity
import (
    "context"
    "disktronet/internal/p2p/config"
    "disktronet/internal/p2p/discovery"
)

ctx := context.Background()
id, _ := config.NewIdentity(ctx, config.Options{
    Host: "localhost", 
    Port: 9000, 
    Type: "client"
})

// mDNS advertise with TXT
txt := discovery.EncodeTXT(string(id.PeerID), id.Meta.NodeType, id.Meta.Port)
adv := discovery.NewZeroconfAdvertiserWithTXT("disktronode", id.Meta.Port, txt)
_ = adv.Start(ctx)
defer adv.Stop()
2

Transport & Connection Management

Efficient connection pooling, heartbeat management, and intelligent connection orchestration.

Features

  • Connection pooling with per-peer limits
  • Heartbeat and idle timeout management
  • Exponential backoff with jitter
  • Connection deduplication
Example: Connection Manager
import (
    "context"
    "time"
    "disktronet/internal/p2p/transport"
)

cm := transport.NewConnManager(transport.ConnMgrOptions{
    MaxConnsPerPeer: 2,
    IdleTimeout:     2 * time.Minute,
    HeartbeatEvery:  20 * time.Second,
    DialTimeout:     7 * time.Second,
    BackoffMin:      500 * time.Millisecond,
    BackoffMax:      30 * time.Second,
    DialFunc: func(ctx context.Context, addr string) (net.Conn, error) {
        return (&net.Dialer{}).DialContext(ctx, "tcp", addr)
    },
})
_ = cm.Start(context.Background())
defer cm.Stop(context.Background())

c, err := cm.Ensure(context.Background(), "peerID", "127.0.0.1:9000")
3

NAT Traversal

Intelligent NAT traversal with direct TCP attempts, UDP hole punching, and automatic fallback to relay.

Features

  • Direct TCP connection attempts
  • UDP hole punching with rendezvous coordination
  • NAT type detection (cone vs symmetric)
  • Automatic relay fallback
Example: NAT Orchestrator
import (
    "context"
    "disktronet/internal/p2p/transport"
    "disktronet/internal/p2p/relay"
)

o := transport.NATOrchestrator{
    TCPDial: func(ctx context.Context, addr string) (net.Conn, error) {
        return (&net.Dialer{}).DialContext(ctx, "tcp", addr)
    },
    Rendezvous:  transport.NewInMemoryRendezvous(),
    HolePunch:   transport.SimpleHolePuncher{},
    RelayClient: relay.InMemoryRelay{},
    DialTimeout:  7 * time.Second,
    PunchTimeout: 5 * time.Second,
}
res, err := o.Connect(context.Background(), "selfID", "peerID", "peer.addr:9000")
4

Relay

Lightweight circuit relay for guaranteed connectivity when direct paths fail.

Features

  • TCP-based circuit relay
  • Framed message protocol
  • Session pairing and management
  • Keepalive and idle timeout
Example: Using Relay
import (
    "context"
    "disktronet/internal/p2p/relay"
)

r := relay.InMemoryRelay{}
// Peer A
go func(){
    sA, _ := r.Open(context.Background(), "peerB")
    _ = sA.Send([]byte("hi"))
}()
// Peer B
sB, _ := r.Open(context.Background(), "peerB")
msg, _ := sB.Recv() // "hi"

API Reference

Comprehensive API documentation for all DisktroNet components.

Transport Layer

ConnectionManager

Manages connection pooling and ensures live connections to peers.

Start(ctx context.Context) error Start background tasks
Stop(ctx context.Context) error Stop and close all peers
Ensure(ctx, peerID, addr) (net.Conn, error) Return or establish a live connection
Stats() Stats Returns connection statistics

NATOrchestrator

Orchestrates connectivity modes: Direct TCP → UDP punch → Relay.

Connect(ctx, selfID, peerID, peerTCPAddr) (ConnectResult, error) Attempts connection with escalation policy

Relay Layer

Session

Bidirectional framed stream between peers.

Send([]byte) error Send data to peer
Recv() ([]byte, error) Receive data from peer
Close() error Close the session

Security

Handshake

Pluggable handshake interface for secure connections.

Client(raw net.Conn) (net.Conn, error) Wrap client side (e.g., TLS)
Server(raw net.Conn) (net.Conn, error) Optional server-side wrapper

Examples

Ready-to-run examples demonstrating DisktroNet capabilities:

🔗 Connection Manager

End-to-end usage of ConnManager with escalation policy.

go run ./examples/connmanager

🌐 NAT Traversal

UDP hole punching demonstration.

go run ./examples/nat

🔄 Relay Fallback

Using relay for guaranteed connectivity.

go run ./examples/relay

🔒 TLS Security

TLS handshake over direct TCP connections.

go run ./examples/tls

🚀 Running the Relay Server

Start a standalone relay server:

# Build the relay server
go build -o bin/disktronet-relay ./cmd/disktronet-relay

# Run with custom configuration
./bin/disktronet-relay -addr :9000 -idle 60s -maxframe 8388608

Security

DisktroNet provides flexible security mechanisms through pluggable handshake interfaces.

🔐 TLS Handshake

Secure connections with configurable TLS settings.

import (
    "crypto/tls"
    "disktronet/internal/p2p/transport"
)

hs := transport.TLSHandshake{
    ClientTLS: &tls.Config{
        InsecureSkipVerify: true, // dev only
    }
}
o := transport.NATOrchestrator{
    TCPDial: func(ctx context.Context, addr string) (net.Conn, error) {
        return (&net.Dialer{}).DialContext(ctx, "tcp", addr)
    },
    Handshake: hs,
}
res, err := o.Connect(context.Background(), "self", "peer", "127.0.0.1:9000")

🛡️ Production Security

  • Configure trusted root CAs
  • Set proper ServerName validation
  • Use strong cipher suites
  • Implement certificate pinning

Observability

Comprehensive metrics and monitoring for debugging and performance analysis.

Transport Metrics

Monitor connection attempts, success rates, and fallback behavior:

import (
    "disktronet/internal/p2p/transport"
    "disktronet/internal/p2p/relay"
)

type myTransportMetrics struct{}
func (myTransportMetrics) DialAttempt(peer string)          { fmt.Println("dial_attempt", peer) }
func (myTransportMetrics) DialSuccess(mode string)          { fmt.Println("dial_success", mode) }
func (myTransportMetrics) DialFailure(mode string)          { fmt.Println("dial_failure", mode) }
func (myTransportMetrics) STUNQuery()                       { fmt.Println("stun_query") }
func (myTransportMetrics) STUNResult()                      { fmt.Println("stun_result") }
func (myTransportMetrics) PunchAttempt()                    { fmt.Println("punch_attempt") }
func (myTransportMetrics) PunchSuccess()                    { fmt.Println("punch_success") }
func (myTransportMetrics) PunchFailure()                    { fmt.Println("punch_failure") }
func (myTransportMetrics) RelayOpenSuccess()                { fmt.Println("relay_open_success") }
func (myTransportMetrics) RelayOpenFailure()                { fmt.Println("relay_open_failure") }

type myRelayMetrics struct{}
func (myRelayMetrics) SessionOpened()                       { fmt.Println("relay_session_opened") }
func (myRelayMetrics) SessionClosed()                       { fmt.Println("relay_session_closed") }
func (myRelayMetrics) BytesForwarded(n int)                 { fmt.Println("relay_bytes", n) }

func init() {
    transport.SetMetrics(myTransportMetrics{})
    relay.SetMetrics(myRelayMetrics{})
}

Relay Metrics

Track session lifecycle and data forwarding:

  • SessionOpened - New relay session established
  • SessionClosed - Session terminated
  • BytesForwarded - Data volume through relay

Troubleshooting

Common issues and their solutions:

🔍 mDNS Discovery Issues

  • Check firewall rules and local network segment
  • Ensure service type/name matches between advertiser and browser
  • Verify network connectivity

🌐 NAT Traversal Problems

  • Symmetric NATs may block punching → rely on relay fallback
  • Ensure both peers can reach the rendezvous coordinator
  • Check STUN server availability

🔄 Connection Issues

  • Too many dials: always use Ensure() for deduplication
  • Idle timeouts: tune IdleTimeout and HeartbeatEvery
  • Reconnect storms: adjust BackoffMin/Max and DialTimeout

🔒 TLS Handshake Failures

  • Certificate validation failures: configure proper RootCAs and ServerName
  • For development: use InsecureSkipVerify: true
  • Handshake failure triggers automatic fallback to UDP/relay

📊 Metrics Not Appearing

  • Ensure you called transport.SetMetrics() and relay.SetMetrics() before dialing
  • Check that metrics implementations are set at program startup
  • Verify metrics hooks are not nil

🔄 Relay Pairing Issues

  • Ensure both sides call Open with the same destPeer
  • Verify both peers share the same relay instance
  • Check relay server connectivity and configuration