TCP RST on Connection Close - Request for Graceful Shutdown API in DefaultTcpTransportMapping

Hello Frank / SNMP4j Community,
We are using SNMP4J library with our Java application
SNMP4J Version: 3.8.2 (also applicable to 3.9.x)
Component: org.snmp4j.transport.DefaultTcpTransportMapping

Problem:
When using DefaultTcpTransportMapping as a trap receiver, closing the SNMP session via snmp.close() immediately terminates all TCP sockets by sending TCP RST (reset) packets instead of performing a graceful shutdown with TCP FIN (finish) packets.

This behavior causes in-flight SNMP traps to be lost when the receiver application restarts while trap senders maintain persistent TCP connections with queuing enabled.

[Trap Forwarder] ──TCP persistent──> [SNMP4J Trap Receiver]
(with queue) (Java Application)
β”‚ β”‚
β”‚ Restart required
β”‚ β”‚
β”œβ”€β”€β”€ Sends trap during restart ──────────X (TCP RST)
β”‚ β”‚
└─── Trap lost ──────────────── Socket closed abruptly

TIME SOURCE DEST TCP FLAGS STATUS
10:00:00 Sender:55123 Receiver:162 [PSH, ACK] Trap sent
10:00:00 Receiver:162 Sender:55123 [RST] Abrupt termination
^^^ Trap lost!

Current Implementation Behavior:

When snmp.close() is called, the underlying implementation directly closes TCP sockets:
// Simplified representation of current behavior
public void close() throws IOException {
for (SocketEntry entry : sockets.values()) {
Socket socket = entry.getSocket();
socket.close(); // Direct close β†’ TCP RST
}
}

Expected Graceful Shutdown:

According to RFC 793 (TCP Specification, Section 3.5), graceful connection termination should:

Send TCP FIN to peer (half-close output)
Wait for peer’s FIN acknowledgment
Allow peer to finish sending buffered data
Close socket after handshake completes

TIME SOURCE DEST TCP FLAGS STATUS

10:00:00 Sender:55123 Receiver:162 [PSH, ACK] Trap sent

10:00:00 Receiver:162 Sender:55123 [FIN, ACK] Graceful close initiated

10:00:00 Sender:55123 Receiver:162 [ACK] Data received

10:00:01 Sender:55123 Receiver:162 [FIN, ACK] Peer closes

10:00:01 Receiver:162 Sender:55123 [ACK] Close complete

Possible code changes:
// Ideal implementation
socket.shutdownOutput(); // Send TCP FIN to peer
socket.setSoTimeout(5000); // Wait up to 5s for peer’s FIN
// Drain remaining data from peer
try {
while (socket.getInputStream().read() != -1) {
// Allow peer to send its FIN
}
} catch (SocketTimeoutException e) {
// Timeout acceptable
}
socket.close(); // Final close after handshake

I will implement it for v3.9.8’s DefaultTcpTransportMapping in a similar way like it had been already done for TLSTM using the AbstractConnectionOrientedTransportMapping.close() calling the SocketEntry.closeSession() which is not implemented for DefaultTcpTransportMapping.SocketEntry yet.

1 Like

Thank you @AGENTPP for considering this request. Will look forward to v3.9.8 fixes and I will test it. Hopefully that will resolve the TCP RST broken connection issue.

Hi Frank @AGENTPP ,

Any approximate timeline for v3.9.8 release ?

It will be release 3.10.0. There are changes necessary to the internal interfaces - especially WorkerTask that require a minor version upgrade. It will take one or two weeks to finish and test the changes. A snapshot release with an initial preview will be available this weekend.