Skip to content

Latest commit

Β 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Reliable Group Notification System

A secure, reliable group notification system built over SSL/TLS-encrypted TCP sockets. Designed as the Jackfruit Mini Project for the Computer Networks Lab at PES University.


πŸ“Œ Project Abstract

The objective of this project is to design and implement a secure networked application using low-level socket programming. The system demonstrates:

  • TCP + SSL/TLS encrypted communication for all data and control exchanges
  • A custom binary protocol with sequence numbers, CRC32 checksums, and message framing
  • Application-layer reliability on top of SSL/TCP: ACK tracking, retransmission, and duplicate detection
  • Keep-Alive / Heartbeat for automatic detection and eviction of disconnected clients
  • A best-effort UDP baseline for head-to-head performance comparison
  • Automated testing under 0%–30% simulated packet loss with Matplotlib performance graphs

πŸ‘₯ Team Members

Roll Number Name Responsibility
PES2UG24CS030 Aditya Basavaraj Jambagi Server, SSL setup, ACK/Retransmit logic
PES2UG24CS033 Aditya Raj Client, Protocol design, Heartbeat
PES2UG24CS044 Aks Raj Singh Testing framework, Performance metrics

πŸ—οΈ System Architecture β€” Hybrid (SSL/TCP Auth + UDP Data)

                      NOTIFICATION SERVER (server.py)
                      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                      β”‚                                              β”‚
    Port 5001         β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
  β”Œβ”€SSL/TCP Auth───────  β”‚  accept_ssl_clients() thread           β”‚  β”‚
  β”‚  (SUBSCRIBE only) β”‚  β”‚  β†’ TLS 1.3 handshake (server.crt/.key) β”‚  β”‚
  β”‚                   β”‚  β”‚  β†’ Reads SUBSCRIBE + client's UDP port β”‚  β”‚
  β”‚                   β”‚  β”‚  β†’ Registers (IP, udp_port) in set     β”‚  β”‚
  β”‚                   β”‚  β”‚  β†’ Closes SSL connection (one-shot)    β”‚  β”‚
  β”‚                   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
  β”‚                   β”‚                                              β”‚
  β”‚   Port 5000       β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
  └──UDP Data──────────  β”‚  listen_udp() thread                   β”‚  β”‚
     (NOTIFY/ACK/     β”‚  β”‚  β†’ Receives ACK, HEARTBEAT, UNSUBSCRIBEβ”‚  β”‚
      HEARTBEAT/      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
      UNSUBSCRIBE)    β”‚                                              β”‚
                      β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                      β”‚  β”‚  retransmission_thread()               β”‚  β”‚
                      β”‚  β”‚  β†’ Retransmits unACK'd UDP packets     β”‚  β”‚
                      β”‚  β”‚  β†’ Evicts clients silent for 5s        β”‚  β”‚
                      β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                        β”‚
                     UDP broadcasts (NOTIFY) β†’ all subscribers
                          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                          β”‚                            β”‚
               β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
               β”‚    CLIENT A          β”‚    β”‚    CLIENT B          β”‚
               β”‚  (client.py)         β”‚    β”‚  (client.py)         β”‚
               β”‚                      β”‚    β”‚                      β”‚
               β”‚ 1. subscribe():      β”‚    β”‚ 1. subscribe():      β”‚
               β”‚    SSL/TCP to :5001  β”‚    β”‚    SSL/TCP to :5001  β”‚
               β”‚    sends UDP port    β”‚    β”‚    sends UDP port    β”‚
               β”‚    β†’ closes SSL      β”‚    β”‚    β†’ closes SSL      β”‚
               β”‚                      β”‚    β”‚                      β”‚
               β”‚ 2. listen() [UDP]:   β”‚    β”‚ 2. listen() [UDP]:   β”‚
               β”‚    recv NOTIFY       β”‚    β”‚    recv NOTIFY       β”‚
               β”‚    β†’ send ACK (UDP)  β”‚    β”‚    β†’ send ACK (UDP)  β”‚
               β”‚                      β”‚    β”‚                      β”‚
               β”‚ 3. heartbeat [UDP]:  β”‚    β”‚ 3. heartbeat [UDP]:  β”‚
               β”‚    ping every 2s     β”‚    β”‚    ping every 2s     β”‚
               β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Topology : Star (1 server ↔ N clients, individual unicast sockets)
Auth     : SSL/TLS (TLS 1.3) on port 5001 β€” SUBSCRIBE only (one-shot)
Data     : UDP on port 5000 β€” NOTIFY, ACK, HEARTBEAT, UNSUBSCRIBE
Protocol : Custom binary packet [4B seq | 1B type | 2B len | 2B CRC32] + payload

πŸ“¦ Custom Packet Format

