---
title: Networking
sidebarTitle: Networking
---

Spacedrive connects devices directly using Iroh, a peer-to-peer networking library built on QUIC. This enables secure communication between your devices without relying on cloud servers.

## Architecture

The networking system manages all device-to-device communication through a single service that handles connections, protocols, and state management.

### Core Components

**NetworkingService** coordinates all networking operations. It manages the Iroh endpoint, tracks device states, and routes messages to protocol handlers.

```rust
pub struct NetworkingService {
    endpoint: Endpoint,              // Iroh's QUIC endpoint
    device_registry: DeviceRegistry, // Tracks all known devices
    protocol_registry: ProtocolRegistry, // Routes messages
    identity: NetworkIdentity,       // Cryptographic identity
}
```

**NetworkIdentity** manages your device's cryptographic identity using Ed25519 keys. This identity persists across sessions and proves your device's authenticity to others.

```rust
pub struct NetworkIdentity {
    node_id: NodeId,           // Derived from public key
    signing_key: SigningKey,   // Ed25519 private key
    verifying_key: VerifyingKey, // Ed25519 public key
}
```

**DeviceRegistry** maintains the state of all discovered and paired devices. It provides a single source of truth for device relationships.

```rust
pub enum DeviceState {
    Discovered { node_addr: NodeAddr },
    Pairing { session_id: Uuid },
    Paired { session_keys: SessionKeys },
    Connected { connection: Connection },
    Disconnected { reason: DisconnectReason },
}
```

### Network Transport

Iroh provides the underlying transport using QUIC, which offers:

- **Built-in encryption** using TLS 1.3
- **Multiplexed streams** over a single connection
- **Reliable delivery** with automatic retransmission
- **NAT traversal** with 90%+ success rate
- **Relay fallback** when direct connections fail

### Protocol System

The networking module uses ALPN (Application-Layer Protocol Negotiation) to route connections to specific protocol handlers.

```rust
// Protocol registration
registry.register("pairing/1.0", PairingProtocol::new());
registry.register("sync/1.0", SyncProtocol::new());
registry.register("transfer/1.0", TransferProtocol::new());

// Connection routing based on ALPN
match alpn {
    "pairing/1.0" => pairing_handler.handle(connection),
    "sync/1.0" => sync_handler.handle(connection),
    _ => Err(UnknownProtocol)
}
```

## Device Discovery

Devices find each other through multiple mechanisms:

### Local Network Discovery

Iroh automatically discovers devices on your local network using mDNS. When a device starts, it broadcasts its presence and listens for others.

```rust
// Automatic local discovery
endpoint.discovery().add_discovery(Box::new(
    DnsDiscovery::builder().build()
));
```

### Manual Connection

You can connect to devices using their NodeAddr, which includes their NodeId and network addresses.

```rust
// Connect to a specific device
let node_addr = NodeAddr {
    node_id: NodeId::from_str("...")?,
    relay_url: Some("https://relay.iroh.network"),
    direct_addresses: vec!["192.168.1.100:11204".parse()?],
};

endpoint.connect(node_addr, "sync/1.0").await?;
```

<Note>
Direct addresses work on local networks. The relay URL enables connections across the internet when direct connections fail.
</Note>

## Device Pairing

Pairing establishes trust between devices using cryptographic signatures and user-friendly codes.

### Pairing Flow

The initiator generates a pairing code that the joiner enters to establish trust.

<Steps>
<Step title="Generate Pairing Code">
The initiator creates a BIP39 mnemonic code:
```rust
// Initiator generates code
let code = PairingCode::generate(); // "brave-lion-sunset"
```
</Step>

<Step title="Exchange Device Info">
Both devices exchange their information and public keys:
```rust
pub struct DeviceInfo {
    pub device_id: Uuid,
    pub device_name: String,
    pub device_type: DeviceType,
    pub public_key: VerifyingKey,
}
```
</Step>

<Step title="Challenge-Response">
The initiator challenges the joiner to prove they have the code:
```rust
// Initiator sends challenge
let challenge = Challenge::random();

// Joiner signs challenge
let signature = identity.sign(&challenge);

// Initiator verifies signature
identity.verify(&challenge, &signature)?;
```
</Step>

