From 4fb58b9727adf5ae8dd19f4798caf3efd62621f8 Mon Sep 17 00:00:00 2001 From: andrei-mihnea-cerbu Date: Tue, 12 Nov 2024 16:13:07 +0200 Subject: [PATCH] refactor networking --- CEO/src/network/connection_manager.ts | 3 -- CEO/src/network/tcp/tcp_client.ts | 38 +++++++++++----- CEO/src/network/tcp/tcp_server.ts | 31 ++++++++----- CEO/src/network/udp/udp_client.ts | 28 ++++++++++-- CEO/src/network/udp/udp_server.ts | 27 +++++++++--- UC/src/network/connection_manager.ts | 3 -- UC/src/tcp_server.ts | 61 +++++++++++++------------- UC/src/udp_server.ts | 37 ++++++++++------ User/src/network/connection_manager.ts | 3 -- User/src/network/tcp/tcp_client.ts | 38 +++++++++++----- User/src/network/tcp/tcp_server.ts | 31 ++++++++----- User/src/network/udp/udp_client.ts | 28 ++++++++++-- User/src/network/udp/udp_server.ts | 27 +++++++++--- 13 files changed, 240 insertions(+), 115 deletions(-) diff --git a/CEO/src/network/connection_manager.ts b/CEO/src/network/connection_manager.ts index f7f29f8..6dba3eb 100644 --- a/CEO/src/network/connection_manager.ts +++ b/CEO/src/network/connection_manager.ts @@ -19,8 +19,6 @@ export class ConnectionManager { this.connections[key] = { communicator }; - - console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`); } // Removes a communicator based on IP and port @@ -28,7 +26,6 @@ export class ConnectionManager { const key = `${ip}:${port}`; if (this.connections[key]) { delete this.connections[key]; - console.log(`Removed communicator for ${ip}:${port}`); } } diff --git a/CEO/src/network/tcp/tcp_client.ts b/CEO/src/network/tcp/tcp_client.ts index 7ad64f3..e4492b5 100644 --- a/CEO/src/network/tcp/tcp_client.ts +++ b/CEO/src/network/tcp/tcp_client.ts @@ -24,29 +24,40 @@ export class TcpClient { this.operationHandler.loadPlugin(new UserToUserOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[TcpClient]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Open a TCP socket connection openSocket(ip: string): void { this.socket = new net.Socket(); this.socket.connect(this.tcp_port, ip, () => { - //console.log(`Client connected to server at ${ip}:${this.tcp_port}`); + this.log(`Connected to server at ${ip}:${this.tcp_port}`); this.communicator = new TcpClientCommunicator(this.socket as Socket, ip, this.tcp_port, this.operationHandler); }); this.socket.on('error', (err) => { - //console.error(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`); + this.log(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`, 'error'); }); this.socket.on('data', async (data: Buffer) => { if (this.communicator) { - await this.communicator.handleIncomingChunk(data); // Let the communicator handle the chunks + await this.communicator.handleIncomingChunk(data); this.lastResult = this.communicator.getHandlerResult(); + this.log(`Data received from ${ip}:${this.tcp_port}`); } }); this.socket.on('close', () => { - //console.log(`Connection closed: ${ip}:${this.tcp_port}`); - this.lastResult = null; // Clear the last result on socket close + this.log(`Connection closed: ${ip}:${this.tcp_port}`); + this.lastResult = null; }); } @@ -56,26 +67,27 @@ export class TcpClient { this.socket.end(); this.socket = null; this.communicator = null; - this.lastResult = null; // Clear the last result on close - //console.log('Client socket connection closed.'); + this.lastResult = null; + this.log('Client socket connection closed.'); } } // Send a message with operationCode, metaInfo, and fileContent in chunks async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise { if (!this.communicator || !this.isAesKeySet()) { - //console.error('Communicator not initialized or AES key not set.'); + this.log('Communicator not initialized or AES key not set.', 'error'); return false; } - await this.communicator.sendChunkedMessage(operationCode, metaInfo, fileContent); // Send message via communicator + this.log(`Sending message with operationCode: ${operationCode}`); + await this.communicator.sendChunkedMessage(operationCode, metaInfo, fileContent); return true; } // Check if AES key is set isAesKeySet(): boolean { - if(!this.communicator) return false; - return this.communicator?.isAesKeySet() + if (!this.communicator) return false; + return this.communicator?.isAesKeySet(); } // Check if the message is received (based on if lastResult is available) @@ -92,6 +104,8 @@ export class TcpClient { // Check if the socket is still connected isSocketConnected(): boolean { - return this.socket !== null && !this.socket.destroyed; + const connected = this.socket !== null && !this.socket.destroyed; + this.log(`Socket connected: ${connected}`); + return connected; } } diff --git a/CEO/src/network/tcp/tcp_server.ts b/CEO/src/network/tcp/tcp_server.ts index e0e66ab..aabb408 100644 --- a/CEO/src/network/tcp/tcp_server.ts +++ b/CEO/src/network/tcp/tcp_server.ts @@ -25,6 +25,16 @@ export class TcpServer { this.operationHandler.loadPlugin(new UserToUserOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[TcpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Start the TCP server public start(): void { const tcpServer = net.createServer(); @@ -33,9 +43,9 @@ export class TcpServer { tcpServer.on('connection', (socket: Socket) => { const ip = socket.remoteAddress || 'unknown'; const port = socket.remotePort || 0; + const clientId = `${ip}:${port}`; - const clientId = `${ip}:${port}`; // Use IP and port to identify the client - //console.log(`Client connected: ${clientId}`); + this.log(`Client connected: ${clientId}`); const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler); this.connectionManager.addConnection(ip, port, tcpCommunicator); @@ -45,36 +55,37 @@ export class TcpServer { tcpCommunicator.sendPublicKey() .then(() => tcpCommunicator.sendAesKey()) .catch(err => { - //console.error(`Error during key exchange with client ${clientId}:`, err); + this.log(`Error during key exchange with client ${clientId}: ${err}`, 'error'); socket.end(); // Close the connection in case of any error }); // Handle incoming data in chunks socket.on('data', async (data: Buffer) => { + this.log(`Data received from client ${clientId}`); await this.handleData(data, ip, port); }); // Handle client disconnect socket.on('end', () => { - //console.log(`Client disconnected: ${clientId}`); + this.log(`Client disconnected: ${clientId}`); this.connectionManager.removeCommunicator(ip, port); }); // Handle socket errors socket.on('error', (err: Error) => { - //console.error(`Error from client ${clientId}: ${err.message}`); + this.log(`Error from client ${clientId}: ${err.message}`, 'error'); this.connectionManager.removeCommunicator(ip, port); }); }); // Handle server errors tcpServer.on('error', (err: Error) => { - console.error(`TCP server error: ${err.message}`); + this.log(`TCP server error: ${err.message}`, 'error'); }); // Start listening for connections tcpServer.listen(this.port, this.host, () => { - console.log(`TCP server listening on ${this.host}:${this.port}`); + this.log(`TCP server listening on ${this.host}:${this.port}`); }); } @@ -85,7 +96,7 @@ export class TcpServer { // Retrieve the communicator associated with this connection const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator; if (!communicator) { - //console.error(`No communicator found for ${clientId}`); + this.log(`No communicator found for ${clientId}`, 'error'); return; } @@ -101,9 +112,9 @@ export class TcpServer { handlerResult.metaInfo, handlerResult.fileContent ); - //console.log(`Response sent to ${clientId}`); + this.log(`Response sent to ${clientId}`); } catch (err) { - //console.error(`Failed to send response to ${clientId}:`, err); + this.log(`Failed to send response to ${clientId}: ${err}`, 'error'); } } } diff --git a/CEO/src/network/udp/udp_client.ts b/CEO/src/network/udp/udp_client.ts index 03789b2..2449639 100644 --- a/CEO/src/network/udp/udp_client.ts +++ b/CEO/src/network/udp/udp_client.ts @@ -18,6 +18,16 @@ export class UdpClient { this.operationHandler.loadPlugin(new GeneralOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UdpClient]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses async getAliveClients(): Promise { const subnet = this.getSubnet(); @@ -25,9 +35,11 @@ export class UdpClient { // Get local machine's IP addresses to exclude const localIPs = this.getLocalIPs(); + this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`); // First, filter active IPs that respond to ping const activeIps = await this.filterActiveIps(ipRange); + this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`); // Send heartbeat to each active IP and keep only those that respond with ALIVE const aliveClients: string[] = []; @@ -40,7 +52,8 @@ export class UdpClient { } } - return aliveClients; // Return the list of IPs that responded with ALIVE, excluding the host machine + this.log(`Alive clients (excluding local machine): ${aliveClients.join(', ')}`); + return aliveClients; } // Get local IP addresses of the host machine (excluding loopback) @@ -65,8 +78,10 @@ export class UdpClient { const heartbeatCode = operationCodes.HEARTBEAT; const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode); + this.log(`Sending heartbeat to ${ip}`); this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => { if (err) { + this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error'); resolve({ found: false }); } else { const timeout = setTimeout(() => { @@ -79,8 +94,10 @@ export class UdpClient { clearTimeout(timeout); const parsedMessage = MessageHandler.parseMessage(msg.toString()); if (parsedMessage?.operationCode === operationCodes.ALIVE) { + this.log(`Received ALIVE response from ${ip}`); resolve({ found: true }); } else { + this.log(`Unexpected response from ${ip}`); resolve({ found: false }); } } @@ -94,8 +111,9 @@ export class UdpClient { private dropConnection(ip: string): void { try { this.udpSocket.removeAllListeners('message'); + this.log(`Dropped connection listeners for ${ip}`); } catch (err: any) { - console.error(`Error dropping connection to ${ip}: ${err.message}`); + this.log(`Error dropping connection to ${ip}: ${err.message}`, 'error'); } } @@ -105,7 +123,9 @@ export class UdpClient { for (const iface of Object.values(interfaces)) { for (const address of iface || []) { if (address.family === 'IPv4' && !address.internal) { - return address.address.split('.').slice(0, 3).join('.'); + const subnet = address.address.split('.').slice(0, 3).join('.'); + this.log(`Detected subnet: ${subnet}`); + return subnet; } } } @@ -118,6 +138,7 @@ export class UdpClient { for (let i = 1; i < 255; i++) { ipRange.push(`${subnet}.${i}`); } + this.log(`Generated IP range for subnet ${subnet}`); return ipRange; } @@ -135,6 +156,7 @@ export class UdpClient { } } + this.log(`Active IPs after pinging: ${activeIps.join(', ')}`); return activeIps; } } diff --git a/CEO/src/network/udp/udp_server.ts b/CEO/src/network/udp/udp_server.ts index 3c66550..7111ed7 100644 --- a/CEO/src/network/udp/udp_server.ts +++ b/CEO/src/network/udp/udp_server.ts @@ -1,7 +1,7 @@ import dgram, { RemoteInfo } from 'dgram'; import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator"; import { OperationHandler } from "../operations_base/operation_handler"; -import { GeneralOperations} from "../operations_custom/general_operations"; +import { GeneralOperations } from "../operations_custom/general_operations"; export class UdpServer { private readonly udpServer: dgram.Socket; @@ -19,10 +19,20 @@ export class UdpServer { this.operationHandler.loadPlugin(new GeneralOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UdpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Start the UDP server public start(): void { this.udpServer.on('message', this.handleUdpMessages.bind(this)); - this.udpServer.on('error', this.handleError); + this.udpServer.on('error', this.handleError.bind(this)); this.udpServer.on('listening', this.handleListening.bind(this)); // Bind the server to the UDP port and host @@ -34,7 +44,7 @@ export class UdpServer { const ip = rinfo.address; const port = rinfo.port; - //console.log(`Received message from ${ip}:${port}`); + this.log(`Received message from ${ip}:${port}`); // Create a temporary communicator for the incoming message const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler); @@ -45,18 +55,23 @@ export class UdpServer { const communicatorResult = communicator.getHandlerResult(); if (communicatorResult) { // Send response back to the client using the temporary communicator - await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + try { + await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + this.log(`Sent response to ${ip}:${port}`); + } catch (error: any) { + this.log(`Error sending response to ${ip}:${port}: ${error.message}`, 'error'); + } } } // Handle UDP server errors private handleError(err: Error): void { - console.error(`UDP server error:\n${err.stack}`); + this.log(`UDP server error:\n${err.stack}`, 'error'); } // Handle when the UDP server starts listening private handleListening(): void { const address = this.udpServer.address(); - console.log(`UDP server listening on ${address.address}:${address.port}`); + this.log(`UDP server listening on ${address.address}:${address.port}`); } } diff --git a/UC/src/network/connection_manager.ts b/UC/src/network/connection_manager.ts index f7f29f8..6dba3eb 100644 --- a/UC/src/network/connection_manager.ts +++ b/UC/src/network/connection_manager.ts @@ -19,8 +19,6 @@ export class ConnectionManager { this.connections[key] = { communicator }; - - console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`); } // Removes a communicator based on IP and port @@ -28,7 +26,6 @@ export class ConnectionManager { const key = `${ip}:${port}`; if (this.connections[key]) { delete this.connections[key]; - console.log(`Removed communicator for ${ip}:${port}`); } } diff --git a/UC/src/tcp_server.ts b/UC/src/tcp_server.ts index a67bc75..1c60e3e 100644 --- a/UC/src/tcp_server.ts +++ b/UC/src/tcp_server.ts @@ -3,14 +3,14 @@ import path from 'path'; import dotenv from 'dotenv'; import { ConnectionManager } from './network/connection_manager'; -import {OperationHandler} from "./network/operations_base/operation_handler"; -import {GeneralOperations} from "./network/operations_custom/general_operations"; -import {TcpServerCommunicator} from "./network/socket_communicator/tcp_server_communicator"; -import {CeoOperations} from "./network/operations_custom/ceo_operations"; -import {AuthOperations} from "./network/operations_custom/auth_operations"; -import {DepartmentOperations} from "./network/operations_custom/department_operations"; -import {KeyOperations} from "./network/operations_custom/key_operations"; -import {UserOperations} from "./network/operations_custom/user_operations"; +import { OperationHandler } from "./network/operations_base/operation_handler"; +import { GeneralOperations } from "./network/operations_custom/general_operations"; +import { TcpServerCommunicator } from "./network/socket_communicator/tcp_server_communicator"; +import { CeoOperations } from "./network/operations_custom/ceo_operations"; +import { AuthOperations } from "./network/operations_custom/auth_operations"; +import { DepartmentOperations } from "./network/operations_custom/department_operations"; +import { KeyOperations } from "./network/operations_custom/key_operations"; +import { UserOperations } from "./network/operations_custom/user_operations"; dotenv.config({ path: path.resolve(__dirname, './config/.env') }); @@ -32,60 +32,62 @@ export class TcpServer { this.operationHandler.loadPlugin(new DepartmentOperations()); this.operationHandler.loadPlugin(new KeyOperations()); this.operationHandler.loadPlugin(new UserOperations()); + } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[TcpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } } // Start the TCP server public start(): void { const tcpServer = net.createServer(); - // Handle incoming connections tcpServer.on('connection', (socket: Socket) => { const ip = socket.remoteAddress || 'unknown'; const port = socket.remotePort || 0; + const clientId = `${ip}:${port}`; - const clientId = `${ip}:${port}`; // Use IP and port to identify the client - console.log(`Client connected: ${clientId}`); + this.log(`Client connected: ${clientId}`); const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler); this.connectionManager.addConnection(ip, port, tcpCommunicator); - // Generate RSA key pair and start key exchange tcpCommunicator.generateKeyPair(); tcpCommunicator.sendPublicKey() .then(() => tcpCommunicator.sendAesKey()) - .then(() => console.log('Public key and AES key sent successfully.')) + .then(() => this.log('Public key and AES key sent successfully.')) .catch(err => { - console.error(`Error during key exchange with client ${clientId}:`, err); - socket.end(); // Close the connection in case of any error + this.log(`Error during key exchange with client ${clientId}: ${err.message}`, 'error'); + socket.end(); }); - // Handle incoming data in chunks socket.on('data', async (data: Buffer) => { await this.handleData(data, ip, port); }); - // Handle client disconnect socket.on('end', () => { - console.log(`Client disconnected: ${clientId}`); + this.log(`Client disconnected: ${clientId}`); this.connectionManager.removeCommunicator(ip, port); }); - // Handle socket errors socket.on('error', (err: Error) => { - console.error(`Error from client ${clientId}: ${err.message}`); + this.log(`Error from client ${clientId}: ${err.message}`, 'error'); this.connectionManager.removeCommunicator(ip, port); }); }); - // Handle server errors tcpServer.on('error', (err: Error) => { - console.error(`TCP server error: ${err.message}`); + this.log(`TCP server error: ${err.message}`, 'error'); }); - // Start listening for connections tcpServer.listen(this.port, this.host, () => { - console.log(`TCP server listening on ${this.host}:${this.port}`); + this.log(`TCP server listening on ${this.host}:${this.port}`); }); } @@ -93,17 +95,14 @@ export class TcpServer { private async handleData(data: Buffer, ip: string, port: number): Promise { const clientId = `${ip}:${port}`; - // Retrieve the communicator associated with this connection const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator; if (!communicator) { - console.error(`No communicator found for ${clientId}`); + this.log(`No communicator found for ${clientId}`, 'error'); return; } - // Handle incoming chunked message via communicator await communicator.handleIncomingChunk(data); - // Fetch and process result if available const handlerResult = communicator.getHandlerResult(); if (handlerResult) { try { @@ -112,9 +111,9 @@ export class TcpServer { handlerResult.metaInfo, handlerResult.fileContent ); - console.log(`Response sent to ${clientId}`); - } catch (err) { - console.error(`Failed to send response to ${clientId}:`, err); + this.log(`Response sent to ${clientId}`); + } catch (err: any) { + this.log(`Failed to send response to ${clientId}: ${err.message}`, 'error'); } } } diff --git a/UC/src/udp_server.ts b/UC/src/udp_server.ts index 87e32e9..8ea867b 100644 --- a/UC/src/udp_server.ts +++ b/UC/src/udp_server.ts @@ -5,30 +5,39 @@ import { UdpSocketCommunicator } from "./network/socket_communicator/udp_socket_ import { OperationHandler } from "./network/operations_base/operation_handler"; import { GeneralOperations } from "./network/operations_custom/general_operations"; +dotenv.config({ path: path.resolve(__dirname, './config/.env') }); + export class UdpServer { private readonly udpServer: dgram.Socket; private readonly operationHandler: OperationHandler; private readonly host: string; - private readonly port: number + private readonly port: number; constructor(host: string, port: number) { this.udpServer = dgram.createSocket('udp4'); this.operationHandler = OperationHandler.getInstance(); - this.host = host; this.port = port; - // Load only the GeneralOperations into the operation handler this.operationHandler.loadPlugin(new GeneralOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UdpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Start the UDP server public start(): void { this.udpServer.on('message', this.handleUdpMessages.bind(this)); - this.udpServer.on('error', this.handleError); + this.udpServer.on('error', this.handleError.bind(this)); this.udpServer.on('listening', this.handleListening.bind(this)); - // Bind the server to the UDP port and host this.udpServer.bind(this.port, this.host); } @@ -37,31 +46,33 @@ export class UdpServer { const ip = rinfo.address; const port = rinfo.port; - console.log(`Received message from ${ip}:${port}`); + this.log(`Received message from ${ip}:${port}`); - // Create a temporary communicator for the incoming message const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler); - // Process the incoming message using the communicator communicator.handleIncomingMessage(msg.toString()); const communicatorResult = communicator.getHandlerResult(); if (communicatorResult) { - // Send response back to the client using the temporary communicator - await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + try { + await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + this.log(`Response sent to ${ip}:${port}`); + } catch (error: any) { + this.log(`Error sending response to ${ip}:${port}: ${error.message}`, 'error'); + } } else { - console.error(`No handler result for ${ip}:${port}`); + this.log(`No handler result for ${ip}:${port}`, 'error'); } } // Handle UDP server errors private handleError(err: Error): void { - console.error(`UDP server error:\n${err.stack}`); + this.log(`UDP server error:\n${err.stack}`, 'error'); } // Handle when the UDP server starts listening private handleListening(): void { const address = this.udpServer.address(); - console.log(`UDP server listening on ${address.address}:${address.port}`); + this.log(`UDP server listening on ${address.address}:${address.port}`); } } diff --git a/User/src/network/connection_manager.ts b/User/src/network/connection_manager.ts index f7f29f8..6dba3eb 100644 --- a/User/src/network/connection_manager.ts +++ b/User/src/network/connection_manager.ts @@ -19,8 +19,6 @@ export class ConnectionManager { this.connections[key] = { communicator }; - - console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`); } // Removes a communicator based on IP and port @@ -28,7 +26,6 @@ export class ConnectionManager { const key = `${ip}:${port}`; if (this.connections[key]) { delete this.connections[key]; - console.log(`Removed communicator for ${ip}:${port}`); } } diff --git a/User/src/network/tcp/tcp_client.ts b/User/src/network/tcp/tcp_client.ts index 7ad64f3..e4492b5 100644 --- a/User/src/network/tcp/tcp_client.ts +++ b/User/src/network/tcp/tcp_client.ts @@ -24,29 +24,40 @@ export class TcpClient { this.operationHandler.loadPlugin(new UserToUserOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[TcpClient]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Open a TCP socket connection openSocket(ip: string): void { this.socket = new net.Socket(); this.socket.connect(this.tcp_port, ip, () => { - //console.log(`Client connected to server at ${ip}:${this.tcp_port}`); + this.log(`Connected to server at ${ip}:${this.tcp_port}`); this.communicator = new TcpClientCommunicator(this.socket as Socket, ip, this.tcp_port, this.operationHandler); }); this.socket.on('error', (err) => { - //console.error(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`); + this.log(`Connection error to server at ${ip}:${this.tcp_port}: ${err.message}`, 'error'); }); this.socket.on('data', async (data: Buffer) => { if (this.communicator) { - await this.communicator.handleIncomingChunk(data); // Let the communicator handle the chunks + await this.communicator.handleIncomingChunk(data); this.lastResult = this.communicator.getHandlerResult(); + this.log(`Data received from ${ip}:${this.tcp_port}`); } }); this.socket.on('close', () => { - //console.log(`Connection closed: ${ip}:${this.tcp_port}`); - this.lastResult = null; // Clear the last result on socket close + this.log(`Connection closed: ${ip}:${this.tcp_port}`); + this.lastResult = null; }); } @@ -56,26 +67,27 @@ export class TcpClient { this.socket.end(); this.socket = null; this.communicator = null; - this.lastResult = null; // Clear the last result on close - //console.log('Client socket connection closed.'); + this.lastResult = null; + this.log('Client socket connection closed.'); } } // Send a message with operationCode, metaInfo, and fileContent in chunks async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise { if (!this.communicator || !this.isAesKeySet()) { - //console.error('Communicator not initialized or AES key not set.'); + this.log('Communicator not initialized or AES key not set.', 'error'); return false; } - await this.communicator.sendChunkedMessage(operationCode, metaInfo, fileContent); // Send message via communicator + this.log(`Sending message with operationCode: ${operationCode}`); + await this.communicator.sendChunkedMessage(operationCode, metaInfo, fileContent); return true; } // Check if AES key is set isAesKeySet(): boolean { - if(!this.communicator) return false; - return this.communicator?.isAesKeySet() + if (!this.communicator) return false; + return this.communicator?.isAesKeySet(); } // Check if the message is received (based on if lastResult is available) @@ -92,6 +104,8 @@ export class TcpClient { // Check if the socket is still connected isSocketConnected(): boolean { - return this.socket !== null && !this.socket.destroyed; + const connected = this.socket !== null && !this.socket.destroyed; + this.log(`Socket connected: ${connected}`); + return connected; } } diff --git a/User/src/network/tcp/tcp_server.ts b/User/src/network/tcp/tcp_server.ts index e0e66ab..aabb408 100644 --- a/User/src/network/tcp/tcp_server.ts +++ b/User/src/network/tcp/tcp_server.ts @@ -25,6 +25,16 @@ export class TcpServer { this.operationHandler.loadPlugin(new UserToUserOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[TcpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Start the TCP server public start(): void { const tcpServer = net.createServer(); @@ -33,9 +43,9 @@ export class TcpServer { tcpServer.on('connection', (socket: Socket) => { const ip = socket.remoteAddress || 'unknown'; const port = socket.remotePort || 0; + const clientId = `${ip}:${port}`; - const clientId = `${ip}:${port}`; // Use IP and port to identify the client - //console.log(`Client connected: ${clientId}`); + this.log(`Client connected: ${clientId}`); const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler); this.connectionManager.addConnection(ip, port, tcpCommunicator); @@ -45,36 +55,37 @@ export class TcpServer { tcpCommunicator.sendPublicKey() .then(() => tcpCommunicator.sendAesKey()) .catch(err => { - //console.error(`Error during key exchange with client ${clientId}:`, err); + this.log(`Error during key exchange with client ${clientId}: ${err}`, 'error'); socket.end(); // Close the connection in case of any error }); // Handle incoming data in chunks socket.on('data', async (data: Buffer) => { + this.log(`Data received from client ${clientId}`); await this.handleData(data, ip, port); }); // Handle client disconnect socket.on('end', () => { - //console.log(`Client disconnected: ${clientId}`); + this.log(`Client disconnected: ${clientId}`); this.connectionManager.removeCommunicator(ip, port); }); // Handle socket errors socket.on('error', (err: Error) => { - //console.error(`Error from client ${clientId}: ${err.message}`); + this.log(`Error from client ${clientId}: ${err.message}`, 'error'); this.connectionManager.removeCommunicator(ip, port); }); }); // Handle server errors tcpServer.on('error', (err: Error) => { - console.error(`TCP server error: ${err.message}`); + this.log(`TCP server error: ${err.message}`, 'error'); }); // Start listening for connections tcpServer.listen(this.port, this.host, () => { - console.log(`TCP server listening on ${this.host}:${this.port}`); + this.log(`TCP server listening on ${this.host}:${this.port}`); }); } @@ -85,7 +96,7 @@ export class TcpServer { // Retrieve the communicator associated with this connection const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator; if (!communicator) { - //console.error(`No communicator found for ${clientId}`); + this.log(`No communicator found for ${clientId}`, 'error'); return; } @@ -101,9 +112,9 @@ export class TcpServer { handlerResult.metaInfo, handlerResult.fileContent ); - //console.log(`Response sent to ${clientId}`); + this.log(`Response sent to ${clientId}`); } catch (err) { - //console.error(`Failed to send response to ${clientId}:`, err); + this.log(`Failed to send response to ${clientId}: ${err}`, 'error'); } } } diff --git a/User/src/network/udp/udp_client.ts b/User/src/network/udp/udp_client.ts index 03789b2..2449639 100644 --- a/User/src/network/udp/udp_client.ts +++ b/User/src/network/udp/udp_client.ts @@ -18,6 +18,16 @@ export class UdpClient { this.operationHandler.loadPlugin(new GeneralOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UdpClient]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses async getAliveClients(): Promise { const subnet = this.getSubnet(); @@ -25,9 +35,11 @@ export class UdpClient { // Get local machine's IP addresses to exclude const localIPs = this.getLocalIPs(); + this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`); // First, filter active IPs that respond to ping const activeIps = await this.filterActiveIps(ipRange); + this.log(`Active IPs in subnet ${subnet}: ${activeIps.join(', ')}`); // Send heartbeat to each active IP and keep only those that respond with ALIVE const aliveClients: string[] = []; @@ -40,7 +52,8 @@ export class UdpClient { } } - return aliveClients; // Return the list of IPs that responded with ALIVE, excluding the host machine + this.log(`Alive clients (excluding local machine): ${aliveClients.join(', ')}`); + return aliveClients; } // Get local IP addresses of the host machine (excluding loopback) @@ -65,8 +78,10 @@ export class UdpClient { const heartbeatCode = operationCodes.HEARTBEAT; const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode); + this.log(`Sending heartbeat to ${ip}`); this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => { if (err) { + this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error'); resolve({ found: false }); } else { const timeout = setTimeout(() => { @@ -79,8 +94,10 @@ export class UdpClient { clearTimeout(timeout); const parsedMessage = MessageHandler.parseMessage(msg.toString()); if (parsedMessage?.operationCode === operationCodes.ALIVE) { + this.log(`Received ALIVE response from ${ip}`); resolve({ found: true }); } else { + this.log(`Unexpected response from ${ip}`); resolve({ found: false }); } } @@ -94,8 +111,9 @@ export class UdpClient { private dropConnection(ip: string): void { try { this.udpSocket.removeAllListeners('message'); + this.log(`Dropped connection listeners for ${ip}`); } catch (err: any) { - console.error(`Error dropping connection to ${ip}: ${err.message}`); + this.log(`Error dropping connection to ${ip}: ${err.message}`, 'error'); } } @@ -105,7 +123,9 @@ export class UdpClient { for (const iface of Object.values(interfaces)) { for (const address of iface || []) { if (address.family === 'IPv4' && !address.internal) { - return address.address.split('.').slice(0, 3).join('.'); + const subnet = address.address.split('.').slice(0, 3).join('.'); + this.log(`Detected subnet: ${subnet}`); + return subnet; } } } @@ -118,6 +138,7 @@ export class UdpClient { for (let i = 1; i < 255; i++) { ipRange.push(`${subnet}.${i}`); } + this.log(`Generated IP range for subnet ${subnet}`); return ipRange; } @@ -135,6 +156,7 @@ export class UdpClient { } } + this.log(`Active IPs after pinging: ${activeIps.join(', ')}`); return activeIps; } } diff --git a/User/src/network/udp/udp_server.ts b/User/src/network/udp/udp_server.ts index 3c66550..7111ed7 100644 --- a/User/src/network/udp/udp_server.ts +++ b/User/src/network/udp/udp_server.ts @@ -1,7 +1,7 @@ import dgram, { RemoteInfo } from 'dgram'; import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator"; import { OperationHandler } from "../operations_base/operation_handler"; -import { GeneralOperations} from "../operations_custom/general_operations"; +import { GeneralOperations } from "../operations_custom/general_operations"; export class UdpServer { private readonly udpServer: dgram.Socket; @@ -19,10 +19,20 @@ export class UdpServer { this.operationHandler.loadPlugin(new GeneralOperations()); } + // Unified logging function + private log(message: string, level: 'log' | 'error' = 'log'): void { + const prefix = '[UdpServer]'; + if (level === 'error') { + console.error(`${prefix} ${message}`); + } else { + console.log(`${prefix} ${message}`); + } + } + // Start the UDP server public start(): void { this.udpServer.on('message', this.handleUdpMessages.bind(this)); - this.udpServer.on('error', this.handleError); + this.udpServer.on('error', this.handleError.bind(this)); this.udpServer.on('listening', this.handleListening.bind(this)); // Bind the server to the UDP port and host @@ -34,7 +44,7 @@ export class UdpServer { const ip = rinfo.address; const port = rinfo.port; - //console.log(`Received message from ${ip}:${port}`); + this.log(`Received message from ${ip}:${port}`); // Create a temporary communicator for the incoming message const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler); @@ -45,18 +55,23 @@ export class UdpServer { const communicatorResult = communicator.getHandlerResult(); if (communicatorResult) { // Send response back to the client using the temporary communicator - await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + try { + await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo); + this.log(`Sent response to ${ip}:${port}`); + } catch (error: any) { + this.log(`Error sending response to ${ip}:${port}: ${error.message}`, 'error'); + } } } // Handle UDP server errors private handleError(err: Error): void { - console.error(`UDP server error:\n${err.stack}`); + this.log(`UDP server error:\n${err.stack}`, 'error'); } // Handle when the UDP server starts listening private handleListening(): void { const address = this.udpServer.address(); - console.log(`UDP server listening on ${address.address}:${address.port}`); + this.log(`UDP server listening on ${address.address}:${address.port}`); } }