Every message β€” whether a SUBSCRIBE, NOTIFY, ACK, HEARTBEAT, or UNSUBSCRIBE β€” uses the same 9-byte binary header format defined in protocol.py:

 0       4   5     7     9         9 + payload_len
 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
 β”‚ Seq Num   β”‚Tyβ”‚ Len  β”‚ CRC  β”‚     Payload        β”‚
 β”‚ (4 bytes) β”‚peβ”‚(2 B) β”‚(2 B) β”‚  (variable length) β”‚
 β”‚ uint32    β”‚(1β”‚uint16β”‚uint16β”‚  UTF-8 string      β”‚
 β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
  • Seq Num: Monotonically increasing ID for reliable delivery tracking
  • Type: 1=SUBSCRIBE, 2=NOTIFY, 3=ACK, 4=UNSUBSCRIBE, 5=HEARTBEAT
  • Len: Payload byte count (used by TCP framing helpers)
  • CRC: 16-bit CRC32 checksum for corruption detection
  • Payload: For NOTIFY: "timestamp|message" (timestamp used for latency calculation)

πŸ”’ SSL/TLS Security

All communication between the server and clients is encrypted using TLS 1.3 via Python's built-in ssl module.

Certificate Files

File Description
server.crt X.509 self-signed public certificate (shared)
server.key RSA-2048 private key (kept on server only)

Regenerating Certificates

If the certificates expire or are missing, regenerate them with:

openssl req -x509 -newkey rsa:2048 \
            -keyout server.key \
            -out server.crt \
            -days 365 \
            -nodes \
            -subj '/CN=localhost'

Note: The -nodes flag skips passphrase encryption on the private key (required for non-interactive server startup). For production environments, use a CA-signed certificate and enable ssl.CERT_REQUIRED on the client.


πŸ› οΈ Requirements

Requirement Version / Notes
Python 3.8 or higher
ssl Built into Python standard library
socket Built into Python standard library
struct Built into Python standard library
zlib Built into Python standard library
matplotlib For performance graph generation

Install matplotlib:

pip install matplotlib

Verify SSL certificate files exist before starting the server:

ls -lh server.crt server.key

πŸš€ The Project Demo

Method A: The Localhost Demo

This method proves the entire Hybrid Architecture (TLS + UDP) works perfectly without fighting university firewalls or mobile hotspot AP isolation.

  1. Open Terminal 1 (The Server)
    python3 server.py
  2. Open Terminal 2 (Client 1)
    python3 client.py
  3. Open Terminal 3 (Client 2)
    python3 client.py
  4. Test the Broadcast Go back to Terminal 1, type Hello world! and press Enter. You will instantly see the UDP broadcast hit both clients, and see the ACKs returned to the server.

Method B: Cross-Device Demo (Between Two Laptops)

Note: This will NOT work on an iPhone/Android Mobile Hotspot or University Wi-Fi due to "Client AP Isolation" hardware firewalls dropping peer-to-peer UDP packets. You MUST be connected to a normal Home Router.

  1. On Laptop 1 (The Mac/Server): Find your IP Address:

    ipconfig getifaddr en0

    (Let's assume it prints 192.168.1.5)

    Start the server:

    python3 server.py
  2. On Laptop 2 (The Windows/Friend's PC): Ensure they have the latest code, then run the client by typing the Mac's IP address directly in the command:

    python client.py 192.168.1.5
  3. Test the Broadcast: Type a message on the Mac server, and it will instantly pop up on the Windows laptop securely!

5. Run Automated Performance Tests

Runs all tests (0%–30% loss) for both systems and saves the graph:

python3 test_system.py

Output: performance_results.png with 4 comparison panels.


πŸ“Š Architecture & Design Decisions

Why TCP instead of UDP for the Reliable system?

SSL/TLS was designed specifically for stream-oriented (TCP) sockets. While DTLS (Datagram TLS) exists for UDP, Python's ssl module does not natively support it. Switching to TCP+SSL gives us full encryption with standard library support.

Why keep ACKs and retransmission on top of TCP?

TCP guarantees bytes arrive at the OS receive buffer. Our application-level ACKs provide a stronger guarantee: the client application processed the notification. This semantic difference is important for notification systems where silent drops (app crashed after receive but before processing) would otherwise go undetected.

Why star topology with unicast?

Unlike multicast (which has router support requirements), unicast over individual SSL sockets gives us per-client delivery tracking. We know exactly which client received which message and can retransmit selectively.


πŸ“ˆ Performance Findings

Tests conducted with 3 clients, 5 notifications per run, at four loss levels:

Metric System 0% Loss 10% Loss 20% Loss 30% Loss
Delivery Rate Reliable SSL ~100% ~100% ~100% ~90-100%
Delivery Rate Plain UDP ~100% ~80% ~65% ~50%
Avg Latency Reliable SSL Low Moderate Moderate High
Avg Latency Plain UDP Low Low Low Low*
Retransmissions Reliable SSL 0 Low Moderate High

*Plain UDP latency appears lower at high loss because undelivered messages are simply not counted β€” the sample set is smaller and biased toward fast arrivals.

Key Takeaway

At 30% packet loss, Plain UDP delivers only ~50% of messages. Our Reliable SSL system maintains 90–100% delivery β€” at the cost of higher latency due to retransmission wait times. This is the classic reliability vs. latency tradeoff in network systems design.


πŸ“‚ File Overview

File Description
protocol.py Custom binary packet format, CRC checksum, TCP framing helpers
server.py SSL/TCP notification server with ACK, retransmit, heartbeat
client.py SSL/TCP subscriber client with listener, heartbeat, latency track
plain_udp.py Best-effort UDP baseline (no SSL, no ACKs, no retransmission)
test_system.py Automated testing framework β€” 4 metrics, 4 loss levels, 4 graphs
server.crt SSL public certificate (X.509, self-signed, RSA-2048)
server.key SSL private key (RSA-2048, not encrypted, lab use only)
performance_results.png Output graph from the last test run

About

A reliable UDP-based group notification system with ACK and retransmission tracking

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages