NetDrive is a full telemetry and control stack for an autonomous vehicle. Multiple users can connect at once to view live telemetry; administrators can also send control commands to the vehicle.
Three main parts:
- Multi-threaded TCP server in C
- Many concurrent client connections
- Token- and role-based authentication (Admin/Observer)
- Sessions with IP/port tracking
- Telemetry broadcast every 10 seconds to authenticated clients
- Vehicle command handling
- Configurable file logging (default
server.log) - Configurable TCP port and log file
- Client STATUS monitoring with disconnect on repeated errors
- Observer: live telemetry display
- Admin: commands and user management
- CustomTkinter UI
- Auto login to the server
- STATUS OK/ERROR health checks
- Background thread sending STATUS every 2 seconds
- Single web UI with login
- UI adapts to Admin vs Observer
- WebSocket–TCP bridge to the C server
- Telemetry view and admin controls
- STATUS OK/ERROR every 2 seconds
Text-based application-layer protocol for this project.
PTT + ACTION (12 bytes) + DATA (150 bytes) + END
- PTT: 3-byte header
- ACTION: 12 space-padded bytes, message type
- DATA: 150 space-padded bytes, payload
- END: 3-byte trailer
Total: 168 bytes per frame.
- LOGIN:
username;password - OK / ERROR / DENIED: server responses
- DATA:
speed=X;dir=Y;battery=Z;temp=W - COMMAND: vehicle command string
- LIST: list connected users (Admin)
- STATUS:
OKorERRORfrom client
- Client connects to TCP port 2000 (default).
- Client sends LOGIN.
- Server answers OK (token + role) or ERROR.
- Server sends DATA every 10 s to authenticated clients.
- Client sends STATUS every 2 s.
- Server counts consecutive errors; drops client after 3.
- Admin clients may send COMMAND.
- On disconnect, server clears the session.
| Username | Password | Role |
|---|---|---|
| admin | admin123 | ADMIN |
| observer | observer123 | OBSERVER |
| user1 | pass1 | OBSERVER |
| root | root | ADMIN |
ADMIN — Live telemetry, vehicle commands, user list, admin panel.
OBSERVER — Live telemetry only; no commands or admin panel.
Each client keeps a response flag: "", "OK", or "ERROR". A thread every 2 s sends STATUS and clears the flag. The server tracks consecutive ERROR values and disconnects after more than two in a row; OK resets the counter.
- Speed 0–120 km/h
- Direction 0–359° (often shown as cardinals)
- Battery 0–100%
- Temperature (°C)
- SPEED UP — +10 km/h (max 120)
- SLOW DOWN — −10 km/h (min 0)
- TURN LEFT / TURN RIGHT — ±45°
Battery drops 1% per command; temperature reacts to movement.
- Server: GCC, pthread, BSD sockets
- Python: 3.7+,
customtkinter,Pillow - Web: Node 14+, npm, modern browser
cd server
make
make run
# or: ./server 3000 my_log.txt
make cleanManual compile:
gcc -o server main.c car.c auth.c protocol.c logger.c -pthread
./server
./server 3000 custom.logArguments: [port] [logfile] — defaults 2000 and server.log.
cd clients/python_client
pip install -r requirements.txt
python client.py
python client.py 3000Uses observer / observer123.
python admin_client.py
python admin_client.py 3000Default admin: admin / admin123.
The folder name is clients/js client (space). Quote it in shells.
cd "clients/js client"
npm install
# Terminal 1 – WebSocket bridge (TCP default 2000)
node server.js
node server.js 3000
# Terminal 2 – static files
npx http-server -p 3000
# Open http://localhost:3000- TCP server: 2000 (default)
- WebSocket bridge: 8080
- HTTP (your choice): e.g. 3000
All clients must target the same TCP port as the C server.
This project is currently deployed with a split architecture:
- Frontend (static web app): Vercel
- Backend (C TCP server + Node WebSocket bridge): Ubuntu VPS
- TLS termination and reverse proxy: Nginx on VPS
- Public frontend URL:
https://net-drive-kappa.vercel.app/ - Public WebSocket endpoint used by the frontend:
wss://rivero-netdrive.duckdns.org/ws/
- The browser loads
index.htmlfrom Vercel. - At startup, the app reads
WS_URLfromenv.js(generated during Vercel build fromNETRIDE_WS_URL). - The frontend opens a secure WebSocket connection to
wss://rivero-netdrive.duckdns.org/ws/. - Nginx receives
/ws/and proxies it to the local Node bridge on127.0.0.1:8080. - The Node bridge forwards protocol frames to the C server on
127.0.0.1:2000. - Telemetry and command responses flow back through the same path to the browser.
The backend side runs as persistent systemd services:
netride-backend.service-> C server (server 2000 server.log)netride-bridge.service-> Node bridge (server.js 2000)
This keeps both processes running after reboot and allows standard log inspection with journalctl.
Nginx is configured to:
- Serve ACME challenges at
/.well-known/acme-challenge/for certificate renewal - Redirect HTTP to HTTPS
- Terminate TLS for
rivero-netdrive.duckdns.org - Proxy
/ws/requests to127.0.0.1:8080with WebSocket upgrade headers
The frontend uses a runtime config file:
env.js(generated at build time, not committed)env.example.js(committed template)
In Vercel:
NETRIDE_WS_URLis defined in project Environment Variables- Build command runs
node scripts/generate-env.js - The script writes
env.jswith the selected WebSocket URL
This avoids committing deployment-specific endpoint values to the repository.
netride/
├── server/
│ ├── main.c, car.c, auth.c, protocol.c, logger.c, *.h, Makefile
│ └── server.log # generated
├── clients/
│ ├── python_client/
│ │ ├── client.py, admin_client.py, telemetry_client.py, car.py
│ │ ├── requirements.txt
│ │ └── images/auto.png
│ └── js client/
│ ├── index.html, server.js, package.json
│ └── images/auto.png
├── .gitignore
└── README.md
- One thread per client; dedicated telemetry broadcast thread.
- Mutexes:
clients_lock,car_lock,sessions_lock. - Sessions keyed by socket fd; unique token per user.
- PTT validation, STATUS error counting,
log_printf()for console + file.
[SERVER] Listening on port 2000...
[SERVER] New client connected (fd=4)
[THREAD] Client connected (fd=4) from 127.0.0.1:12345
[AUTH] Login successful: admin (role=2) fd=4
[TELEMETRY] Sent to admin (fd=4)
[COMMAND] Executed 'SPEED UP' by admin fd=4
| Issue | Check |
|---|---|
| Won’t compile | gcc --version, pthread, MinGW/WSL on Windows |
| Python won’t connect | Server running, host/port, firewall |
| Web client | Bridge + HTTP server + C server running; hard refresh |
| Commands ignored | User must be ADMIN; server logs |
| Random disconnect | server.log, STATUS ERROR count (3 strikes) |
| No log file | Write permissions; logger.c linked in binary |
If login shows a generic connection error but backend services are healthy, the browser may be blocking cross-site WebSocket traffic due to strict privacy or anti-tracking protections.
Typical symptoms:
- Console shows
WebSocket connection ... failed - Network panel shows a
wsrequest without a completed handshake (101) - The same deployment works after relaxing privacy protections for that site
Recommended checks:
- Temporarily disable strict tracking protection for the frontend domain.
- Allow third-party connections for the site (or create a site exception).
- Hard refresh and retry login.
- Test in a second browser profile to confirm whether the issue is browser-policy related.
For production environments, using a single domain strategy (for example app and websocket under the same parent domain) reduces this class of browser blocking issues.
- Users: edit
users_dbinserver/auth.candusers_db_count. - Commands:
updateCarTelemetry()inserver/car.c+ UI buttons. - Telemetry interval:
sleep(10)insend_telemetry()inserver/main.c.