update
This commit is contained in:
@ -455,14 +455,103 @@ export class DataHandler implements IDataHandler {
|
||||
socket.write(`${response}${SMTP_DEFAULTS.CRLF}`);
|
||||
SmtpLogger.logResponse(response, socket);
|
||||
} catch (error) {
|
||||
SmtpLogger.error(`Error sending response: ${error instanceof Error ? error.message : String(error)}`, {
|
||||
response,
|
||||
remoteAddress: socket.remoteAddress,
|
||||
remotePort: socket.remotePort,
|
||||
error: error instanceof Error ? error : new Error(String(error))
|
||||
});
|
||||
|
||||
socket.destroy();
|
||||
// Attempt to recover from specific transient errors
|
||||
if (this.isRecoverableSocketError(error)) {
|
||||
this.handleSocketError(socket, error, response);
|
||||
} else {
|
||||
// Log error for non-recoverable errors
|
||||
SmtpLogger.error(`Error sending response: ${error instanceof Error ? error.message : String(error)}`, {
|
||||
response,
|
||||
remoteAddress: socket.remoteAddress,
|
||||
remotePort: socket.remotePort,
|
||||
error: error instanceof Error ? error : new Error(String(error))
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a socket error is potentially recoverable
|
||||
* @param error - The error that occurred
|
||||
* @returns Whether the error is potentially recoverable
|
||||
*/
|
||||
private isRecoverableSocketError(error: unknown): boolean {
|
||||
const recoverableErrorCodes = [
|
||||
'EPIPE', // Broken pipe
|
||||
'ECONNRESET', // Connection reset by peer
|
||||
'ETIMEDOUT', // Connection timed out
|
||||
'ECONNABORTED' // Connection aborted
|
||||
];
|
||||
|
||||
return (
|
||||
error instanceof Error &&
|
||||
'code' in error &&
|
||||
typeof (error as any).code === 'string' &&
|
||||
recoverableErrorCodes.includes((error as any).code)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle recoverable socket errors with retry logic
|
||||
* @param socket - Client socket
|
||||
* @param error - The error that occurred
|
||||
* @param response - The response that failed to send
|
||||
*/
|
||||
private handleSocketError(socket: plugins.net.Socket | plugins.tls.TLSSocket, error: unknown, response: string): void {
|
||||
// Get the session for this socket
|
||||
const session = this.sessionManager.getSession(socket);
|
||||
if (!session) {
|
||||
SmtpLogger.error(`Session not found when handling socket error`);
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get error details for logging
|
||||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||||
const errorCode = error instanceof Error && 'code' in error ? (error as any).code : 'UNKNOWN';
|
||||
|
||||
SmtpLogger.warn(`Recoverable socket error during data handling (${errorCode}): ${errorMessage}`, {
|
||||
sessionId: session.id,
|
||||
remoteAddress: session.remoteAddress,
|
||||
error: error instanceof Error ? error : new Error(String(error))
|
||||
});
|
||||
|
||||
// Check if socket is already destroyed
|
||||
if (socket.destroyed) {
|
||||
SmtpLogger.info(`Socket already destroyed, cannot retry data operation`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if socket is writeable
|
||||
if (!socket.writable) {
|
||||
SmtpLogger.info(`Socket no longer writable, aborting data recovery attempt`);
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to retry the write operation after a short delay
|
||||
setTimeout(() => {
|
||||
try {
|
||||
if (!socket.destroyed && socket.writable) {
|
||||
socket.write(`${response}${SMTP_DEFAULTS.CRLF}`);
|
||||
SmtpLogger.info(`Successfully retried data send operation after error`);
|
||||
} else {
|
||||
SmtpLogger.warn(`Socket no longer available for data retry`);
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
} catch (retryError) {
|
||||
SmtpLogger.error(`Data retry attempt failed: ${retryError instanceof Error ? retryError.message : String(retryError)}`);
|
||||
if (!socket.destroyed) {
|
||||
socket.destroy();
|
||||
}
|
||||
}
|
||||
}, 100); // Short delay before retry
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user