<Step title="Establish Session">
Both devices derive session keys for future communication:
```rust
// Derive shared secret using ECDH
let shared_secret = ecdh(my_private, their_public);

// Derive session keys
let keys = SessionKeys::from_shared_secret(shared_secret);
```
</Step>
</Steps>

### Pairing Security

The pairing protocol prevents several attacks:

- **Man-in-the-middle**: Public key exchange with out-of-band verification
- **Replay attacks**: Fresh challenges for each pairing attempt
- **Brute force**: Rate limiting on pairing attempts
- **Eavesdropping**: All communication encrypted after initial handshake

## Message Protocol

Paired devices communicate using an encrypted messaging protocol.

### Message Types

```rust
pub enum NetworkMessage {
    // Library discovery
    LibraryAnnounce { libraries: Vec<LibraryInfo> },
    LibraryRequest { library_id: Uuid },
    
    // Sync coordination
    SyncRequest { library_id: Uuid, after: HLC },
    SyncResponse { entries: Vec<SyncEntry> },
    
    // File operations
    FileRequest { entry_id: Uuid },
    FileResponse { chunks: Vec<Chunk> },
    
    // Diagnostics
    Ping { timestamp: SystemTime },
    Pong { timestamp: SystemTime },
}
```

### Message Flow

Messages are serialized as JSON and encrypted using session keys:

```rust
// Send a message
async fn send_message(
    connection: &mut Connection,
    message: NetworkMessage,
    keys: &SessionKeys,
) -> Result<()> {
    // Serialize to JSON
    let json = serde_json::to_vec(&message)?;
    
    // Encrypt with session key
    let encrypted = keys.encrypt(&json)?;
    
    // Send over QUIC stream
    let mut stream = connection.open_uni().await?;
    stream.write_all(&encrypted).await?;
    stream.finish().await?;
    
    Ok(())
}
```

### Reliability

QUIC provides reliable delivery, but the application layer adds:

- **Message acknowledgments** for critical operations
- **Automatic retries** with exponential backoff
- **Connection health monitoring** with periodic pings
- **Graceful reconnection** after network changes

## File Transfer

The file transfer protocol enables secure, resumable file sharing between devices.

### Transfer Process

<Steps>
<Step title="Request File">
Device A requests a file by its entry ID:
```rust
let request = FileRequest {
    entry_id: Uuid::parse_str("...")?,
    resume_from: Some(1048576), // Resume from 1MB
};
```
</Step>

<Step title="Stream Chunks">
Device B streams the file in encrypted chunks:
```rust
// 256KB chunks
const CHUNK_SIZE: usize = 262144;

while let Some(chunk) = file.read_chunk(CHUNK_SIZE).await? {
    let encrypted = session_keys.encrypt(&chunk)?;
    stream.write_all(&encrypted).await?;
}
```
</Step>

<Step title="Verify Transfer">
Both devices verify the transfer using checksums:
```rust
let checksum = blake3::hash(&file_data);
if checksum != expected_checksum {
    return Err(TransferError::ChecksumMismatch);
}
```
</Step>
</Steps>

### Transfer Features

- **Resumable transfers**: Continue from where you left off
- **Progress tracking**: Real-time updates on transfer status
- **Bandwidth throttling**: Respect network limits
- **Parallel transfers**: Multiple files simultaneously
- **Compression**: Optional gzip compression for text files

## Connection Management

The event loop handles all incoming connections and routes them appropriately.

### Event Loop

```rust
pub struct NetworkingEventLoop {
    endpoint: Endpoint,
    registry: ProtocolRegistry,
    commands: mpsc::Receiver<NetworkCommand>,
}

impl NetworkingEventLoop {
    pub async fn run(mut self) -> Result<()> {
        loop {
            select! {
                // Handle incoming connections
                Some(connection) = self.endpoint.accept() => {
                    let alpn = connection.alpn();
                    let handler = self.registry.get(alpn)?;
                    tokio::spawn(handler.handle(connection));
                }
                
                // Process commands
                Some(cmd) = self.commands.recv() => {
                    self.handle_command(cmd).await?;
                }
            }
        }
    }
}
```

