org.snmp4j.agent.BaseAgent Maven / Gradle / Ivy
/*_############################################################################
_##
_## SNMP4J-Agent 3 - BaseAgent.java
_##
_## Copyright (C) 2005-2018 Frank Fock (SNMP4J.org)
_##
_## Licensed under the Apache License, Version 2.0 (the "License");
_## you may not use this file except in compliance with the License.
_## You may obtain a copy of the License at
_##
_## http://www.apache.org/licenses/LICENSE-2.0
_##
_## Unless required by applicable law or agreed to in writing, software
_## distributed under the License is distributed on an "AS IS" BASIS,
_## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
_## See the License for the specific language governing permissions and
_## limitations under the License.
_##
_##########################################################################*/
package org.snmp4j.agent;
import java.io.*;
import org.snmp4j.*;
import org.snmp4j.agent.cfg.EngineBootsCounterFile;
import org.snmp4j.agent.io.*;
import org.snmp4j.agent.mo.DefaultMOFactory;
import org.snmp4j.agent.mo.snmp.*;
import org.snmp4j.agent.mo.snmp4j.*;
import org.snmp4j.log.*;
import org.snmp4j.mp.*;
import org.snmp4j.security.*;
import org.snmp4j.smi.*;
import org.snmp4j.transport.*;
/**
* The {@code BaseAgent} abstract class defines a framework for writing
* SNMP agents using the SNMP4J-Agent API. To implement your own SNMP agent,
* extend this class and implement the abstract methods defined by BaseAgent.
* The hook methods do not need any specific implementation. They only provide
* a defined mechanism to customize your agent.
*
* @author Frank Fock
* @version 1.0
* @deprecated Use {@link AgentConfigManager} instead. See {@link org.snmp4j.agent.example.SampleAgent} for sample
* code on how to use {@link AgentConfigManager}. This class will be removed in SNMP4J-Agent 3.1.
*/
@Deprecated
public abstract class BaseAgent implements Runnable {
private static final LogAdapter logger =
LogFactory.getLogger(BaseAgent.class);
public static final int STATE_CREATED = 0;
public static final int STATE_INIT_STARTED = 10;
public static final int STATE_INIT_FINISHED = 20;
public static final int STATE_RUNNING = 40;
public static final int STATE_STOPPED = 30;
protected SNMPv2MIB snmpv2MIB;
protected SnmpMpdMib snmpMpdMib;
protected SnmpFrameworkMIB snmpFrameworkMIB;
protected SnmpTargetMIB snmpTargetMIB;
protected SnmpNotificationMIB snmpNotificationMIB;
protected SnmpProxyMIB snmpProxyMIB;
protected SnmpCommunityMIB snmpCommunityMIB;
protected Snmp4jLogMib snmp4jLogMIB;
protected Snmp4jConfigMib snmp4jConfigMIB;
protected UsmMIB usmMIB;
protected VacmMIB vacmMIB;
protected DefaultMOServer server;
protected Snmp session;
protected TransportMapping extends Address>[] transportMappings;
protected MessageDispatcherImpl dispatcher;
protected CommandProcessor agent;
protected MPv3 mpv3;
protected USM usm;
protected EngineBootsCounterFile bootCounterFile;
protected NotificationOriginator notificationOriginator;
protected ProxyForwarder defaultProxyForwarder;
protected OctetString sysDescr =
new OctetString("SNMP4J-Agent - " +
System.getProperty("os.name", "") +
" - " + System.getProperty("os.arch") +
" - " + System.getProperty("os.version"));
protected OID sysOID = new OID("1.3.6.1.4.1.4976");
protected Integer32 sysServices = new Integer32(10);
protected int agentState = STATE_CREATED;
protected OctetString defaultContext;
protected DefaultMOPersistenceProvider defaultPersistenceProvider;
protected String configFileURI;
/**
* Creates a base agent with a {@link DefaultMOServer} as {@link MOServer}.
* To use a different server implementation, modify the {@link #server} member
* after construction.
*
* @param configURI
* the URI of the config file holding persistent data for this agent. If
* persistent data is not used then set this parameter to
* {@code null}.
*/
protected BaseAgent(String configURI) {
this.configFileURI = configURI;
this.server = new DefaultMOServer();
this.defaultPersistenceProvider =
new DefaultMOPersistenceProvider(new MOServer[]{this.server},
configURI);
}
/**
* Creates a base agent with boot-counter, config file, and a CommandProcessor
* for processing SNMP requests.
*
* @param bootCounterFile
* a file with serialized boot-counter information (read/write). If the
* file does not exist it is created on shutdown of the agent.
* @param configFile
* a file with serialized configuration information (read/write). If the
* file does not exist it is created on shutdown of the agent.
* @param commandProcessor
* the {@code CommandProcessor} instance that handles the SNMP
* requests.
*/
protected BaseAgent(File bootCounterFile,
File configFile,
CommandProcessor commandProcessor) {
this((configFile == null) ? null : configFile.getPath());
this.bootCounterFile = new EngineBootsCounterFile(bootCounterFile);
this.agent = commandProcessor;
}
/**
* Initialize transport mappings, message dispatcher, basic MIB modules,
* proxy forwarder, VACM and USM security, and custom MIB modules and objects
* provided by sub-classes.
*
* @throws IOException
* if initialization fails because transport initialization fails.
*/
public void init() throws IOException {
agentState = STATE_INIT_STARTED;
initTransportMappings();
initMessageDispatcher();
server.addContext(new OctetString());
snmpv2MIB = new SNMPv2MIB(sysDescr, sysOID, sysServices);
snmpMpdMib = new SnmpMpdMib(DefaultMOFactory.getInstance());
// register Snmp counters for updates
dispatcher.addCounterListener(snmpv2MIB);
dispatcher.addCounterListener(snmpMpdMib);
mpv3.getCounterSupport().addCounterListener(snmpMpdMib);
agent.addCounterListener(snmpv2MIB);
agent.addCounterListener(snmpMpdMib);
snmpFrameworkMIB =
new SnmpFrameworkMIB(usm.getLocalEngineID(), (USM)
mpv3.getSecurityModel(SecurityModel.SECURITY_MODEL_USM),
dispatcher.getTransportMappings());
usmMIB = new UsmMIB(usm, SecurityProtocols.getInstance());
usm.addUsmUserListener(usmMIB);
vacmMIB = new VacmMIB(new MOServer[]{server});
snmpTargetMIB = new SnmpTargetMIB(dispatcher);
snmpNotificationMIB = new SnmpNotificationMIB();
snmpCommunityMIB = new SnmpCommunityMIB(snmpTargetMIB);
initConfigMIB();
snmpProxyMIB = new SnmpProxyMIB();
notificationOriginator =
new NotificationOriginatorImpl(session, vacmMIB,
snmpv2MIB.getSysUpTime(),
snmpTargetMIB, snmpNotificationMIB, snmpCommunityMIB);
snmpv2MIB.setNotificationOriginator(agent);
usm.getCounterSupport().addCounterListener(snmpv2MIB);
setupDefaultProxyForwarder();
// add USM users
addUsmUser(usm);
// add SNMPv1/v2c community to SNMPv3 security name mappings
addCommunities(snmpCommunityMIB);
addViews(vacmMIB);
addNotificationTargets(snmpTargetMIB, snmpNotificationMIB);
registerSnmpMIBs();
}
protected void initConfigMIB() {
snmp4jLogMIB = new Snmp4jLogMib();
if ((configFileURI != null) && (defaultPersistenceProvider != null)) {
snmp4jConfigMIB = new Snmp4jConfigMib(snmpv2MIB.getSysUpTime());
snmp4jConfigMIB.setSnmpCommunityMIB(snmpCommunityMIB);
snmp4jConfigMIB.setPrimaryProvider(defaultPersistenceProvider);
}
}
/**
* This method can be overwritten by a subagent to specify the contexts
* each MIB module (group) will be registered to.
*
* @param mibGroup
* a group of {@link ManagedObject}s (i.e., a MIB module).
*
* @return the context for which the module should be registered.
* @since 1.1
*/
protected OctetString getContext(MOGroup mibGroup) {
return getDefaultContext();
}
/**
* Register the basic MIB modules at the agent's {@code MOServer}.
*/
protected void registerSnmpMIBs() {
try {
snmpTargetMIB.registerMOs(server, getContext(snmpTargetMIB));
snmpNotificationMIB.registerMOs(server, getContext(snmpNotificationMIB));
vacmMIB.registerMOs(server, getContext(vacmMIB));
usmMIB.registerMOs(server, getContext(usmMIB));
snmpv2MIB.registerMOs(server, getContext(snmpv2MIB));
snmpMpdMib.registerMOs(server, getContext(snmpMpdMib));
snmpFrameworkMIB.registerMOs(server, getContext(snmpFrameworkMIB));
snmpCommunityMIB.registerMOs(server, getContext(snmpCommunityMIB));
snmp4jLogMIB.registerMOs(server, getContext(snmp4jLogMIB));
if (snmp4jConfigMIB != null) {
snmp4jConfigMIB.registerMOs(server, getContext(snmp4jConfigMIB));
}
snmpProxyMIB.registerMOs(server, getContext(snmpProxyMIB));
registerManagedObjects();
} catch (DuplicateRegistrationException ex) {
ex.printStackTrace();
}
}
/**
* Unregister the basic MIB modules from the agent's {@code MOServer}.
*/
protected void unregisterSnmpMIBs() {
snmpTargetMIB.unregisterMOs(server, getContext(snmpTargetMIB));
snmpNotificationMIB.unregisterMOs(server, getContext(snmpNotificationMIB));
vacmMIB.unregisterMOs(server, getContext(vacmMIB));
usmMIB.unregisterMOs(server, getContext(usmMIB));
snmpv2MIB.unregisterMOs(server, getContext(snmpv2MIB));
snmpFrameworkMIB.unregisterMOs(server, getContext(snmpFrameworkMIB));
snmpCommunityMIB.unregisterMOs(server, getContext(snmpCommunityMIB));
snmp4jLogMIB.unregisterMOs(server, getContext(snmp4jLogMIB));
if (snmp4jConfigMIB != null) {
snmp4jConfigMIB.unregisterMOs(server, getContext(snmp4jConfigMIB));
}
snmpProxyMIB.unregisterMOs(server, getContext(snmpProxyMIB));
unregisterManagedObjects();
}
/**
* Register additional managed objects at the agent's server.
*/
protected abstract void registerManagedObjects();
/**
* Unregister additional managed objects from the agent's server.
*/
protected abstract void unregisterManagedObjects();
/**
* Creates and registers the default proxy forwarder application
* ({@link ProxyForwarderImpl}).
*/
protected void setupDefaultProxyForwarder() {
defaultProxyForwarder = new ProxyForwarderImpl(session, snmpProxyMIB,
snmpTargetMIB);
agent.addProxyForwarder(defaultProxyForwarder,
null, ProxyForwarder.PROXY_TYPE_ALL);
((ProxyForwarderImpl) defaultProxyForwarder).addCounterListener(snmpv2MIB);
}
/**
* Loads the configuration using the specified import mode from the set
* config file.
*
* @param importMode
* one of the import modes defined by {@link ImportMode}.
*/
public void loadConfig(int importMode) {
try {
defaultPersistenceProvider.restore(null, importMode);
} catch (IOException ex) {
logger.error(ex);
}
}
/**
* Save the current (serializable) managed object configuration into
* the config file.
*/
public void saveConfig() {
try {
defaultPersistenceProvider.store(configFileURI);
} catch (IOException ex) {
logger.error(ex);
}
}
/**
* Adds a shutdown hook that saves the internal config into the config file
* when a SIGTERM (Ctrl-C) is terminating the agent.
*/
protected void addShutdownHook() {
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
saveConfig();
}
});
}
/**
* Finishes initialization of the agent by connecting server and command
* processor, setting up USM, VACM, notification targets, and finally sending
* a coldStart notification to configured targets.
*/
protected void finishInit() {
if (agentState < STATE_INIT_STARTED) {
logger.fatal("Agent initialization finish is called before " +
"initialization, current state is " + agentState);
}
agent.setNotificationOriginator(notificationOriginator);
agent.addMOServer(server);
agent.setCoexistenceProvider(snmpCommunityMIB);
agent.setVacm(vacmMIB);
dispatcher.addCommandResponder(agent);
agentState = STATE_INIT_FINISHED;
}
protected void sendColdStartNotification() {
notificationOriginator.notify(new OctetString(), SnmpConstants.coldStart,
new VariableBinding[0]);
}
/**
* Starts the agent by let it listen on the configured SNMP agent ports
* (transpot mappings).
*/
public void run() {
if (agentState < STATE_INIT_FINISHED) {
logger.fatal("Agent is run uninitialized, current state is " + agentState);
}
if (agentState == STATE_STOPPED) {
initSnmpSession();
}
try {
session.listen();
agentState = STATE_RUNNING;
} catch (IOException iox) {
logger.error(iox);
}
}
/**
* Stops the agent by closing the SNMP session and associated transport
* mappings.
*
* @since 1.1
*/
public void stop() {
if (agentState != STATE_RUNNING) {
logger.error("Agent is stopped although it is not running, " +
"current state is " + agentState);
}
try {
session.close();
} catch (IOException ex) {
logger.warn("Closing agent session threw IOException: " + ex.getMessage());
}
session = null;
agentState = STATE_STOPPED;
}
/**
* Initializes the message dispatcher ({@link MessageDispatcherImpl}) with
* the transport mappings.
*/
protected void initMessageDispatcher() {
dispatcher = new MessageDispatcherImpl();
mpv3 = new MPv3(agent.getContextEngineID().getValue());
usm = new USM(SecurityProtocols.getInstance(),
agent.getContextEngineID(),
updateEngineBoots());
SecurityModels.getInstance().addSecurityModel(usm);
SecurityProtocols.getInstance().addDefaultProtocols();
dispatcher.addMessageProcessingModel(new MPv1());
dispatcher.addMessageProcessingModel(new MPv2c());
dispatcher.addMessageProcessingModel(mpv3);
initSnmpSession();
}
protected void initSnmpSession() {
session = new Snmp(dispatcher);
for (TransportMapping extends Address> transportMapping : transportMappings) {
try {
session.addTransportMapping(transportMapping);
} catch (Exception ex) {
logger.warn("Failed to initialize transport mapping '" +
transportMapping + "' with: " + ex.getMessage());
}
}
updateSession(session);
}
/**
* Updates all objects with a new session instance. This method must be
* overwritten, if non-default SNMP MIB instances are created by a subclass.
*
* @param session
* a SNMP Session instance.
*/
protected void updateSession(Session session) {
if (notificationOriginator instanceof NotificationOriginatorImpl) {
((NotificationOriginatorImpl) notificationOriginator).setSession(session);
}
if (defaultProxyForwarder instanceof ProxyForwarderImpl) {
((ProxyForwarderImpl) defaultProxyForwarder).setSession(session);
}
}
/**
* Updates the engine boots counter and returns the actual value.
*
* @return the actual boots counter value.
*/
protected int updateEngineBoots() {
return bootCounterFile.updateEngineBoots();
}
/**
* Reads the engine boots counter from the corresponding input stream (file).
*
* @return the boots counter value read or zero if it could not be read.
*/
protected int getEngineBoots() {
return bootCounterFile.getEngineBoots();
}
/**
* Adds all the necessary initial users to the USM.
*
* @param usm
* the USM instance used by this agent.
*/
protected abstract void addUsmUser(USM usm);
/**
* Adds initial notification targets and filters.
*
* @param targetMIB
* the SnmpTargetMIB holding the target configuration.
* @param notificationMIB
* the SnmpNotificationMIB holding the notification (filter)
* configuration.
*/
protected abstract void addNotificationTargets(SnmpTargetMIB targetMIB,
SnmpNotificationMIB notificationMIB);
/**
* Adds initial VACM configuration.
*
* @param vacmMIB
* the VacmMIB holding the agent's view configuration.
*/
protected abstract void addViews(VacmMIB vacmMIB);
/**
* Adds community to security name mappings needed for SNMPv1 and SNMPv2c.
*
* @param communityMIB
* the SnmpCommunityMIB holding coexistence configuration for community
* based security models.
*/
protected abstract void addCommunities(SnmpCommunityMIB communityMIB);
/**
* Initializes the transport mappings (ports) to be used by the agent.
*
* @throws IOException
* if an IO exception occurs while initializing the default transport mapping on all local IP addresses on
* port 161.
*/
protected void initTransportMappings() throws IOException {
transportMappings = new DefaultUdpTransportMapping[]{
new DefaultUdpTransportMapping(new UdpAddress("0.0.0.0/161"))};
}
public NotificationOriginator getNotificationOriginator() {
return notificationOriginator;
}
public void setDefaultProxyForwarder(ProxyForwarder defaultProxyForwarder) {
this.defaultProxyForwarder = defaultProxyForwarder;
}
public void setSysDescr(OctetString sysDescr) {
this.sysDescr.setValue(sysDescr.getValue());
}
public void setSysOID(OID sysOID) {
this.sysOID.setValue(sysOID.getValue());
}
public void setSysServices(Integer32 sysServices) {
this.sysServices.setValue(sysServices.getValue());
}
public void setAgent(CommandProcessor agent) {
this.agent = agent;
}
public void setBootCounterFile(File bootCounterFile) {
this.bootCounterFile = new EngineBootsCounterFile(bootCounterFile);
}
public void setConfigFile(File configFile) {
this.configFileURI = configFile.getPath();
}
/**
* Sets the default context for this base agent. By setting this value before
* any MIB modules have been registered at the internal server, the context
* for which the registration is performed can be changed. The default context
* is {@code null} which causes MIB objects to be virtually registered
* for all contexts.
*
* @param defaultContext
* the context for default MIB objects.
*
* @since 1.1
*/
public void setDefaultContext(OctetString defaultContext) {
this.defaultContext = defaultContext;
}
public ProxyForwarder getDefaultProxyForwarder() {
return defaultProxyForwarder;
}
public OctetString getSysDescr() {
return sysDescr;
}
public OID getSysOID() {
return sysOID;
}
public Integer32 getSysServices() {
return sysServices;
}
public CommandProcessor getAgent() {
return agent;
}
public File getBootCounterFile() {
return bootCounterFile.getBootCounterFile();
}
public File getConfigFile() {
return new File(configFileURI);
}
public Snmp4jConfigMib getSnmp4jConfigMIB() {
return snmp4jConfigMIB;
}
public Snmp4jLogMib getSnmp4jLogMIB() {
return snmp4jLogMIB;
}
public SnmpCommunityMIB getSnmpCommunityMIB() {
return snmpCommunityMIB;
}
public SnmpFrameworkMIB getSnmpFrameworkMIB() {
return snmpFrameworkMIB;
}
public SnmpNotificationMIB getSnmpNotificationMIB() {
return snmpNotificationMIB;
}
public SnmpProxyMIB getSnmpProxyMIB() {
return snmpProxyMIB;
}
public SnmpTargetMIB getSnmpTargetMIB() {
return snmpTargetMIB;
}
public SNMPv2MIB getSnmpv2MIB() {
return snmpv2MIB;
}
public SnmpMpdMib getSnmpMpdMib() {
return snmpMpdMib;
}
public UsmMIB getUsmMIB() {
return usmMIB;
}
public VacmMIB getVacmMIB() {
return vacmMIB;
}
public Snmp getSession() {
return session;
}
public DefaultMOServer getServer() {
return server;
}
public MPv3 getMPv3() {
return mpv3;
}
public USM getUsm() {
return usm;
}
/**
* Returns the agent's state.
*
* @return one of the state's starting from {@link #STATE_CREATED} to
* {@link #STATE_RUNNING}.
* @since 1.1
*/
public int getAgentState() {
return agentState;
}
/**
* Returns the default context - which is the context that is used by the
* base agent to register its MIB objects. By default it is {@code null}
* which causes the objects to be registered virtually for all contexts.
* In that case, subagents for example my not register their own objects
* under the same subtree(s) in any context. To allow subagents to register
* their own instances of those MIB modules, an empty {@code OctetString}
* should be used as default context instead.
*
* @return {@code null} or an {@code OctetString} (normally the empty
* string) denoting the context used for registering default MIBs.
* @since 1.1
*/
public OctetString getDefaultContext() {
return defaultContext;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy