This is a production-ready RTP proxy server implemented in Rust 2024 Edition with gRPC control interface.
- Rust 2024 Edition (latest stable)
- Compiled with rustc 1.90.0
- tokio 1.42: Async runtime with full feature set
- tonic 0.12: gRPC framework
- prost 0.13: Protocol Buffers implementation
- dashmap 6.1: Concurrent HashMap for session storage
- tracing: Structured logging and diagnostics
UDP Transport (Fully Implemented):
- Dual socket architecture: separate listen and forward sockets
- Supports binding to specific network interfaces
- Non-blocking async I/O
- Maximum packet size: 65535 bytes (UDP MTU)
- Automatic RTCP support on port + 1
TCP Transport (Implemented):
- Bidirectional TCP forwarding support
- Connection lifecycle management
- Async I/O for both client and destination connections
- Graceful connection shutdown
Session Lifecycle:
Created → Connecting → Active → [Error] → Closed
Concurrency Model:
- Lock-free statistics using atomic operations (AtomicU64)
- Broadcast channels for graceful shutdown
- Async RwLock for shared state (SessionState, error messages)
- DashMap for concurrent session storage
Statistics Tracking:
- Packets received/sent (atomic counters)
- Bytes received/sent (atomic counters)
- Packet loss tracking
- Automatic loss rate calculation
- Last activity timestamp
Event System:
- Unbounded MPSC channels for event propagation
- Five event types: Created, StateChanged, StatsUpdate, Error, Closed
- Optional periodic statistics reporting
API Endpoints:
- CreateSession: Creates new forwarding session
- DestroySession: Cleanly shuts down session
- GetSessionStatus: Query current session state
- ListSessions: Enumerate all sessions with optional filtering
- StreamSessionEvents: Real-time event streaming
Protocol Buffers:
- Clean separation between internal types and protobuf types
- Type conversions handled in gRPC layer
- Endpoint structure: address + port (no interface field)
Custom error types using thiserror:
- IoError: Wraps std::io::Error
- AddrParseError: Invalid address parsing
- SessionNotFound: Session lookup failures
- Transport: Transport-specific errors
- Additional error variants for future use
Initialization:
- Tracing subscriber with environment variable configuration
- Session manager singleton (Arc-wrapped)
- gRPC server on
[::]:50051
Logging Levels:
- INFO: Session lifecycle events
- DEBUG: Per-packet forwarding details
- ERROR: Failure conditions
The proxy supports multi-homed scenarios through explicit endpoint configuration:
-
Listen Endpoint: Where to receive incoming RTP traffic
- Can bind to specific interface:
192.168.1.10:20000 - Or bind to all interfaces:
0.0.0.0:20000
- Can bind to specific interface:
-
Forward Endpoint: Source address for outgoing traffic
- Determines which interface sends packets
- Example:
10.0.0.5:20001sends via 10.0.0.x network
-
Destination Endpoint: Final recipient of forwarded traffic
This architecture enables scenarios like:
- Receiving on internal network, forwarding via external network
- NAT traversal assistance
- Multi-datacenter proxying
loop {
// Receive packet on listen socket
(data, source) = listen_socket.recv_from()
// Update statistics
stats.record_received(data.len())
// Forward via forward socket to destination
bytes_sent = forward_socket.send_to(data, destination)
// Update statistics
stats.record_sent(bytes_sent)
}Current implementation is unidirectional (client → destination). Bidirectional support would require:
- Reverse channel tracking
- Dynamic port allocation
- NAT hole punching logic
Scalability:
- Concurrent session handling via Tokio async tasks
- Lock-free statistics (atomic operations)
- Zero-copy packet forwarding where possible
Resource Usage:
- Each session: ~2 UDP sockets + 1 async task
- Memory: Minimal per-session overhead
- CPU: Dominated by kernel network stack
Limitations:
- No packet queuing (immediate forward or drop)
- No traffic shaping or rate limiting
- Single-threaded event loop (Tokio default)
Debug Build:
cargo build
# Output: target/debug/rtpproxyRelease Build (optimized):
cargo build --release
# Output: target/release/rtpproxyUnit Tests: Not yet implemented Integration Tests: Not yet implemented
Manual Testing:
# Terminal 1: Start proxy
cargo run --release
# Terminal 2: Create session
grpcurl -plaintext -d '...' localhost:50051 rtpproxy.RtpProxy/CreateSession
# Terminal 3: Send test UDP packets
echo "test" | nc -u localhost 20000
# Terminal 4: Receive on destination
nc -u -l 30000- Latency Metrics: avg_latency_ms always returns 0.0
- Packet Validation: No RTP header parsing/validation
- Session Persistence: In-memory only (lost on restart)
- Authentication: No access control
- Rate Limiting: No traffic shaping
High Priority:
- Unit and integration tests
- Latency measurements
- Session timeout enforcement
Medium Priority:
- RTP header parsing and validation
- Packet validation and filtering
- Enhanced error recovery
Low Priority:
- Persistent session storage
- gRPC authentication
- Prometheus metrics
- Admin web UI
- Rate limiting and traffic shaping
Current State:
- No authentication on gRPC interface (plaintext)
- No validation of forwarding destinations
- No rate limiting (DDoS vulnerable)
- No packet inspection (can proxy anything)
Production Recommendations:
- Use TLS for gRPC (configure Tonic with certificates)
- Implement IP whitelist for allowed destinations
- Add rate limiting per session
- Deploy behind firewall with restricted access
- Enable detailed audit logging
Systemd Service (example):
[Unit]
Description=RTP Proxy Service
After=network.target
[Service]
Type=simple
User=rtpproxy
ExecStart=/usr/local/bin/rtpproxy
Restart=on-failure
Environment=RUST_LOG=info
[Install]
WantedBy=multi-user.targetDocker (future):
- Multi-stage build for minimal image size
- Non-root user
- Expose UDP ports and gRPC port
- Health check endpoint
MIT License - See LICENSE file for details.