update
This commit is contained in:
@ -4,8 +4,7 @@
|
||||
*/
|
||||
|
||||
import * as plugins from '../../../plugins.js';
|
||||
import type { IConnectionManager } from './interfaces.js';
|
||||
import type { ISessionManager } from './interfaces.js';
|
||||
import type { IConnectionManager, ISmtpServer } from './interfaces.js';
|
||||
import { SmtpResponseCode, SMTP_DEFAULTS, SmtpState } from './constants.js';
|
||||
import { SmtpLogger } from './utils/logging.js';
|
||||
import { adaptiveLogger } from './utils/adaptive-logging.js';
|
||||
@ -17,6 +16,11 @@ import { getSocketDetails, formatMultilineResponse } from './utils/helpers.js';
|
||||
* Provides resource management, connection tracking, and monitoring
|
||||
*/
|
||||
export class ConnectionManager implements IConnectionManager {
|
||||
/**
|
||||
* Reference to the SMTP server instance
|
||||
*/
|
||||
private smtpServer: ISmtpServer;
|
||||
|
||||
/**
|
||||
* Set of active socket connections
|
||||
*/
|
||||
@ -49,11 +53,6 @@ export class ConnectionManager implements IConnectionManager {
|
||||
*/
|
||||
private resourceCheckInterval: NodeJS.Timeout | null = null;
|
||||
|
||||
/**
|
||||
* Reference to the session manager
|
||||
*/
|
||||
private sessionManager: ISessionManager;
|
||||
|
||||
/**
|
||||
* SMTP server options with enhanced resource controls
|
||||
*/
|
||||
@ -68,33 +67,15 @@ export class ConnectionManager implements IConnectionManager {
|
||||
resourceCheckInterval: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Command handler function
|
||||
*/
|
||||
private commandHandler: (socket: plugins.net.Socket | plugins.tls.TLSSocket, line: string) => void;
|
||||
|
||||
/**
|
||||
* Creates a new connection manager with enhanced resource management
|
||||
* @param sessionManager - Session manager instance
|
||||
* @param commandHandler - Command handler function
|
||||
* @param options - Connection manager options
|
||||
* @param smtpServer - SMTP server instance
|
||||
*/
|
||||
constructor(
|
||||
sessionManager: ISessionManager,
|
||||
commandHandler: (socket: plugins.net.Socket | plugins.tls.TLSSocket, line: string) => void,
|
||||
options: {
|
||||
hostname?: string;
|
||||
maxConnections?: number;
|
||||
socketTimeout?: number;
|
||||
maxConnectionsPerIP?: number;
|
||||
connectionRateLimit?: number;
|
||||
connectionRateWindow?: number;
|
||||
bufferSizeLimit?: number;
|
||||
resourceCheckInterval?: number;
|
||||
} = {}
|
||||
) {
|
||||
this.sessionManager = sessionManager;
|
||||
this.commandHandler = commandHandler;
|
||||
constructor(smtpServer: ISmtpServer) {
|
||||
this.smtpServer = smtpServer;
|
||||
|
||||
// Get options from server
|
||||
const serverOptions = this.smtpServer.getOptions();
|
||||
|
||||
// Default values for resource management - adjusted for production scalability
|
||||
const DEFAULT_MAX_CONNECTIONS_PER_IP = 50; // Increased to support high-concurrency scenarios
|
||||
@ -104,14 +85,14 @@ export class ConnectionManager implements IConnectionManager {
|
||||
const DEFAULT_RESOURCE_CHECK_INTERVAL = 30 * 1000; // 30 seconds
|
||||
|
||||
this.options = {
|
||||
hostname: options.hostname || SMTP_DEFAULTS.HOSTNAME,
|
||||
maxConnections: options.maxConnections || SMTP_DEFAULTS.MAX_CONNECTIONS,
|
||||
socketTimeout: options.socketTimeout || SMTP_DEFAULTS.SOCKET_TIMEOUT,
|
||||
maxConnectionsPerIP: options.maxConnectionsPerIP || DEFAULT_MAX_CONNECTIONS_PER_IP,
|
||||
connectionRateLimit: options.connectionRateLimit || DEFAULT_CONNECTION_RATE_LIMIT,
|
||||
connectionRateWindow: options.connectionRateWindow || DEFAULT_CONNECTION_RATE_WINDOW,
|
||||
bufferSizeLimit: options.bufferSizeLimit || DEFAULT_BUFFER_SIZE_LIMIT,
|
||||
resourceCheckInterval: options.resourceCheckInterval || DEFAULT_RESOURCE_CHECK_INTERVAL
|
||||
hostname: serverOptions.hostname || SMTP_DEFAULTS.HOSTNAME,
|
||||
maxConnections: serverOptions.maxConnections || SMTP_DEFAULTS.MAX_CONNECTIONS,
|
||||
socketTimeout: serverOptions.socketTimeout || SMTP_DEFAULTS.SOCKET_TIMEOUT,
|
||||
maxConnectionsPerIP: DEFAULT_MAX_CONNECTIONS_PER_IP,
|
||||
connectionRateLimit: DEFAULT_CONNECTION_RATE_LIMIT,
|
||||
connectionRateWindow: DEFAULT_CONNECTION_RATE_WINDOW,
|
||||
bufferSizeLimit: DEFAULT_BUFFER_SIZE_LIMIT,
|
||||
resourceCheckInterval: DEFAULT_RESOURCE_CHECK_INTERVAL
|
||||
};
|
||||
|
||||
// Start resource monitoring
|
||||
@ -280,7 +261,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
}
|
||||
|
||||
// 3. Check for sessions without corresponding active connections
|
||||
const sessionCount = this.sessionManager.getSessionCount();
|
||||
const sessionCount = this.smtpServer.getSessionManager().getSessionCount();
|
||||
if (sessionCount > this.activeConnections.size) {
|
||||
inconsistenciesFound.push({
|
||||
issue: 'Orphaned sessions',
|
||||
@ -361,7 +342,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
this.setupSocketEventHandlers(socket);
|
||||
|
||||
// Create a session for this connection
|
||||
this.sessionManager.createSession(socket, false);
|
||||
this.smtpServer.getSessionManager().createSession(socket, false);
|
||||
|
||||
// Log the new connection using adaptive logger
|
||||
const socketDetails = getSocketDetails(socket);
|
||||
@ -517,7 +498,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
this.setupSocketEventHandlers(socket);
|
||||
|
||||
// Create a session for this connection
|
||||
this.sessionManager.createSession(socket, true);
|
||||
this.smtpServer.getSessionManager().createSession(socket, true);
|
||||
|
||||
// Log the new secure connection using adaptive logger
|
||||
adaptiveLogger.logConnection(socket, 'connect');
|
||||
@ -553,9 +534,9 @@ export class ConnectionManager implements IConnectionManager {
|
||||
socket.on('data', (data) => {
|
||||
try {
|
||||
// Get current session and update activity timestamp
|
||||
const session = this.sessionManager.getSession(socket);
|
||||
const session = this.smtpServer.getSessionManager().getSession(socket);
|
||||
if (session) {
|
||||
this.sessionManager.updateSessionActivity(session);
|
||||
this.smtpServer.getSessionManager().updateSessionActivity(session);
|
||||
}
|
||||
|
||||
// Check if we're in DATA receiving mode - handle differently
|
||||
@ -565,7 +546,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
try {
|
||||
const dataString = data.toString('utf8');
|
||||
// Use a special prefix to indicate this is raw data, not a command line
|
||||
this.commandHandler(socket, `__RAW_DATA__${dataString}`);
|
||||
this.smtpServer.getCommandHandler().processCommand(socket, `__RAW_DATA__${dataString}`);
|
||||
return;
|
||||
} catch (dataError) {
|
||||
SmtpLogger.error(`Data handler error during DATA mode: ${dataError instanceof Error ? dataError.message : String(dataError)}`);
|
||||
@ -619,7 +600,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
if (line.length > 0) {
|
||||
try {
|
||||
// In DATA state, the command handler will process the data differently
|
||||
this.commandHandler(socket, line);
|
||||
this.smtpServer.getCommandHandler().processCommand(socket, line);
|
||||
} catch (cmdError) {
|
||||
// Handle any errors in command processing
|
||||
SmtpLogger.error(`Command handler error: ${cmdError instanceof Error ? cmdError.message : String(cmdError)}`);
|
||||
@ -744,13 +725,13 @@ export class ConnectionManager implements IConnectionManager {
|
||||
}
|
||||
|
||||
// Get the session before removing it
|
||||
const session = this.sessionManager.getSession(socket);
|
||||
const session = this.smtpServer.getSessionManager().getSession(socket);
|
||||
|
||||
// Remove from active connections
|
||||
this.activeConnections.delete(socket);
|
||||
|
||||
// Remove from session manager
|
||||
this.sessionManager.removeSession(socket);
|
||||
this.smtpServer.getSessionManager().removeSession(socket);
|
||||
|
||||
// Cancel any timeout ID stored in the session
|
||||
if (session?.dataTimeoutId) {
|
||||
@ -786,7 +767,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
const socketId = `${socketDetails.remoteAddress}:${socketDetails.remotePort}`;
|
||||
|
||||
// Get the session
|
||||
const session = this.sessionManager.getSession(socket);
|
||||
const session = this.smtpServer.getSessionManager().getSession(socket);
|
||||
|
||||
// Detailed error logging with context information
|
||||
SmtpLogger.error(`Socket error for ${socketId}: ${error.message}`, {
|
||||
@ -815,7 +796,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
this.activeConnections.delete(socket);
|
||||
|
||||
// Remove from session manager
|
||||
this.sessionManager.removeSession(socket);
|
||||
this.smtpServer.getSessionManager().removeSession(socket);
|
||||
} catch (handlerError) {
|
||||
// Meta-error handling (errors in the error handler)
|
||||
SmtpLogger.error(`Error in handleSocketError: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}`);
|
||||
@ -842,7 +823,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
const socketId = `${socketDetails.remoteAddress}:${socketDetails.remotePort}`;
|
||||
|
||||
// Get the session
|
||||
const session = this.sessionManager.getSession(socket);
|
||||
const session = this.smtpServer.getSessionManager().getSession(socket);
|
||||
|
||||
// Get timing information for better debugging
|
||||
const now = Date.now();
|
||||
@ -894,7 +875,7 @@ export class ConnectionManager implements IConnectionManager {
|
||||
|
||||
// Clean up resources
|
||||
this.activeConnections.delete(socket);
|
||||
this.sessionManager.removeSession(socket);
|
||||
this.smtpServer.getSessionManager().removeSession(socket);
|
||||
} catch (handlerError) {
|
||||
// Handle any unexpected errors during timeout handling
|
||||
SmtpLogger.error(`Error in handleSocketTimeout: ${handlerError instanceof Error ? handlerError.message : String(handlerError)}`);
|
||||
@ -979,4 +960,25 @@ export class ConnectionManager implements IConnectionManager {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up resources
|
||||
*/
|
||||
public destroy(): void {
|
||||
// Clear resource monitoring interval
|
||||
if (this.resourceCheckInterval) {
|
||||
clearInterval(this.resourceCheckInterval);
|
||||
this.resourceCheckInterval = null;
|
||||
}
|
||||
|
||||
// Close all active connections
|
||||
this.closeAllConnections();
|
||||
|
||||
// Clear maps
|
||||
this.activeConnections.clear();
|
||||
this.connectionTimestamps.clear();
|
||||
this.ipConnectionCounts.clear();
|
||||
|
||||
SmtpLogger.debug('ConnectionManager destroyed');
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user