[SNMP4J] Unnecessary SNMP retries after a response has been received ?

Frank Fock fock at agentpp.com
Sun Mar 5 20:46:21 CET 2006


Hi,

Please replace the following method in Snmp.java to
fix the bug:

   public ResponseEvent send(PDU pdu, Target target,
                             TransportMapping transport) throws 
IOException {
     if (!pdu.isConfirmedPdu()) {
       sendMessage(pdu, target, transport);
       return null;
     }
     SyncResponseListener syncResponse = new SyncResponseListener();
     synchronized (syncResponse) {
       PduHandle handle;
       PendingRequest request;
       synchronized (sync) {
         handle = sendMessage(pdu, target, transport);
         request =
             new PendingRequest(handle, syncResponse, target, pdu, target,
                                transport);
         if (logger.isDebugEnabled()) {
           logger.debug("New pending request with handle " + handle);
         }
         pendingRequests.put(handle, request);
         long delay = timeoutModel.getRetryTimeout(0, target.getRetries(),
                                                   target.getTimeout());
         timer.schedule(request, delay);
       }
       try {
         syncResponse.wait();
         PendingRequest retryRequest =
             (PendingRequest) pendingRequests.remove(handle);
         if (retryRequest != null) {
           retryRequest.setFinished();
           retryRequest.cancel();
         }
         if (logger.isDebugEnabled()) {
           logger.debug("Removed pending request with handle: "+handle);
         }
         request.setFinished();
         request.cancel();
       }
       catch (InterruptedException iex) {
         logger.warn(iex);
         // ignore
       }
     }
     return syncResponse.response;
   }


Best regards,
Frank

k j wrote:
> A small program to show the behaviour:
> 
> import junit.framework.TestCase;
> import org.snmp4j.*;
> import org.snmp4j.event.ResponseEvent;
> import org.snmp4j.log.Log4jLogFactory;
> import org.snmp4j.log.LogFactory;
> import org.snmp4j.mp.MPv1;
> import org.snmp4j.smi.OID;
> import org.snmp4j.smi.OctetString;
> import org.snmp4j.smi.UdpAddress;
> import org.snmp4j.smi.VariableBinding;
> import org.snmp4j.transport.DefaultUdpTransportMapping;
> import org.snmp4j.util.DefaultPDUFactory;
> 
> import javax.resource.ResourceException;
> import java.io.IOException;
> import java.net.InetAddress;
> 
> public class Snmp4JTest extends TestCase {
> 
>    private static final OctetString HELLO = new OctetString("hello");
> 
>    /**
>     * Sends one get request to a daemon. Daemon reacts with a delay of 
> 1.5 seconds. Client
>     * is configured with retry 9 (just to show the issue) and timeout 1 
> second.
>     * The test shows that as soon as one retry is send, all retries are 
> send, even if the
>     * response is received after the first retry.
>     */
>    public void testSnmp4jRetryBehavior() throws ResourceException, 
> IOException, InterruptedException {
> 
>        LogFactory.setLogFactory(new Log4jLogFactory());
>        int freePort = 23454;
> 
>        //INIT server
>        UdpAddress udpAddress = new 
> UdpAddress(InetAddress.getByName("127.0.0.1"), freePort);
>        DefaultUdpTransportMapping defaultUdpTransportMapping = new 
> DefaultUdpTransportMapping(udpAddress);
>        Snmp daemon = new Snmp(defaultUdpTransportMapping);
>        final MyCommandResponder myCommandResponder = new 
> MyCommandResponder();
>        myCommandResponder.setSleepBeforeSendingResponse(1500);//force 
> one retry..
> 
>        daemon.addCommandResponder(myCommandResponder);
>        daemon.listen();
> 
>        try {
> 
>            //INIT client
>            DefaultPDUFactory factory = new DefaultPDUFactory();
>            MessageDispatcher mtDispatcher = new MessageDispatcherImpl();
>            mtDispatcher.addMessageProcessingModel(new MPv1());
>            Snmp snmpClient = new Snmp(mtDispatcher, new 
> DefaultUdpTransportMapping());
>            snmpClient.listen();
> 
>            //Create Request
>            Target target = new CommunityTarget(udpAddress, new 
> OctetString("public"));
>            target.setRetries(9);
>            target.setTimeout(1000);
>            PDU pdu = factory.createPDU(target);
>            pdu.setType(PDU.GET);
>            pdu.addAll(new VariableBinding[]{new VariableBinding(new 
> OID("1.2"))});
> 
>            // Send the request
>            ResponseEvent event = snmpClient.send(pdu, target);
>            PDU response = event.getResponse();
>            assertEquals(HELLO, response.get(0).getVariable());
>            System.out.println("Received response: " + response);
>            Thread.sleep(12000);//sleep for a while..
>        } finally {
>            daemon.close();
>        }
> 
>        //server should have received only two requests (request + one 
> retry)
>        assertEquals(2, myCommandResponder.getProcessCount());
> 
>    }
> 
>    private class MyCommandResponder implements CommandResponder {
>        private long m_sleepBeforeSendingResponse = 0;
>        private int m_processCount;
> 
>        public MyCommandResponder(){
>        }
> 
>        public void setSleepBeforeSendingResponse(long 
> sleepBeforeSendingResponse) {
>            m_sleepBeforeSendingResponse = sleepBeforeSendingResponse;
>        }
> 
>        public int getProcessCount() {
>            return m_processCount;
>        }
> 
>        public void processPdu(CommandResponderEvent vEvent) {
>            PDU pdu = vEvent.getPDU();
>            int pduType = pdu.getType();
>            System.out.println("Process PDU: " + pdu);
>            if (pduType == PDU.GET) {
>                m_processCount++;
>                ((VariableBinding) 
> pdu.getVariableBindings().get(0)).setVariable(HELLO);
>            }
>            try {
>                Thread.sleep(m_sleepBeforeSendingResponse);
>            } catch (InterruptedException e) {
>                throw new RuntimeException(e);
>            }
>            pdu.setErrorIndex(0);
>            pdu.setErrorStatus(0);
>            pdu.setType(PDU.RESPONSE);
>            try {
>                
> vEvent.getMessageDispatcher().returnResponsePdu(vEvent.getMessageProcessingModel(), 
> 
>                        vEvent.getSecurityModel(), vEvent.getSecurityName(),
>                        vEvent.getSecurityLevel(), pdu, 
> vEvent.getMaxSizeResponsePDU(), vEvent.getStateReference(),
>                        null);
>            } catch (MessageException e) {
>                throw new RuntimeException(e);
>            }
>        }
>    }
> }
> 
> 
> _______________________________________________
> SNMP4J mailing list
> SNMP4J at agentpp.org
> http://lists.agentpp.org/mailman/listinfo/snmp4j

-- 
AGENT++
http://www.agentpp.com
http://www.mibexplorer.com
http://www.mibdesigner.com




More information about the SNMP4J mailing list