Based on the docs/draft-hedberg-spocp-tcp-00.txt specification, I've implemented a complete TCP server and client for SPOCP with the following features:
- Length-value (LV) encoding:
L:valueformat - Message encoding:
L(L'Operation' *L'arg') - Operations: QUERY, ADD, RELOAD (extension), LOGOUT
- Full spec compliance with draft-hedberg-spocp-tcp-00
- Multi-client concurrent handling
- TLS support (optional)
- Dynamic rule loading from
.spocfiles - Automatic rule reloading (configurable interval)
- Graceful shutdown with signal handling
- Comprehensive logging
- Interactive and batch modes
- TLS support with certificate verification
- Query, Add, Reload, Logout operations
- Connection pooling and management
- 6/6 protocol tests passing
- 4/4 integration tests passing
- Complete documentation in
docs/TCP_SERVER.md - Example rule files
- Integration test script
# Build server
go build -o spocpd ./cmd/spocpd
# Build client
go build -o spocp-client ./cmd/spocp-clientCreate a directory with .spoc files:
mkdir -p rules
cat > rules/policies.spoc <<'EOF'
# HTTP access rules
(4:http(4:page10:index.html)(6:action3:GET)(6:userid))
(4:http(4:page9:admin.php)(6:action)(6:userid5:admin))
EOF# Basic server
./spocpd -rules ./rules
# With auto-reload every 5 minutes
./spocpd -rules ./rules -reload 5m
# With TLS
./spocpd -rules ./rules \
-tls-cert server.crt \
-tls-key server.key# Interactive mode
./spocp-client
# Single query
./spocp-client -query '(4:http(4:page10:index.html)(6:action3:GET)(6:userid4:john))'
# Add a rule
./spocp-client -add '(4:http(4:page8:new.html)(6:action3:GET)(6:userid))'
# With TLS
./spocp-client -tls$ ./spocp-client
Connected to localhost:6000
SPOCP Client - Interactive Mode
Commands:
query <s-expression> - Query a rule
add <s-expression> - Add a rule
reload - Reload server rules
quit - Exit
> query (4:http(4:page10:index.html)(6:action3:GET)(6:userid4:john))
✓ OK - Query matched
> add (4:http(4:page7:api.php)(6:action4:POST)(6:userid))
✓ Rule added successfully
> reload
✓ Server rules reloaded
> quit
Goodbye!
Client sends QUERY:
70:5:QUERY60:(4:http(4:page10:index.html)(6:action3:GET)(6:userid4:olav))
Server responds:
6:200:Ok
-addr string
Address to listen on (default ":6000")
-rules string
Directory containing .spoc rule files (REQUIRED)
-tls-cert string
Path to TLS certificate (optional)
-tls-key string
Path to TLS private key (optional)
-reload duration
Auto-reload interval, e.g., 5m, 1h (default: disabled)
-addr string
Server address (default "localhost:6000")
-tls
Use TLS connection
-insecure
Skip TLS certificate verification (testing only)
-query string
Execute single query and exit
-add string
Add single rule and exit
The server monitors a directory for .spoc files:
- At startup: Loads all
.spocfiles - Manual reload: Send RELOAD command from client
- Auto-reload: Optional periodic reloading (
-reloadflag)
When reloading:
- Creates new engine
- Loads all
.spocfiles - Atomically swaps engines (no downtime)
- Logs rule count
Generate test certificates:
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.crt -days 365 \
-subj "/CN=localhost"Start with TLS:
./spocpd -rules ./rules -tls-cert server.crt -tls-key server.keyConnect:
./spocp-client -tlsRules must use canonical S-expression format (length-prefixed):
# Comments supported (# // ;)
# Simple rule
(4:http(4:page10:index.html)(6:action3:GET)(6:userid))
# With user constraint
(4:http(4:page)(6:action3:GET)(6:userid5:alice))
Run integration tests:
./test-tcp.shRun protocol tests:
go test ./pkg/protocol -v┌─────────────────┐
│ spocp-client │
│ (cmd/) │
└────────┬────────┘
│ TCP/TLS
▼
┌─────────────────┐ ┌──────────────┐
│ spocpd │◄─────┤ .spoc files │
│ (cmd/) │ │ (rules/) │
└────────┬────────┘ └──────────────┘
│
┌────┴────┐
│ │
┌───▼───┐ ┌──▼────┐
│Server │ │ Proto │
│(pkg/) │ │ col │
└───┬───┘ │(pkg/) │
│ └───────┘
┌───▼───────┐
│ Engine │
│ (spocp) │
└───────────┘
- docs/TCP_SERVER.md - Complete server/client documentation
- docs/draft-hedberg-spocp-tcp-00.txt - Protocol specification
- docs/FILE_LOADING.md - Rule file formats
- docs/ADAPTIVE_ENGINE.md - Engine performance
The server uses the optimized SPOCP engine with:
- Tag-based indexing (2-5x faster queries)
- Zero allocations during queries
- Concurrent client handling
- Efficient rule reloading
See docs/OPTIMIZATION_SUMMARY.md for details.
- Always use TLS (
-tls-cert,-tls-key) - Never use
-insecurein production - Firewall the SPOCP port (default 6000)
- Consider using TLS client certificates for authentication
- The protocol has no built-in authentication
Connection refused:
# Check if server is running
netstat -an | grep 6000
# Check server logs
./spocpd -rules ./rules # Run in foregroundTLS errors:
# Verify certificate
openssl x509 -in server.crt -text -noout
# Test with insecure mode (development only)
./spocp-client -tls -insecureRules not loading:
# Check file extension (.spoc required)
ls -la rules/
# Validate S-expression syntax
# Use length-prefixed format: (4:http...)
# Check server logs for parse errorsSee examples/rules/ for sample rule files:
http.spoc- HTTP access rulesfile.spoc- File access rules
Possible enhancements:
- Authentication layer (SASL, TLS client certs)
- Query result caching
- Metrics/monitoring endpoint
- Rule validation API
- Batch operations
- Compression support
pkg/protocol/protocol.go - Protocol encoding/decoding
pkg/protocol/protocol_test.go - Protocol tests (6 tests)
pkg/server/server.go - TCP server implementation
pkg/client/client.go - Client library
cmd/spocpd/main.go - Server daemon
cmd/spocp-client/main.go - Client CLI
examples/rules/http.spoc - Example HTTP rules
examples/rules/file.spoc - Example file rules
docs/TCP_SERVER.md - Complete documentation
test-tcp.sh - Integration tests
Total: ~2,200 lines of code added
Follows the same license as the go-spocp project.