Brice Fines | 5 Nov 2009 11:32
Picon

Re: random problem sending command over TCP

Hi Frank,

No, it seems we are not using 
TransportStateListener.connectionStateChanged (I could not find any 
reference to TransportStateListener in the whole code).

We use SNMP4J in a straight forward way: configure and init an SNMP object 
for the whole application life, use it to send commands.

Please find enclosed the source for the class we use (to send a command we 
call the "sendCommand" method, that's where the application hangs (but 
only a few times, it works ok 99% of the time)
(I still have to check with version 1.10.2, hope to be able to do it soon)

Thanks

import java.io.IOException;

import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.ScopedPDU;
import org.snmp4j.Snmp;
import org.snmp4j.Target;
import org.snmp4j.TransportMapping;
import org.snmp4j.UserTarget;
import org.snmp4j.event.CounterListener;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.CounterSupport;
import org.snmp4j.mp.DefaultCounterListener;
import org.snmp4j.mp.MPv3;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.security.AuthMD5;
import org.snmp4j.security.AuthSHA;
import org.snmp4j.security.PrivDES;
import org.snmp4j.security.SecurityLevel;
import org.snmp4j.security.SecurityModels;
import org.snmp4j.security.SecurityProtocols;
import org.snmp4j.security.USM;
import org.snmp4j.security.UsmUser;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.TcpAddress;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;

import aaa.bbbbbb.xxxxx.business.channel.ControlChannel;
import aaa.bbbbbb.xxxxx.business.dialog.ComandosResolver;
import aaa.bbbbbb.xxxxx.commands.Comando;
import aaa.bbbbbb.xxxxx.exceptions.AccesoDenegadoException;
import aaa.bbbbbb.xxxxx.exceptions.ClientUnreachableException;
import aaa.bbbbbb.xxxxx.exceptions.CommandNotFoundException;
import aaa.bbbbbb.xxxxx.exceptions.InternalErrorException;
import aaa.bbbbbb.xxxxx.exceptions.RespuestaErrorGenerico;
import aaa.bbbbbb.xxxxx.exceptions.RespuestaInvalidaException;
import aaa.bbbbbb.xxxxx.exceptions.SintaxisIncorrectaException;
import aaa.bbbbbb.xxxxx.model.Client;
import aaa.bbbbbb.xxxxx.util.log4j.SourcesLogger;

public class SnmpChannel implements ControlChannel {

        private SourcesLogger logger = new SourcesLogger(getClass());

        private String commandPort = "/161";

        public void setCommandPort(String commandPort) {
                this.commandPort = commandPort;
        }

        private int timeout = 10 * 1000;

        public void setTimeout(int timeout) {
                this.timeout = timeout * 1000;
        }

        private int retries = 3;

        public void setRetries(int retries) {
                this.retries = retries;
        }

        private String community = "ppp";

        public void setCommunity(String community) {
                this.community = community;
        }

        private boolean soportaVersion3 = false;

        public void setV3(boolean soportaVersion3) {
                this.soportaVersion3 = soportaVersion3;
        }
        private String securityName = "";

        public void setSecurityName(String securityName) {
                this.securityName = securityName;
        }

        private String authProtocol = "";

        public void setAuthProtocol(String authProtocol) {
                this.authProtocol = authProtocol;
        }

        private String authPassphrase = "";

        public void setAuthPassphrase(String authPassphrase) {
                this.authPassphrase = authPassphrase;
        }

        private String privProtocol = "";

        public void setPrivProtocol(String privProtocol) {
                this.privProtocol = privProtocol;
        }

        private String privPassphrase = "";

        public void setPrivPassphrase(String privPassphrase) {
                this.privPassphrase = privPassphrase;
        }

        private Control2SNMP snmpConversionService;

        public void setControl2SNMP(Control2SNMP snmpConversionService) {
                this.snmpConversionService = snmpConversionService;
        }

        private ComandosResolver theComandosResolver;

        public void setComandosResolver(ComandosResolver 
comandosResolver){
                theComandosResolver = comandosResolver; 
        }

        private Snmp snmp;

        private final CounterListener counterListener = new 
DefaultCounterListener();

        private TransportMapping transportMapping;

