From 19361a839f77c3124a8aad9632a9299df680d582 Mon Sep 17 00:00:00 2001 From: Ajurna Date: Fri, 1 Aug 2025 08:47:25 +0100 Subject: [PATCH] server06 start --- CMakeLists.txt | 2 + server06.c | 43 +++++++++ server06.h | 70 +++++++++++++++ speed_ticket_monitoring_system.py | 141 ++++++++++++++++++++++++++++++ 4 files changed, 256 insertions(+) create mode 100644 server06.c create mode 100644 server06.h create mode 100644 speed_ticket_monitoring_system.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 08b0afe..8ecaf2a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,3 +35,5 @@ add_executable(server04 server04.c server04.h ${COMMON_SOURCES}) target_link_libraries(server04 wsock32 ws2_32) add_executable(server05 server05.c server05.h ${COMMON_SOURCES}) target_link_libraries(server05 wsock32 ws2_32 PCRE2::8BIT) +add_executable(server06 server06.c server06.h ${COMMON_SOURCES}) +target_link_libraries(server06 wsock32 ws2_32 PCRE2::8BIT) \ No newline at end of file diff --git a/server06.c b/server06.c new file mode 100644 index 0000000..6a690f2 --- /dev/null +++ b/server06.c @@ -0,0 +1,43 @@ +// +// Created by Ajurna on 01/08/2025. +// + +#include "server06.h" +#include +#include +#include "data.h" +#include + +int main() { + SOCKET server = get_listen_socket(); + SOCKADDR_IN clientAddr; + SOCKET client; + int clientAddrSize = sizeof(clientAddr); + int connection_number = 1; + printf("Listening for incoming connections...\n"); + while((client = accept(server, (SOCKADDR *)&clientAddr, &clientAddrSize)) != INVALID_SOCKET) + { + handle_args_t *args = malloc(sizeof(handle_args_t)); + args->client = client; + args->connection = connection_number++; + pthread_t thread; + pthread_create(&thread, nullptr, handle_connection, args); + } + return 0; +} + +void *handle_connection(void *args) { + handle_args_t *handleArgs = args; + char buffer[1024] = {0}; + int bytesReceived; + connection_type_t connection_type = UNKNOWN; + byte_array_t *data = byte_array_create(1024); + while ((bytesReceived = recv(handleArgs->client, buffer, sizeof(buffer), 0)) > 0) { + printf("Client sent {%d}: |%d| \n", handleArgs->connection, bytesReceived); + byte_array_append(data, buffer, bytesReceived); + char *request; + while ((request = byte_array_get_bytes(data, 1)) != NULL) { + parse_request(handleArgs, request, data); + } + } +} \ No newline at end of file diff --git a/server06.h b/server06.h new file mode 100644 index 0000000..e6d45f7 --- /dev/null +++ b/server06.h @@ -0,0 +1,70 @@ +// +// Created by Ajurna on 01/08/2025. +// + +#ifndef SERVER06_H +#define SERVER06_H +#include +#include + +#endif //SERVER06_H + +typedef struct handleArgs { + int connection; + SOCKET client; +}handle_args_t; + +typedef enum ConnectionType { + UNKNOWN, + CAMERA, + DISPATCHER, +} connection_type_t; + +typedef enum MessageType { + ERROR_MSG = 0x10, + PLATE_MSG = 0x20, + TICKET_MSG = 0x21, + WANT_HEARTBEAT_MSG = 0x40, + HEARTBEAT_MSG = 0x41, + I_AM_CAMERA_MSG = 0x80, + I_AM_DISPATCHER_MSG = 0x81, +}message_type_t; + +typedef struct ErrorMsg { + char *message; +} error_msg_t; + +typedef struct PlateMsg { + char *plate; + uint32_t timestamp; +} plate_msg_t; + +typedef struct TicketMsg { + char *plate; + uint16_t road; + uint16_t mile1; + uint32_t timestamp1; + uint16_t mile2; + uint32_t timestamp2; + uint16_t speed; +} ticket_msg_t; + +typedef struct WantHeartbeatMsg { + uint32_t timestamp; +} want_heartbeat_msg_t; + +typedef struct HeartbeatMsg { + +} heartbeat_msg_t; + +typedef struct IAmCameraMsg { + uint16_t road; + uint16_t mile; + uint16_t limit; +} i_am_camera_msg_t; + +typedef struct IAmDispatcherMsg { + uint16_t *road; +} i_am_dispatcher_msg_t; + +void *handle_connection(void *args); \ No newline at end of file diff --git a/speed_ticket_monitoring_system.py b/speed_ticket_monitoring_system.py new file mode 100644 index 0000000..92786ea --- /dev/null +++ b/speed_ticket_monitoring_system.py @@ -0,0 +1,141 @@ +import socket +import struct +import time +from threading import Thread +from typing import List, Optional + +class MessageType: + ERROR = 0x10 + PLATE = 0x20 + TICKET = 0x21 + WANT_HEARTBEAT = 0x40 + HEARTBEAT = 0x41 + I_AM_CAMERA = 0x80 + I_AM_DISPATCHER = 0x81 + +class SpeedDaemonClient: + def __init__(self, host: str = 'localhost', port: int = 12345): + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect((host, port)) + self.running = True + self.received_tickets = [] + + def send_bytes(self, data: bytes): + self.socket.send(data) + + def receive_message(self) -> Optional[tuple]: + try: + msg_type = self.socket.recv(1) + if not msg_type: + return None + + msg_type = msg_type[0] + + if msg_type == MessageType.ERROR: + length = struct.unpack('!B', self.socket.recv(1))[0] + message = self.socket.recv(length).decode('ascii') + return (MessageType.ERROR, message) + + elif msg_type == MessageType.TICKET: + # Read plate length + plate_len = struct.unpack('!B', self.socket.recv(1))[0] + plate = self.socket.recv(plate_len).decode('ascii') + + # Read other fields + data = self.socket.recv(16) + road, mile1, timestamp1, mile2, timestamp2, speed = struct.unpack('!HHIHHI', data) + return (MessageType.TICKET, { + 'plate': plate, + 'road': road, + 'mile1': mile1, + 'timestamp1': timestamp1, + 'mile2': mile2, + 'timestamp2': timestamp2, + 'speed': speed + }) + + elif msg_type == MessageType.HEARTBEAT: + return (MessageType.HEARTBEAT, None) + + except Exception as e: + print(f"Error receiving message: {e}") + return None + + def close(self): + self.running = False + self.socket.close() + +class Camera(SpeedDaemonClient): + def __init__(self, road: int, mile: int, limit: int, host: str = 'localhost', port: int = 12345): + super().__init__(host, port) + self.road = road + self.mile = mile + self.limit = limit + self.register() + + def register(self): + # Send IAmCamera message + msg = struct.pack('!BHHH', MessageType.I_AM_CAMERA, self.road, self.mile, self.limit) + self.send_bytes(msg) + + def report_plate(self, plate: str, timestamp: int): + # Send Plate message + msg = struct.pack(f'!BB{len(plate)}sI', MessageType.PLATE, len(plate), + plate.encode('ascii'), timestamp) + self.send_bytes(msg) + +class Dispatcher(SpeedDaemonClient): + def __init__(self, roads: List[int], host: str = 'localhost', port: int = 12345): + super().__init__(host, port) + self.roads = roads + self.register() + # Start listening for tickets + self.listener_thread = Thread(target=self._listen_for_tickets) + self.listener_thread.start() + + def register(self): + # Send IAmDispatcher message + roads_data = struct.pack(f'!{len(self.roads)}H', *self.roads) + msg = struct.pack('!BB', MessageType.I_AM_DISPATCHER, len(self.roads)) + roads_data + self.send_bytes(msg) + + def _listen_for_tickets(self): + while self.running: + message = self.receive_message() + if message and message[0] == MessageType.TICKET: + self.received_tickets.append(message[1]) + +def run_speed_test(): + # Create a dispatcher for road 123 + dispatcher = Dispatcher([123]) + time.sleep(0.1) # Give dispatcher time to register + + # Create two cameras on road 123 + camera1 = Camera(123, 8, 60) # Camera at mile 8, 60mph limit + camera2 = Camera(123, 9, 60) # Camera at mile 9, same limit + time.sleep(0.1) # Give cameras time to register + + # Report a speeding car (same as in example session) + camera1.report_plate("UN1X", 0) + camera2.report_plate("UN1X", 45) # 1 mile in 45 seconds = 80mph + + # Wait for ticket processing + time.sleep(1) + + # Check received tickets + if dispatcher.received_tickets: + print("Test passed! Received tickets:") + for ticket in dispatcher.received_tickets: + print(f"Plate: {ticket['plate']}") + print(f"Road: {ticket['road']}") + print(f"Speed: {ticket['speed']/100.0} mph") + else: + print("Test failed: No tickets received") + + # Cleanup + dispatcher.close() + camera1.close() + camera2.close() + +if __name__ == "__main__": + run_speed_test()