### Connection States

Connections transition through several states:

1. **Connecting**: Initial QUIC handshake
2. **Connected**: Active connection, can send/receive
3. **Idle**: No recent activity, may be closed
4. **Closing**: Graceful shutdown in progress
5. **Closed**: Connection terminated

### Keep-Alive

Connections are kept alive using periodic pings:

```rust
// Ping every 30 seconds of inactivity
const KEEP_ALIVE_INTERVAL: Duration = Duration::from_secs(30);

async fn keep_alive_loop(connection: Connection) {
    let mut interval = tokio::time::interval(KEEP_ALIVE_INTERVAL);
    
    loop {
        interval.tick().await;
        
        if let Err(_) = send_ping(&connection).await {
            // Connection lost
            break;
        }
    }
}
```

## NAT Traversal

Iroh handles NAT traversal automatically using several techniques:

### Direct Connection

First, Iroh attempts a direct connection using known addresses:

```rust
// Try direct addresses first
for addr in &node_addr.direct_addresses {
    if let Ok(conn) = endpoint.connect_direct(addr).await {
        return Ok(conn);
    }
}
```

### STUN

If direct connection fails, Iroh uses STUN to discover public addresses:

```rust
// STUN automatically handled by Iroh
// Discovers public IP and port mapping
let public_addr = endpoint.my_addr().await?;
```

### Relay Fallback

When both devices are behind symmetric NATs, Iroh falls back to relay servers:

```rust
// Relay connection automatic in Iroh
// Uses relay_url from NodeAddr
let conn = endpoint.connect(node_addr, alpn).await?;
// This may be relayed if direct connection impossible
```

<Info>
Relay servers don't decrypt your data. They only forward encrypted packets between devices.
</Info>

## Security

### Encryption Layers

The networking stack provides multiple encryption layers:

1. **Transport encryption**: QUIC's built-in TLS 1.3
2. **Application encryption**: Additional encryption using session keys
3. **File encryption**: Per-file encryption keys for transfers

### Key Management

```rust
pub struct KeyHierarchy {
    // Long-term identity
    device_key: SigningKey,
    
    // Per-pairing session keys
    session_keys: HashMap<DeviceId, SessionKeys>,
    
    // Per-transfer ephemeral keys
    transfer_keys: HashMap<TransferId, TransferKeys>,
}
```

### Trust Model

- **Device identity**: Ed25519 signatures prove device authenticity
- **Pairing verification**: Out-of-band code exchange prevents MITM
- **Forward secrecy**: New keys for each session and transfer
- **No central authority**: Direct device-to-device trust

## API Usage

### Initialize Networking

```rust
// In Core initialization
let networking = NetworkingService::new(
    data_dir.clone(),
    device_id,
)?;

// Start the event loop
let event_loop = networking.spawn_event_loop();
tokio::spawn(event_loop.run());
```

### Pair Devices

```rust
// Generate pairing code (initiator)
let code = core.networking()
    .start_pairing_as_initiator()
    .await?;

println!("Share this code: {}", code);

// Join pairing (joiner)
core.networking()
    .join_pairing(&code)
    .await?;
```

### Send Messages

```rust
// Get paired device
let device = core.networking()
    .get_device(device_id)?;

// Send sync request
let message = NetworkMessage::SyncRequest {
    library_id,
    after: last_sync_hlc,
};

device.send_message(message).await?;
```

### Transfer Files

```rust
// Share a file
let transfer = core.share_with_device(
    entry_id,
    device_id,
    TransferOptions {
        compress: true,
        encrypt: true,
    },
).await?;

// Monitor progress
while let Some(progress) = transfer.progress().await {
    println!("Transfer: {}%", progress.percentage);
}
```

## Performance

### Benchmarks

Typical performance on local network:

- **Connection setup**: 10-50ms
- **Message latency**: 1-5ms
- **File transfer**: 100MB/s+ (gigabit network)
- **Memory usage**: ~10MB per connection

### Optimization Strategies

1. **Connection pooling**: Reuse connections for multiple operations
2. **Stream multiplexing**: Multiple logical streams over one connection
3. **Adaptive chunking**: Adjust chunk size based on network conditions
4. **Compression**: Enable for text-heavy workloads

## Troubleshooting

### Connection Issues

If devices can't connect:

```bash
# Check if port is open
nc -zv 192.168.1.100 11204

# Monitor Iroh logs
RUST_LOG=iroh=debug cargo run

# Test connectivity
iroh doctor connect <node-id>
```

### Common Problems

**Problem**: "Connection refused"
- Check firewall allows UDP port 11204
- Verify both devices are running
- Ensure correct NodeId

**Problem**: "Connection timeout"
- Check network allows UDP traffic
- Try relay connection instead of direct
- Verify NAT type using STUN

**Problem**: "Pairing failed"
- Ensure pairing code is entered correctly
- Check code hasn't expired (5 minute timeout)
- Verify clocks are roughly synchronized

### Debug Commands

```rust
// Get connection info
let info = endpoint.connection_info(node_id).await?;
println!("RTT: {:?}", info.rtt);
println!("Congestion: {:?}", info.congestion_window);

// List connections
for conn in endpoint.connections() {
    println!("Connected to: {}", conn.remote_node_id());
}

// Force relay connection
let mut node_addr = node_addr.clone();
node_addr.direct_addresses.clear(); // Force relay
```

## Implementation Details

### Protocol Registration

New protocols are registered during initialization:

```rust
impl Protocol for CustomProtocol {
    fn alpn(&self) -> &[u8] {
        b"custom/1.0"
    }
    
    async fn handle(
        &self,
        connection: Connection,
    ) -> Result<()> {
        // Handle incoming connection
    }
}

// Register during startup
networking.register_protocol(Box::new(CustomProtocol::new()));
```

### Error Handling

The networking module uses a typed error system:

```rust
pub enum NetworkError {
    // Connection errors
    ConnectionFailed(node_id: NodeId),
    ConnectionTimeout(duration: Duration),
    
    // Protocol errors
    UnknownProtocol(alpn: String),
    ProtocolViolation(reason: String),
    
    // Security errors
    InvalidSignature,
    DecryptionFailed,
    
    // Device errors
    DeviceNotPaired(device_id: Uuid),
    DeviceOffline(device_id: Uuid),
}
```

### State Persistence

Device relationships and session keys are encrypted and persisted via the KeyManager:

```rust
// Paired device data stored per-device in KeyManager
pub struct PersistedPairedDevice {
    device_info: DeviceInfo,
    session_keys: SessionKeys,
    paired_at: DateTime<Utc>,
    trust_level: TrustLevel,
    relay_url: Option<String>,
}

// Storage:
// - Device key: OS keychain or encrypted fallback file
// - Paired devices: KeyManager's encrypted KV store (secrets.redb)
// - Network identity: Derived from device key
```

## Future Development

### Planned Features

**Enhanced Discovery**
- DHT-based global discovery
- Bluetooth device discovery
- QR code pairing

**Advanced Protocols**
- Video streaming protocol
- Real-time collaboration
- Distributed compute

**Infrastructure**
- Custom relay servers
- Relay server selection
- Bandwidth quotas

**Performance**
- Protocol buffer serialization
- Native stream handling
- Zero-copy transfers

### Extension Points

The networking module is designed for extensibility:

```rust
// Custom protocol implementation
pub trait NetworkProtocol: Send + Sync {
    fn alpn(&self) -> &[u8];
    fn handle(&self, conn: Connection) -> BoxFuture<Result<()>>;
}

// Custom discovery mechanism
pub trait Discovery: Send + Sync {
    fn discover(&self) -> BoxStream<NodeAddr>;
}

// Custom relay selection
pub trait RelaySelector: Send + Sync {
    fn select(&self, relays: &[Url]) -> Url;
}
```

## Related Documentation

- [Devices](/docs/core/devices) - Device identity and pairing
- [Sync](/docs/core/sync) - Data synchronization over network
- [Security](/docs/core/security) - Encryption and trust model