        public boolean startup() {
                try {
                        logger.getLogger().warn(
                                        logger.fromServer("Starting 
SNMP"));
 CounterSupport.getInstance().addCounterListener(counterListener);
                        snmp = createSnmpSession();
                        snmp.listen();
                        logger
                                        .getLogger()
                                        .warn(
                                                        logger
 .fromServer("SNMP started"));
                        return true;
                } catch (Exception exception) {
 logger.getLogger().error(logger.fromServer(exception.toString()));
                        exception.printStackTrace();
                        return false;
                }
        }

        public void shutdown() {
                try {
                        logger.getLogger().warn(
                                        logger.fromServer("closing 
SNMP"));
 CounterSupport.getInstance().removeCounterListener(counterListener);
                        snmp.close();
                } catch (Exception exception) {
 logger.getLogger().warn(logger.fromServer(exception.toString()));
                        exception.printStackTrace();
                }
        }

        public Comando sendCommand(Client client, Comando comando)
                        throws   ClientUnreachableException, 
AccesoDenegadoException,
                        SintaxisIncorrectaException, 
RespuestaInvalidaException, CommandNotFoundException,
                        RespuestaErrorGenerico, InternalErrorException

                {
                final ResponseEvent responseEvent ;
                try {
                        final PDU pdu = comando2PDU(comando);

                        if(pdu == null){
                                throw new InternalErrorException("PDU not 
found");
                        }
                        final String ip = client.getIp();
                        final Target target = createTarget(ip);
                         responseEvent = snmp.send(pdu, target);
                } catch (Exception e) {
                        throw new InternalErrorException("Exception with 
command: " + e + " " + e.getMessage());
                }

                if (responseEvent == null) { 
                        throw new ClientUnreachableException("Answer 
null");
                }

                if (responseEvent.getResponse() == null) { 
                        throw new ClientUnreachableException("Answer 
null");
                }
                final PDU pduResponse = responseEvent.getResponse(); 
                if(pduResponse.getType() != PDU.REPORT 
                        && pduResponse.getType() != PDU.RESPONSE){
                        throw new RespuestaInvalidaException("Unknown 
answer: pduResponse.getType()= " + 

pduResponse.getType());
                }
                if (pduResponse.getType() == PDU.REPORT) {
                        throw new AccesoDenegadoException("SNMP REPORT: " 
+ pduResponse.toString());
                }
                if (pduResponse.getErrorStatus() != PDU.noError) {
                        if (pduResponse.getErrorStatus() == 
PDU.authorizationError) {
                                throw new AccesoDenegadoException("SNMP 
answer: autorizationError status");
                        }
                        if(pduResponse.getErrorStatus() == PDU.badValue){ 
                                throw new 
SintaxisIncorrectaException("SNMP answer: badValue status");
                        }
                        if(pduResponse.getErrorStatus() == PDU.noSuchName
                                || pduResponse.getErrorStatus() == 
PDU.readOnly){
                                throw new CommandNotFoundException("SNMP 
answer: noSuchName/readOnly status");
                        }

                        boolean posibleMsgError = 
pduResponse.getErrorStatus() == PDU.genErr && !comando.isGet()? true : 

false;
                        throw new RespuestaErrorGenerico(posibleMsgError, 
"SNMP answer: " + 

pduResponse.getErrorStatusText());
                }
                if (pduResponse.getVariableBindings().size() == 0) {
                        throw new RespuestaInvalidaException("SNMP answer 
with no varBind");
                }
                try{
                        final VariableBinding variableBinding = 
pduResponse.get(0);
                        String res = 
snmpConversionService.getStringValue(variableBinding);
                        comando.setResultado(res);
                        return comando;

                }catch(Exception e){
                        throw new RespuestaInvalidaException("Exception 
parsing answer: "+ e + " " +e.getMessage());
                }

        }

        private Snmp createSnmpSession() throws IOException {
                logger.getLogger().debug(logger.fromServer("Creating SNMP 
session"));
                transportMapping = new DefaultTcpTransportMapping();
                final Snmp snmp = new Snmp(transportMapping);
                if (soportaVersion3) {
                        final USM usm = new 
USM(SecurityProtocols.getInstance(),
                                        new 
OctetString(MPv3.createLocalEngineID()), 0);
 SecurityModels.getInstance().addSecurityModel(usm);
                        addUsmUser(snmp);
                        logger.getLogger().debug(
                                        logger.fromServer("SNMP session 
created"));
                }
                return snmp;
        }

        private void addUsmUser(Snmp snmp) {
                logger.getLogger().debug(
                                logger.fromServer("Creating SNMP user " + 
securityName
                                                + ", Protocolo " + 
authProtocol));
                snmp.getUSM().addUser(
                                new OctetString(securityName),
                                new UsmUser(new OctetString(securityName), 
authProtocol
                                                .equals("MD5") ? 
AuthMD5.ID : AuthSHA.ID,
                                                authPassphrase.length() != 
0 ? new OctetString(
 authPassphrase) : null,
                                                privProtocol.length() != 0 
? PrivDES.ID : null,
                                                privPassphrase.length() != 
0 ? new OctetString(
 privPassphrase) : null));
        }

        private Target createTarget(String ip) {
                Target target = null;
                if (soportaVersion3) {
                        target = createSecuredUserTarget(ip);
                } else {
                        target = createCommunityTarget(ip);
                }
                target.setTimeout(timeout);
                target.setRetries(retries);
                return target;
        }

        private Target createSecuredUserTarget(String ip) {
                final UserTarget userTarget = new UserTarget();
                if (authPassphrase != null && authPassphrase.length() != 
0) {
                        if (privPassphrase != null && 
privPassphrase.length() != 0) {
 userTarget.setSecurityLevel(SecurityLevel.AUTH_PRIV);
                        } else {
 userTarget.setSecurityLevel(SecurityLevel.AUTH_NOPRIV);
                        }
                } else {
 userTarget.setSecurityLevel(SecurityLevel.NOAUTH_NOPRIV);
                }
                userTarget.setSecurityName(new OctetString(securityName));
                userTarget.setVersion(SnmpConstants.version3);
                userTarget.setAddress(new TcpAddress(ip + commandPort));
                return userTarget;
        }

        private Target createCommunityTarget(String ip) {
                final CommunityTarget communityTarget = new 
CommunityTarget();
                communityTarget.setCommunity(new OctetString(community));
                communityTarget.setAddress(new TcpAddress(ip + 
commandPort));
                return communityTarget;
        }

        private PDU comando2PDU(Comando cmd) {
                final PDU pdu = soportaVersion3 ? new ScopedPDU() : new 
PDU();
                pdu.setType(cmd.isGet() ? PDU.GET : PDU.SET);
                final String mibId = 
theComandosResolver.getMibIdFromDBCodigo(cmd.getCodigoComando());
                if(mibId == null){
                        return null;
                }
                final OID oid = snmpConversionService.findOID(mibId);
                if(oid == null){
                        return null;
                }

                final VariableBinding variableBinding = new 
VariableBinding(oid);
                if (cmd.isGet() == false) {
                        variableBinding.setVariable(snmpConversionService
 .createSNMPVariable(cmd.getParam()));
                }
                pdu.add(variableBinding);
                return pdu;
        }

}

Gmane