refactor networking
This commit is contained in:
@@ -19,8 +19,6 @@ export class ConnectionManager {
|
|||||||
this.connections[key] = {
|
this.connections[key] = {
|
||||||
communicator
|
communicator
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a communicator based on IP and port
|
// Removes a communicator based on IP and port
|
||||||
@@ -28,7 +26,6 @@ export class ConnectionManager {
|
|||||||
const key = `${ip}:${port}`;
|
const key = `${ip}:${port}`;
|
||||||
if (this.connections[key]) {
|
if (this.connections[key]) {
|
||||||
delete this.connections[key];
|
delete this.connections[key];
|
||||||
console.log(`Removed communicator for ${ip}:${port}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,29 +24,40 @@ export class TcpClient {
|
|||||||
this.operationHandler.loadPlugin(new UserToUserOperations());
|
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
|
// Open a TCP socket connection
|
||||||
openSocket(ip: string): void {
|
openSocket(ip: string): void {
|
||||||
this.socket = new net.Socket();
|
this.socket = new net.Socket();
|
||||||
|
|
||||||
this.socket.connect(this.tcp_port, ip, () => {
|
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.communicator = new TcpClientCommunicator(this.socket as Socket, ip, this.tcp_port, this.operationHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('error', (err) => {
|
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) => {
|
this.socket.on('data', async (data: Buffer) => {
|
||||||
if (this.communicator) {
|
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.lastResult = this.communicator.getHandlerResult();
|
||||||
|
this.log(`Data received from ${ip}:${this.tcp_port}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', () => {
|
||||||
//console.log(`Connection closed: ${ip}:${this.tcp_port}`);
|
this.log(`Connection closed: ${ip}:${this.tcp_port}`);
|
||||||
this.lastResult = null; // Clear the last result on socket close
|
this.lastResult = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,26 +67,27 @@ export class TcpClient {
|
|||||||
this.socket.end();
|
this.socket.end();
|
||||||
this.socket = null;
|
this.socket = null;
|
||||||
this.communicator = null;
|
this.communicator = null;
|
||||||
this.lastResult = null; // Clear the last result on close
|
this.lastResult = null;
|
||||||
//console.log('Client socket connection closed.');
|
this.log('Client socket connection closed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message with operationCode, metaInfo, and fileContent in chunks
|
// Send a message with operationCode, metaInfo, and fileContent in chunks
|
||||||
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<boolean> {
|
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<boolean> {
|
||||||
if (!this.communicator || !this.isAesKeySet()) {
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if AES key is set
|
// Check if AES key is set
|
||||||
isAesKeySet(): boolean {
|
isAesKeySet(): boolean {
|
||||||
if(!this.communicator) return false;
|
if (!this.communicator) return false;
|
||||||
return this.communicator?.isAesKeySet()
|
return this.communicator?.isAesKeySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the message is received (based on if lastResult is available)
|
// 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
|
// Check if the socket is still connected
|
||||||
isSocketConnected(): boolean {
|
isSocketConnected(): boolean {
|
||||||
return this.socket !== null && !this.socket.destroyed;
|
const connected = this.socket !== null && !this.socket.destroyed;
|
||||||
|
this.log(`Socket connected: ${connected}`);
|
||||||
|
return connected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ export class TcpServer {
|
|||||||
this.operationHandler.loadPlugin(new UserToUserOperations());
|
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
|
// Start the TCP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
const tcpServer = net.createServer();
|
const tcpServer = net.createServer();
|
||||||
@@ -33,9 +43,9 @@ export class TcpServer {
|
|||||||
tcpServer.on('connection', (socket: Socket) => {
|
tcpServer.on('connection', (socket: Socket) => {
|
||||||
const ip = socket.remoteAddress || 'unknown';
|
const ip = socket.remoteAddress || 'unknown';
|
||||||
const port = socket.remotePort || 0;
|
const port = socket.remotePort || 0;
|
||||||
|
const clientId = `${ip}:${port}`;
|
||||||
|
|
||||||
const clientId = `${ip}:${port}`; // Use IP and port to identify the client
|
this.log(`Client connected: ${clientId}`);
|
||||||
//console.log(`Client connected: ${clientId}`);
|
|
||||||
|
|
||||||
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
||||||
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
||||||
@@ -45,36 +55,37 @@ export class TcpServer {
|
|||||||
tcpCommunicator.sendPublicKey()
|
tcpCommunicator.sendPublicKey()
|
||||||
.then(() => tcpCommunicator.sendAesKey())
|
.then(() => tcpCommunicator.sendAesKey())
|
||||||
.catch(err => {
|
.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
|
socket.end(); // Close the connection in case of any error
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle incoming data in chunks
|
// Handle incoming data in chunks
|
||||||
socket.on('data', async (data: Buffer) => {
|
socket.on('data', async (data: Buffer) => {
|
||||||
|
this.log(`Data received from client ${clientId}`);
|
||||||
await this.handleData(data, ip, port);
|
await this.handleData(data, ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle client disconnect
|
// Handle client disconnect
|
||||||
socket.on('end', () => {
|
socket.on('end', () => {
|
||||||
//console.log(`Client disconnected: ${clientId}`);
|
this.log(`Client disconnected: ${clientId}`);
|
||||||
this.connectionManager.removeCommunicator(ip, port);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle socket errors
|
// Handle socket errors
|
||||||
socket.on('error', (err: Error) => {
|
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);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle server errors
|
// Handle server errors
|
||||||
tcpServer.on('error', (err: Error) => {
|
tcpServer.on('error', (err: Error) => {
|
||||||
console.error(`TCP server error: ${err.message}`);
|
this.log(`TCP server error: ${err.message}`, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start listening for connections
|
// Start listening for connections
|
||||||
tcpServer.listen(this.port, this.host, () => {
|
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
|
// Retrieve the communicator associated with this connection
|
||||||
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
||||||
if (!communicator) {
|
if (!communicator) {
|
||||||
//console.error(`No communicator found for ${clientId}`);
|
this.log(`No communicator found for ${clientId}`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +112,9 @@ export class TcpServer {
|
|||||||
handlerResult.metaInfo,
|
handlerResult.metaInfo,
|
||||||
handlerResult.fileContent
|
handlerResult.fileContent
|
||||||
);
|
);
|
||||||
//console.log(`Response sent to ${clientId}`);
|
this.log(`Response sent to ${clientId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//console.error(`Failed to send response to ${clientId}:`, err);
|
this.log(`Failed to send response to ${clientId}: ${err}`, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ export class UdpClient {
|
|||||||
this.operationHandler.loadPlugin(new GeneralOperations());
|
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
|
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
|
||||||
async getAliveClients(): Promise<string[]> {
|
async getAliveClients(): Promise<string[]> {
|
||||||
const subnet = this.getSubnet();
|
const subnet = this.getSubnet();
|
||||||
@@ -25,9 +35,11 @@ export class UdpClient {
|
|||||||
|
|
||||||
// Get local machine's IP addresses to exclude
|
// Get local machine's IP addresses to exclude
|
||||||
const localIPs = this.getLocalIPs();
|
const localIPs = this.getLocalIPs();
|
||||||
|
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`);
|
||||||
|
|
||||||
// First, filter active IPs that respond to ping
|
// First, filter active IPs that respond to ping
|
||||||
const activeIps = await this.filterActiveIps(ipRange);
|
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
|
// Send heartbeat to each active IP and keep only those that respond with ALIVE
|
||||||
const aliveClients: string[] = [];
|
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)
|
// Get local IP addresses of the host machine (excluding loopback)
|
||||||
@@ -65,8 +78,10 @@ export class UdpClient {
|
|||||||
const heartbeatCode = operationCodes.HEARTBEAT;
|
const heartbeatCode = operationCodes.HEARTBEAT;
|
||||||
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
||||||
|
|
||||||
|
this.log(`Sending heartbeat to ${ip}`);
|
||||||
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
|
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error');
|
||||||
resolve({ found: false });
|
resolve({ found: false });
|
||||||
} else {
|
} else {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
@@ -79,8 +94,10 @@ export class UdpClient {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
const parsedMessage = MessageHandler.parseMessage(msg.toString());
|
const parsedMessage = MessageHandler.parseMessage(msg.toString());
|
||||||
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
||||||
|
this.log(`Received ALIVE response from ${ip}`);
|
||||||
resolve({ found: true });
|
resolve({ found: true });
|
||||||
} else {
|
} else {
|
||||||
|
this.log(`Unexpected response from ${ip}`);
|
||||||
resolve({ found: false });
|
resolve({ found: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +111,9 @@ export class UdpClient {
|
|||||||
private dropConnection(ip: string): void {
|
private dropConnection(ip: string): void {
|
||||||
try {
|
try {
|
||||||
this.udpSocket.removeAllListeners('message');
|
this.udpSocket.removeAllListeners('message');
|
||||||
|
this.log(`Dropped connection listeners for ${ip}`);
|
||||||
} catch (err: any) {
|
} 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 iface of Object.values(interfaces)) {
|
||||||
for (const address of iface || []) {
|
for (const address of iface || []) {
|
||||||
if (address.family === 'IPv4' && !address.internal) {
|
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++) {
|
for (let i = 1; i < 255; i++) {
|
||||||
ipRange.push(`${subnet}.${i}`);
|
ipRange.push(`${subnet}.${i}`);
|
||||||
}
|
}
|
||||||
|
this.log(`Generated IP range for subnet ${subnet}`);
|
||||||
return ipRange;
|
return ipRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +156,7 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`);
|
||||||
return activeIps;
|
return activeIps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import dgram, { RemoteInfo } from 'dgram';
|
import dgram, { RemoteInfo } from 'dgram';
|
||||||
import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator";
|
import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator";
|
||||||
import { OperationHandler } from "../operations_base/operation_handler";
|
import { OperationHandler } from "../operations_base/operation_handler";
|
||||||
import { GeneralOperations} from "../operations_custom/general_operations";
|
import { GeneralOperations } from "../operations_custom/general_operations";
|
||||||
|
|
||||||
export class UdpServer {
|
export class UdpServer {
|
||||||
private readonly udpServer: dgram.Socket;
|
private readonly udpServer: dgram.Socket;
|
||||||
@@ -19,10 +19,20 @@ export class UdpServer {
|
|||||||
this.operationHandler.loadPlugin(new GeneralOperations());
|
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
|
// Start the UDP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
this.udpServer.on('message', this.handleUdpMessages.bind(this));
|
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));
|
this.udpServer.on('listening', this.handleListening.bind(this));
|
||||||
|
|
||||||
// Bind the server to the UDP port and host
|
// Bind the server to the UDP port and host
|
||||||
@@ -34,7 +44,7 @@ export class UdpServer {
|
|||||||
const ip = rinfo.address;
|
const ip = rinfo.address;
|
||||||
const port = rinfo.port;
|
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
|
// Create a temporary communicator for the incoming message
|
||||||
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
|
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
|
||||||
@@ -45,18 +55,23 @@ export class UdpServer {
|
|||||||
const communicatorResult = communicator.getHandlerResult();
|
const communicatorResult = communicator.getHandlerResult();
|
||||||
if (communicatorResult) {
|
if (communicatorResult) {
|
||||||
// Send response back to the client using the temporary communicator
|
// 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
|
// Handle UDP server errors
|
||||||
private handleError(err: Error): void {
|
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
|
// Handle when the UDP server starts listening
|
||||||
private handleListening(): void {
|
private handleListening(): void {
|
||||||
const address = this.udpServer.address();
|
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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ export class ConnectionManager {
|
|||||||
this.connections[key] = {
|
this.connections[key] = {
|
||||||
communicator
|
communicator
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a communicator based on IP and port
|
// Removes a communicator based on IP and port
|
||||||
@@ -28,7 +26,6 @@ export class ConnectionManager {
|
|||||||
const key = `${ip}:${port}`;
|
const key = `${ip}:${port}`;
|
||||||
if (this.connections[key]) {
|
if (this.connections[key]) {
|
||||||
delete this.connections[key];
|
delete this.connections[key];
|
||||||
console.log(`Removed communicator for ${ip}:${port}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+30
-31
@@ -3,14 +3,14 @@ import path from 'path';
|
|||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
|
|
||||||
import { ConnectionManager } from './network/connection_manager';
|
import { ConnectionManager } from './network/connection_manager';
|
||||||
import {OperationHandler} from "./network/operations_base/operation_handler";
|
import { OperationHandler } from "./network/operations_base/operation_handler";
|
||||||
import {GeneralOperations} from "./network/operations_custom/general_operations";
|
import { GeneralOperations } from "./network/operations_custom/general_operations";
|
||||||
import {TcpServerCommunicator} from "./network/socket_communicator/tcp_server_communicator";
|
import { TcpServerCommunicator } from "./network/socket_communicator/tcp_server_communicator";
|
||||||
import {CeoOperations} from "./network/operations_custom/ceo_operations";
|
import { CeoOperations } from "./network/operations_custom/ceo_operations";
|
||||||
import {AuthOperations} from "./network/operations_custom/auth_operations";
|
import { AuthOperations } from "./network/operations_custom/auth_operations";
|
||||||
import {DepartmentOperations} from "./network/operations_custom/department_operations";
|
import { DepartmentOperations } from "./network/operations_custom/department_operations";
|
||||||
import {KeyOperations} from "./network/operations_custom/key_operations";
|
import { KeyOperations } from "./network/operations_custom/key_operations";
|
||||||
import {UserOperations} from "./network/operations_custom/user_operations";
|
import { UserOperations } from "./network/operations_custom/user_operations";
|
||||||
|
|
||||||
dotenv.config({ path: path.resolve(__dirname, './config/.env') });
|
dotenv.config({ path: path.resolve(__dirname, './config/.env') });
|
||||||
|
|
||||||
@@ -32,60 +32,62 @@ export class TcpServer {
|
|||||||
this.operationHandler.loadPlugin(new DepartmentOperations());
|
this.operationHandler.loadPlugin(new DepartmentOperations());
|
||||||
this.operationHandler.loadPlugin(new KeyOperations());
|
this.operationHandler.loadPlugin(new KeyOperations());
|
||||||
this.operationHandler.loadPlugin(new UserOperations());
|
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
|
// Start the TCP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
const tcpServer = net.createServer();
|
const tcpServer = net.createServer();
|
||||||
|
|
||||||
// Handle incoming connections
|
|
||||||
tcpServer.on('connection', (socket: Socket) => {
|
tcpServer.on('connection', (socket: Socket) => {
|
||||||
const ip = socket.remoteAddress || 'unknown';
|
const ip = socket.remoteAddress || 'unknown';
|
||||||
const port = socket.remotePort || 0;
|
const port = socket.remotePort || 0;
|
||||||
|
const clientId = `${ip}:${port}`;
|
||||||
|
|
||||||
const clientId = `${ip}:${port}`; // Use IP and port to identify the client
|
this.log(`Client connected: ${clientId}`);
|
||||||
console.log(`Client connected: ${clientId}`);
|
|
||||||
|
|
||||||
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
||||||
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
||||||
|
|
||||||
// Generate RSA key pair and start key exchange
|
|
||||||
tcpCommunicator.generateKeyPair();
|
tcpCommunicator.generateKeyPair();
|
||||||
tcpCommunicator.sendPublicKey()
|
tcpCommunicator.sendPublicKey()
|
||||||
.then(() => tcpCommunicator.sendAesKey())
|
.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 => {
|
.catch(err => {
|
||||||
console.error(`Error during key exchange with client ${clientId}:`, err);
|
this.log(`Error during key exchange with client ${clientId}: ${err.message}`, 'error');
|
||||||
socket.end(); // Close the connection in case of any error
|
socket.end();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle incoming data in chunks
|
|
||||||
socket.on('data', async (data: Buffer) => {
|
socket.on('data', async (data: Buffer) => {
|
||||||
await this.handleData(data, ip, port);
|
await this.handleData(data, ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle client disconnect
|
|
||||||
socket.on('end', () => {
|
socket.on('end', () => {
|
||||||
console.log(`Client disconnected: ${clientId}`);
|
this.log(`Client disconnected: ${clientId}`);
|
||||||
this.connectionManager.removeCommunicator(ip, port);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle socket errors
|
|
||||||
socket.on('error', (err: Error) => {
|
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);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle server errors
|
|
||||||
tcpServer.on('error', (err: Error) => {
|
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, () => {
|
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<void> {
|
private async handleData(data: Buffer, ip: string, port: number): Promise<void> {
|
||||||
const clientId = `${ip}:${port}`;
|
const clientId = `${ip}:${port}`;
|
||||||
|
|
||||||
// Retrieve the communicator associated with this connection
|
|
||||||
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
||||||
if (!communicator) {
|
if (!communicator) {
|
||||||
console.error(`No communicator found for ${clientId}`);
|
this.log(`No communicator found for ${clientId}`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle incoming chunked message via communicator
|
|
||||||
await communicator.handleIncomingChunk(data);
|
await communicator.handleIncomingChunk(data);
|
||||||
|
|
||||||
// Fetch and process result if available
|
|
||||||
const handlerResult = communicator.getHandlerResult();
|
const handlerResult = communicator.getHandlerResult();
|
||||||
if (handlerResult) {
|
if (handlerResult) {
|
||||||
try {
|
try {
|
||||||
@@ -112,9 +111,9 @@ export class TcpServer {
|
|||||||
handlerResult.metaInfo,
|
handlerResult.metaInfo,
|
||||||
handlerResult.fileContent
|
handlerResult.fileContent
|
||||||
);
|
);
|
||||||
console.log(`Response sent to ${clientId}`);
|
this.log(`Response sent to ${clientId}`);
|
||||||
} catch (err) {
|
} catch (err: any) {
|
||||||
console.error(`Failed to send response to ${clientId}:`, err);
|
this.log(`Failed to send response to ${clientId}: ${err.message}`, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-13
@@ -5,30 +5,39 @@ import { UdpSocketCommunicator } from "./network/socket_communicator/udp_socket_
|
|||||||
import { OperationHandler } from "./network/operations_base/operation_handler";
|
import { OperationHandler } from "./network/operations_base/operation_handler";
|
||||||
import { GeneralOperations } from "./network/operations_custom/general_operations";
|
import { GeneralOperations } from "./network/operations_custom/general_operations";
|
||||||
|
|
||||||
|
dotenv.config({ path: path.resolve(__dirname, './config/.env') });
|
||||||
|
|
||||||
export class UdpServer {
|
export class UdpServer {
|
||||||
private readonly udpServer: dgram.Socket;
|
private readonly udpServer: dgram.Socket;
|
||||||
private readonly operationHandler: OperationHandler;
|
private readonly operationHandler: OperationHandler;
|
||||||
private readonly host: string;
|
private readonly host: string;
|
||||||
private readonly port: number
|
private readonly port: number;
|
||||||
|
|
||||||
constructor(host: string, port: number) {
|
constructor(host: string, port: number) {
|
||||||
this.udpServer = dgram.createSocket('udp4');
|
this.udpServer = dgram.createSocket('udp4');
|
||||||
this.operationHandler = OperationHandler.getInstance();
|
this.operationHandler = OperationHandler.getInstance();
|
||||||
|
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
|
||||||
// Load only the GeneralOperations into the operation handler
|
|
||||||
this.operationHandler.loadPlugin(new GeneralOperations());
|
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
|
// Start the UDP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
this.udpServer.on('message', this.handleUdpMessages.bind(this));
|
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));
|
this.udpServer.on('listening', this.handleListening.bind(this));
|
||||||
|
|
||||||
// Bind the server to the UDP port and host
|
|
||||||
this.udpServer.bind(this.port, this.host);
|
this.udpServer.bind(this.port, this.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,31 +46,33 @@ export class UdpServer {
|
|||||||
const ip = rinfo.address;
|
const ip = rinfo.address;
|
||||||
const port = rinfo.port;
|
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);
|
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
|
||||||
|
|
||||||
// Process the incoming message using the communicator
|
|
||||||
communicator.handleIncomingMessage(msg.toString());
|
communicator.handleIncomingMessage(msg.toString());
|
||||||
|
|
||||||
const communicatorResult = communicator.getHandlerResult();
|
const communicatorResult = communicator.getHandlerResult();
|
||||||
if (communicatorResult) {
|
if (communicatorResult) {
|
||||||
// Send response back to the client using the temporary communicator
|
try {
|
||||||
await communicator.sendMessage(communicatorResult.operationCode, communicatorResult.metaInfo);
|
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 {
|
} else {
|
||||||
console.error(`No handler result for ${ip}:${port}`);
|
this.log(`No handler result for ${ip}:${port}`, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle UDP server errors
|
// Handle UDP server errors
|
||||||
private handleError(err: Error): void {
|
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
|
// Handle when the UDP server starts listening
|
||||||
private handleListening(): void {
|
private handleListening(): void {
|
||||||
const address = this.udpServer.address();
|
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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ export class ConnectionManager {
|
|||||||
this.connections[key] = {
|
this.connections[key] = {
|
||||||
communicator
|
communicator
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(`Added communicator for ${ip}:${port}, generated public and private keys.`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes a communicator based on IP and port
|
// Removes a communicator based on IP and port
|
||||||
@@ -28,7 +26,6 @@ export class ConnectionManager {
|
|||||||
const key = `${ip}:${port}`;
|
const key = `${ip}:${port}`;
|
||||||
if (this.connections[key]) {
|
if (this.connections[key]) {
|
||||||
delete this.connections[key];
|
delete this.connections[key];
|
||||||
console.log(`Removed communicator for ${ip}:${port}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,29 +24,40 @@ export class TcpClient {
|
|||||||
this.operationHandler.loadPlugin(new UserToUserOperations());
|
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
|
// Open a TCP socket connection
|
||||||
openSocket(ip: string): void {
|
openSocket(ip: string): void {
|
||||||
this.socket = new net.Socket();
|
this.socket = new net.Socket();
|
||||||
|
|
||||||
this.socket.connect(this.tcp_port, ip, () => {
|
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.communicator = new TcpClientCommunicator(this.socket as Socket, ip, this.tcp_port, this.operationHandler);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('error', (err) => {
|
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) => {
|
this.socket.on('data', async (data: Buffer) => {
|
||||||
if (this.communicator) {
|
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.lastResult = this.communicator.getHandlerResult();
|
||||||
|
this.log(`Data received from ${ip}:${this.tcp_port}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.socket.on('close', () => {
|
this.socket.on('close', () => {
|
||||||
//console.log(`Connection closed: ${ip}:${this.tcp_port}`);
|
this.log(`Connection closed: ${ip}:${this.tcp_port}`);
|
||||||
this.lastResult = null; // Clear the last result on socket close
|
this.lastResult = null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,26 +67,27 @@ export class TcpClient {
|
|||||||
this.socket.end();
|
this.socket.end();
|
||||||
this.socket = null;
|
this.socket = null;
|
||||||
this.communicator = null;
|
this.communicator = null;
|
||||||
this.lastResult = null; // Clear the last result on close
|
this.lastResult = null;
|
||||||
//console.log('Client socket connection closed.');
|
this.log('Client socket connection closed.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a message with operationCode, metaInfo, and fileContent in chunks
|
// Send a message with operationCode, metaInfo, and fileContent in chunks
|
||||||
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<boolean> {
|
async sendMessage(operationCode: string, metaInfo?: { [key: string]: any }, fileContent?: Buffer): Promise<boolean> {
|
||||||
if (!this.communicator || !this.isAesKeySet()) {
|
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;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if AES key is set
|
// Check if AES key is set
|
||||||
isAesKeySet(): boolean {
|
isAesKeySet(): boolean {
|
||||||
if(!this.communicator) return false;
|
if (!this.communicator) return false;
|
||||||
return this.communicator?.isAesKeySet()
|
return this.communicator?.isAesKeySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the message is received (based on if lastResult is available)
|
// 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
|
// Check if the socket is still connected
|
||||||
isSocketConnected(): boolean {
|
isSocketConnected(): boolean {
|
||||||
return this.socket !== null && !this.socket.destroyed;
|
const connected = this.socket !== null && !this.socket.destroyed;
|
||||||
|
this.log(`Socket connected: ${connected}`);
|
||||||
|
return connected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,16 @@ export class TcpServer {
|
|||||||
this.operationHandler.loadPlugin(new UserToUserOperations());
|
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
|
// Start the TCP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
const tcpServer = net.createServer();
|
const tcpServer = net.createServer();
|
||||||
@@ -33,9 +43,9 @@ export class TcpServer {
|
|||||||
tcpServer.on('connection', (socket: Socket) => {
|
tcpServer.on('connection', (socket: Socket) => {
|
||||||
const ip = socket.remoteAddress || 'unknown';
|
const ip = socket.remoteAddress || 'unknown';
|
||||||
const port = socket.remotePort || 0;
|
const port = socket.remotePort || 0;
|
||||||
|
const clientId = `${ip}:${port}`;
|
||||||
|
|
||||||
const clientId = `${ip}:${port}`; // Use IP and port to identify the client
|
this.log(`Client connected: ${clientId}`);
|
||||||
//console.log(`Client connected: ${clientId}`);
|
|
||||||
|
|
||||||
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
const tcpCommunicator = new TcpServerCommunicator(socket, ip, port, this.operationHandler);
|
||||||
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
this.connectionManager.addConnection(ip, port, tcpCommunicator);
|
||||||
@@ -45,36 +55,37 @@ export class TcpServer {
|
|||||||
tcpCommunicator.sendPublicKey()
|
tcpCommunicator.sendPublicKey()
|
||||||
.then(() => tcpCommunicator.sendAesKey())
|
.then(() => tcpCommunicator.sendAesKey())
|
||||||
.catch(err => {
|
.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
|
socket.end(); // Close the connection in case of any error
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle incoming data in chunks
|
// Handle incoming data in chunks
|
||||||
socket.on('data', async (data: Buffer) => {
|
socket.on('data', async (data: Buffer) => {
|
||||||
|
this.log(`Data received from client ${clientId}`);
|
||||||
await this.handleData(data, ip, port);
|
await this.handleData(data, ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle client disconnect
|
// Handle client disconnect
|
||||||
socket.on('end', () => {
|
socket.on('end', () => {
|
||||||
//console.log(`Client disconnected: ${clientId}`);
|
this.log(`Client disconnected: ${clientId}`);
|
||||||
this.connectionManager.removeCommunicator(ip, port);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle socket errors
|
// Handle socket errors
|
||||||
socket.on('error', (err: Error) => {
|
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);
|
this.connectionManager.removeCommunicator(ip, port);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle server errors
|
// Handle server errors
|
||||||
tcpServer.on('error', (err: Error) => {
|
tcpServer.on('error', (err: Error) => {
|
||||||
console.error(`TCP server error: ${err.message}`);
|
this.log(`TCP server error: ${err.message}`, 'error');
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start listening for connections
|
// Start listening for connections
|
||||||
tcpServer.listen(this.port, this.host, () => {
|
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
|
// Retrieve the communicator associated with this connection
|
||||||
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
const communicator = this.connectionManager.getCommunicator(ip, port) as TcpServerCommunicator;
|
||||||
if (!communicator) {
|
if (!communicator) {
|
||||||
//console.error(`No communicator found for ${clientId}`);
|
this.log(`No communicator found for ${clientId}`, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,9 +112,9 @@ export class TcpServer {
|
|||||||
handlerResult.metaInfo,
|
handlerResult.metaInfo,
|
||||||
handlerResult.fileContent
|
handlerResult.fileContent
|
||||||
);
|
);
|
||||||
//console.log(`Response sent to ${clientId}`);
|
this.log(`Response sent to ${clientId}`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
//console.error(`Failed to send response to ${clientId}:`, err);
|
this.log(`Failed to send response to ${clientId}: ${err}`, 'error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ export class UdpClient {
|
|||||||
this.operationHandler.loadPlugin(new GeneralOperations());
|
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
|
// Send heartbeat and get clients that respond with ALIVE, excluding the host machine's IP addresses
|
||||||
async getAliveClients(): Promise<string[]> {
|
async getAliveClients(): Promise<string[]> {
|
||||||
const subnet = this.getSubnet();
|
const subnet = this.getSubnet();
|
||||||
@@ -25,9 +35,11 @@ export class UdpClient {
|
|||||||
|
|
||||||
// Get local machine's IP addresses to exclude
|
// Get local machine's IP addresses to exclude
|
||||||
const localIPs = this.getLocalIPs();
|
const localIPs = this.getLocalIPs();
|
||||||
|
this.log(`Local IPs to exclude from scan: ${localIPs.join(', ')}`);
|
||||||
|
|
||||||
// First, filter active IPs that respond to ping
|
// First, filter active IPs that respond to ping
|
||||||
const activeIps = await this.filterActiveIps(ipRange);
|
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
|
// Send heartbeat to each active IP and keep only those that respond with ALIVE
|
||||||
const aliveClients: string[] = [];
|
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)
|
// Get local IP addresses of the host machine (excluding loopback)
|
||||||
@@ -65,8 +78,10 @@ export class UdpClient {
|
|||||||
const heartbeatCode = operationCodes.HEARTBEAT;
|
const heartbeatCode = operationCodes.HEARTBEAT;
|
||||||
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
const heartbeatMessage = MessageHandler.formatMessage(heartbeatCode);
|
||||||
|
|
||||||
|
this.log(`Sending heartbeat to ${ip}`);
|
||||||
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
|
this.udpSocket.send(heartbeatMessage, this.port, ip, (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
this.log(`Failed to send heartbeat to ${ip}: ${err.message}`, 'error');
|
||||||
resolve({ found: false });
|
resolve({ found: false });
|
||||||
} else {
|
} else {
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
@@ -79,8 +94,10 @@ export class UdpClient {
|
|||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
const parsedMessage = MessageHandler.parseMessage(msg.toString());
|
const parsedMessage = MessageHandler.parseMessage(msg.toString());
|
||||||
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
if (parsedMessage?.operationCode === operationCodes.ALIVE) {
|
||||||
|
this.log(`Received ALIVE response from ${ip}`);
|
||||||
resolve({ found: true });
|
resolve({ found: true });
|
||||||
} else {
|
} else {
|
||||||
|
this.log(`Unexpected response from ${ip}`);
|
||||||
resolve({ found: false });
|
resolve({ found: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -94,8 +111,9 @@ export class UdpClient {
|
|||||||
private dropConnection(ip: string): void {
|
private dropConnection(ip: string): void {
|
||||||
try {
|
try {
|
||||||
this.udpSocket.removeAllListeners('message');
|
this.udpSocket.removeAllListeners('message');
|
||||||
|
this.log(`Dropped connection listeners for ${ip}`);
|
||||||
} catch (err: any) {
|
} 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 iface of Object.values(interfaces)) {
|
||||||
for (const address of iface || []) {
|
for (const address of iface || []) {
|
||||||
if (address.family === 'IPv4' && !address.internal) {
|
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++) {
|
for (let i = 1; i < 255; i++) {
|
||||||
ipRange.push(`${subnet}.${i}`);
|
ipRange.push(`${subnet}.${i}`);
|
||||||
}
|
}
|
||||||
|
this.log(`Generated IP range for subnet ${subnet}`);
|
||||||
return ipRange;
|
return ipRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,6 +156,7 @@ export class UdpClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.log(`Active IPs after pinging: ${activeIps.join(', ')}`);
|
||||||
return activeIps;
|
return activeIps;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import dgram, { RemoteInfo } from 'dgram';
|
import dgram, { RemoteInfo } from 'dgram';
|
||||||
import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator";
|
import { UdpSocketCommunicator } from "../socket_communicator/udp_socket_communicator";
|
||||||
import { OperationHandler } from "../operations_base/operation_handler";
|
import { OperationHandler } from "../operations_base/operation_handler";
|
||||||
import { GeneralOperations} from "../operations_custom/general_operations";
|
import { GeneralOperations } from "../operations_custom/general_operations";
|
||||||
|
|
||||||
export class UdpServer {
|
export class UdpServer {
|
||||||
private readonly udpServer: dgram.Socket;
|
private readonly udpServer: dgram.Socket;
|
||||||
@@ -19,10 +19,20 @@ export class UdpServer {
|
|||||||
this.operationHandler.loadPlugin(new GeneralOperations());
|
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
|
// Start the UDP server
|
||||||
public start(): void {
|
public start(): void {
|
||||||
this.udpServer.on('message', this.handleUdpMessages.bind(this));
|
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));
|
this.udpServer.on('listening', this.handleListening.bind(this));
|
||||||
|
|
||||||
// Bind the server to the UDP port and host
|
// Bind the server to the UDP port and host
|
||||||
@@ -34,7 +44,7 @@ export class UdpServer {
|
|||||||
const ip = rinfo.address;
|
const ip = rinfo.address;
|
||||||
const port = rinfo.port;
|
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
|
// Create a temporary communicator for the incoming message
|
||||||
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
|
const communicator = new UdpSocketCommunicator(this.udpServer, ip, port, this.operationHandler);
|
||||||
@@ -45,18 +55,23 @@ export class UdpServer {
|
|||||||
const communicatorResult = communicator.getHandlerResult();
|
const communicatorResult = communicator.getHandlerResult();
|
||||||
if (communicatorResult) {
|
if (communicatorResult) {
|
||||||
// Send response back to the client using the temporary communicator
|
// 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
|
// Handle UDP server errors
|
||||||
private handleError(err: Error): void {
|
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
|
// Handle when the UDP server starts listening
|
||||||
private handleListening(): void {
|
private handleListening(): void {
|
||||||
const address = this.udpServer.address();
|
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}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user