/*
* Copyright 2011-16 Fraunhofer ISE
*
* This file is part of OpenMUC.
* For more information visit http://www.openmuc.org
*
* OpenMUC is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenMUC is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenMUC. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openmuc.framework.driver.snmp;
import java.util.HashMap;
import java.util.Map;
import org.openmuc.framework.config.ArgumentSyntaxException;
import org.openmuc.framework.config.DriverInfo;
import org.openmuc.framework.config.ScanException;
import org.openmuc.framework.config.ScanInterruptedException;
import org.openmuc.framework.driver.snmp.implementation.SnmpDevice;
import org.openmuc.framework.driver.snmp.implementation.SnmpDevice.SNMPVersion;
import org.openmuc.framework.driver.snmp.implementation.SnmpDeviceV1V2c;
import org.openmuc.framework.driver.snmp.implementation.SnmpDeviceV3;
import org.openmuc.framework.driver.spi.Connection;
import org.openmuc.framework.driver.spi.ConnectionException;
import org.openmuc.framework.driver.spi.DriverDeviceScanListener;
import org.openmuc.framework.driver.spi.DriverService;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Mehran Shakeri
*
*/
@Component
public final class SnmpDriver implements DriverService {
private final static Logger logger = LoggerFactory.getLogger(SnmpDriver.class);
private final static DriverInfo info = new DriverInfo("snmp", "snmp v1/v2c/v3 are supported.", "?", "?", "?", "?");
// AUTHENTICATIONPASSPHRASE is the same COMMUNITY word in SNMP V2c
public enum SnmpDriverSettingVariableNames {
SNMPVersion,
USERNAME,
SECURITYNAME,
AUTHENTICATIONPASSPHRASE,
PRIVACYPASSPHRASE
};
// AUTHENTICATIONPASSPHRASE is the same COMMUNITY word in SNMP V2c
public enum SnmpDriverScanSettingVariableNames {
SNMPVersion,
USERNAME,
SECURITYNAME,
AUTHENTICATIONPASSPHRASE,
PRIVACYPASSPHRASE,
STARTIP,
ENDIP
};
// exception messages
private final static String nullDeviceAddressException = "No device address found in config. Please specify one [eg. \"1.1.1.1/161\"].";
private final static String nullSettingsException = "No device settings found in config. Please specify settings.";
private final static String incorrectSettingsFormatException = "Format of setting string is invalid! \n Please use this format: "
+ "USERNAME=username:SECURITYNAME=securityname:AUTHENTICATIONPASSPHRASE=password:PRIVACYPASSPHRASE=privacy";
private final static String incorrectSNMPVersionException = "Incorrect snmp version value. "
+ "Please choose proper version. Possible values are defined in SNMPVersion enum";
private final static String nullSNMPVersionException = "Snmp version is not defined. "
+ "Please choose proper version. Possible values are defined in SNMPVersion enum";
@Override
public DriverInfo getInfo() {
return info;
}
/**
* Currently only supports SNMP V2c
*
* Default port number 161 is used
*
* @param settings
* at least must contain<br>
*
* <br>
* SnmpDriverSettingVariableNames.AUTHENTICATIONPASSPHRASE: (community word) in case of more than on
* value, they should be separated by ",". No community word is allowed to contain "," <br>
* SnmpDriverScanSettingVariableNames.STARTIP: Start of IP range <br>
* SnmpDriverScanSettingVariableNames.ENDIP: End of IP range <br>
* eg. "AUTHENTICATIONPASSPHRASE=community,public:STARTIP=1.1.1.1:ENDIP=1.10.1.1"
*
*/
@Override
public void scanForDevices(String settings, DriverDeviceScanListener listener)
throws ArgumentSyntaxException, ScanException, ScanInterruptedException {
Map<String, String> settingMapper = settingParser(settings);
// Current implementation is only for SNMP version 2c
SnmpDeviceV1V2c snmpScanner;
try {
snmpScanner = new SnmpDeviceV1V2c(SNMPVersion.V2c);
} catch (ConnectionException e) {
throw new ScanException(e.getMessage());
}
SnmpDriverDiscoveryListener discoveryListener = new SnmpDriverDiscoveryListener(listener);
snmpScanner.addEventListener(discoveryListener);
String[] communityWords = settingMapper
.get(SnmpDriverScanSettingVariableNames.AUTHENTICATIONPASSPHRASE.toString()).split(",");
snmpScanner.scanSnmpV2cEnabledDevices(settingMapper.get(SnmpDriverScanSettingVariableNames.STARTIP.toString()),
settingMapper.get(SnmpDriverScanSettingVariableNames.ENDIP.toString()), communityWords);
}
@Override
public void interruptDeviceScan() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
*
* @param settings
* SNMPVersion=V2c:COMMUNITY=value:SECURITYNAME=value:AUTHENTICATIONPASSPHRASE=value:PRIVACYPASSPHRASE=
* value
*
* @throws ConnectionException
* thrown if SNMP listen or initialization failed
* @throws ArgumentSyntaxException
* thrown if Device address foramt is wrong
*/
@Override
public Connection connect(String deviceAddress, String settings)
throws ConnectionException, ArgumentSyntaxException {
SnmpDevice device = null;
SNMPVersion snmpVersion = null;
// check arguments
if (deviceAddress == null || deviceAddress.equals("")) {
throw new ArgumentSyntaxException(nullDeviceAddressException);
}
else if (settings == null || settings.equals("")) {
throw new ArgumentSyntaxException(nullSettingsException);
}
else {
Map<String, String> mappedSettings = settingParser(settings);
try {
snmpVersion = SNMPVersion
.valueOf(mappedSettings.get(SnmpDriverSettingVariableNames.SNMPVersion.toString()));
} catch (IllegalArgumentException e) {
throw new ArgumentSyntaxException(incorrectSNMPVersionException);
} catch (NullPointerException e) {
throw new ArgumentSyntaxException(nullSNMPVersionException);
}
// create SnmpDevice object based on SNMP version
switch (snmpVersion) {
case V1:
case V2c:
device = new SnmpDeviceV1V2c(snmpVersion, deviceAddress,
mappedSettings.get(SnmpDriverSettingVariableNames.AUTHENTICATIONPASSPHRASE.toString()));
break;
case V3:
device = new SnmpDeviceV3(deviceAddress,
mappedSettings.get(SnmpDriverSettingVariableNames.USERNAME.toString()),
mappedSettings.get(SnmpDriverSettingVariableNames.SECURITYNAME.toString()),
mappedSettings.get(SnmpDriverSettingVariableNames.AUTHENTICATIONPASSPHRASE.toString()),
mappedSettings.get(SnmpDriverSettingVariableNames.PRIVACYPASSPHRASE.toString()));
break;
default:
throw new ArgumentSyntaxException(incorrectSNMPVersionException);
}
}
return device;
}
/**
* Read settings string and put them in a Key,Value HashMap Each setting consists of a pair of key/value and is
* separated by ":" from other settings Inside the setting string, key and value are separated by "=" e.g.
* "key1=value1:key2=value3" Be careful! "=" and ":" are not allowed in keys and values
*
* if your key contains more than one value, you can separate values by ",". in this case "," is not allowed in
* values.
*
* @param settings
* @return Map<String,String>
* @throws ArgumentSyntaxException
*/
private Map<String, String> settingParser(String settings) throws ArgumentSyntaxException {
Map<String, String> settingsMaper = new HashMap<>();
try {
String[] settingsArray = settings.split(":");
for (String setting : settingsArray) {
String[] keyValue = setting.split("=", 2);
settingsMaper.put(keyValue[0], keyValue[1]);
}
} catch (ArrayIndexOutOfBoundsException e) {
throw new ArgumentSyntaxException(incorrectSettingsFormatException);
}
return settingsMaper;
}
}