A reliable, ordered, connection-oriented transport protocol — SHAM — built from scratch in C on top of raw UDP datagrams. UDP gives you only best-effort delivery: packets can be dropped, duplicated, or reordered, with no connection and no guarantees. RUDP layers TCP-style reliability on top of it: a connection handshake, sequenced data with acknowledgements, retransmission of what gets lost, and in-order reassembly at the receiver — validated under deliberately injected packet loss.
- 3-way handshake (
SYN→SYN-ACK→ACK) with random initial sequence numbers to establish a connection, and a 4-way FIN teardown to close it cleanly. - Sliding-window sender (
SHAM_SND_WIN_PKTSpackets in flight) with cumulative ACKs, duplicate-ACK detection, and receiver-advertised flow control (the receiver's free buffer is carried in every header'swindow_size, and the sender never overruns it). - RTO-based retransmission: unacknowledged segments are resent after a fixed retransmission timeout (
SHAM_RTO_MS), so loss anywhere in the path is recovered. - Out-of-order reassembly: the receiver buffers segments that arrive early and delivers bytes to the application strictly in sequence.
- 12-byte fixed header (
seq,ack,flags,window), packed/unpacked in network byte order — seesham.h. - End-to-end integrity check: in file-transfer mode the server prints the MD5 of the received file so it can be compared against the source.
Requires GCC and OpenSSL headers (the server links -lcrypto for MD5).
make # builds ./server and ./clientThe protocol supports two modes: file transfer and interactive chat. The optional trailing loss_rate (e.g. 0.1 = 10%) makes the receiver randomly drop incoming packets so you can watch retransmission and reassembly recover the stream.
# Server
./server <port> [--chat] [loss_rate]
# Client — file transfer:
./client <server_ip> <server_port> <input_file> <output_file_name> [loss_rate]
# Client — chat:
./client <server_ip> <server_port> --chat [loss_rate]# terminal 1 — receive into out.bin, dropping 20% of incoming packets
./server 9000 0.2
# terminal 2 — send big.bin; it arrives intact despite the loss
./client 127.0.0.1 9000 big.bin out.binThe server prints the MD5 of out.bin on completion; it matches md5sum big.bin even though packets were dropped mid-transfer, demonstrating that the retransmission + reassembly layer delivers the data reliably.
./server 9000 --chat # one side
./client 127.0.0.1 9000 --chat # other sideBoth server.c and client.c run every received packet through a loss filter (should_drop_rx) gated by the loss_rate argument. Dropped packets are logged (DROP DATA SEQ=…), the sender's RTO fires, the segment is retransmitted (RETX …), and the receiver reassembles in order — so the protocol's correctness can be verified at any loss level without needing a real lossy network. Each side writes a timestamped packet log (server_log.txt / client_log.txt) tracing every SND/RCV/RETX/DROP for inspection.
Protocol constants live in sham.h: SHAM_MSS_DATA (payload size), SHAM_SND_WIN_PKTS (window), SHAM_RTO_MS (retransmit timeout), SHAM_RECV_BUF_CAP (advertised receive buffer).
Scope: this implements reliability, ordering, and flow control. It does not implement TCP-style congestion control (the in-flight window is fixed rather than adapting to network congestion).