diff --git a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java index ce1777a3566..bfab5d02db4 100644 --- a/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java +++ b/bundles/org.openhab.binding.snmp/src/main/java/org/openhab/binding/snmp/internal/SnmpTargetHandler.java @@ -52,6 +52,7 @@ import org.snmp4j.CommandResponderEvent; import org.snmp4j.CommunityTarget; import org.snmp4j.PDU; import org.snmp4j.PDUv1; +import org.snmp4j.Snmp; import org.snmp4j.event.ResponseEvent; import org.snmp4j.event.ResponseListener; import org.snmp4j.mp.SnmpConstants; @@ -175,6 +176,15 @@ public class SnmpTargetHandler extends BaseThingHandler implements ResponseListe if (event == null) { return; } + + if (event.getSource() instanceof Snmp) { + // Always cancel async request when response has been received + // otherwise a memory leak is created! Not canceling a request + // immediately can be useful when sending a request to a broadcast + // address (Comment is taken from the snmp4j API doc). + ((Snmp) event.getSource()).cancel(event.getRequest(), this); + } + PDU response = event.getResponse(); if (response == null) { Exception e = event.getError(); diff --git a/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/SnmpTargetHandlerTest.java b/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/SnmpTargetHandlerTest.java index b11ec10857f..def1bd04714 100644 --- a/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/SnmpTargetHandlerTest.java +++ b/bundles/org.openhab.binding.snmp/src/test/java/org/openhab/binding/snmp/internal/SnmpTargetHandlerTest.java @@ -24,6 +24,7 @@ import org.eclipse.smarthome.core.library.types.OnOffType; import org.eclipse.smarthome.core.library.types.StringType; import org.junit.Test; import org.snmp4j.PDU; +import org.snmp4j.Snmp; import org.snmp4j.event.ResponseEvent; import org.snmp4j.smi.Counter64; import org.snmp4j.smi.Integer32; @@ -104,4 +105,27 @@ public class SnmpTargetHandlerTest extends AbstractSnmpTargetHandlerTest { thingHandler.onResponse(event); verify(thingHandlerCallback, atLeast(1)).stateUpdated(eq(CHANNEL_UID), eq(new DecimalType("12.4"))); } + + @Test + public void testCancelingAsyncRequest() { + setup(SnmpBindingConstants.CHANNEL_TYPE_UID_NUMBER, SnmpChannelMode.READ, SnmpDatatype.FLOAT); + PDU responsePDU = new PDU(PDU.RESPONSE, + Collections.singletonList(new VariableBinding(new OID(TEST_OID), new OctetString("12.4")))); + + SnmpMock source = new SnmpMock(); + + ResponseEvent event = new ResponseEvent(source, null, null, responsePDU, null); + + thingHandler.onResponse(event); + assertEquals(1, source.cancelCallCounter); + } + + class SnmpMock extends Snmp { + public int cancelCallCounter = 0; + + @Override + public void cancel(PDU request, org.snmp4j.event.ResponseListener listener) { + ++cancelCallCounter; + } + } }