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