package com.owera.xaps.tr069.methods; import java.io.FileWriter; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.security.NoSuchAlgorithmException; import java.sql.SQLException; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; import com.owera.common.log.Context; import com.owera.xaps.base.BaseCache; import com.owera.xaps.base.JobLogic; import com.owera.xaps.base.Log; import com.owera.xaps.base.db.DBAccess; import com.owera.xaps.base.db.DBAccessSessionTR069; import com.owera.xaps.dbi.Unit; import com.owera.xaps.dbi.util.SystemParameters; import com.owera.xaps.dbi.util.TimestampWrapper; import com.owera.xaps.tr069.CPEParameters; import com.owera.xaps.tr069.CommandKey; import com.owera.xaps.tr069.HTTPReqResData; import com.owera.xaps.tr069.InformParameters; import com.owera.xaps.tr069.ParameterKey; import com.owera.xaps.tr069.Properties; import com.owera.xaps.tr069.SessionData; import com.owera.xaps.tr069.background.ScheduledKickTask; import com.owera.xaps.tr069.exception.TR069DatabaseException; import com.owera.xaps.tr069.exception.TR069Exception; import com.owera.xaps.tr069.exception.TR069ExceptionShortMessage; import com.owera.xaps.tr069.test.system1.KillDatabase; import com.owera.xaps.tr069.test.system1.KillDatabaseObject; import com.owera.xaps.tr069.test.system1.TestDatabase; import com.owera.xaps.tr069.test.system1.TestDatabaseObject; import com.owera.xaps.tr069.xml.DeviceIdStruct; import com.owera.xaps.tr069.xml.EventList; import com.owera.xaps.tr069.xml.EventStruct; import com.owera.xaps.tr069.xml.Header; import com.owera.xaps.tr069.xml.ParameterList; import com.owera.xaps.tr069.xml.ParameterValueStruct; import com.owera.xaps.tr069.xml.Parser; public class INreq { private static void parseEvents(Parser parser, SessionData sessionData) { EventList eventList = parser.getEventList(); Set<Integer> eventCodeIntSet = new TreeSet<Integer>(); Set<String> eventCodeStrSet = new HashSet<String>(); sessionData.setCommandKey(new CommandKey()); for (int i = 0; eventList != null && i < eventList.getEventList().size(); i++) { EventStruct es = eventList.getEventList().get(i); String[] tmpArr = es.getEventCode().split(" "); try { eventCodeIntSet.add(Integer.parseInt(tmpArr[0])); } catch (NumberFormatException nfe) { eventCodeStrSet.add(tmpArr[0]); } if (es.getEventCode().startsWith("0")) sessionData.setFactoryReset(true); if (es.getEventCode().startsWith("1")) sessionData.setBooted(true); if (es.getEventCode().startsWith("2")) sessionData.setPeriodic(true); if (es.getEventCode().startsWith("4")) sessionData.setValueChange(true); if (es.getEventCode().startsWith("6")) sessionData.setKicked(true); if (es.getEventCode().startsWith("8")) sessionData.setDiagnosticsComplete(true); // This is a quick-and-easy impl. since, there can potentially be more than // one CommandKey. However, I don't think this will be the case in practice. (Morten May 2012) // TODO: This is surely not correct - Morten Jul 2012 if (es.getCommandKey() != null && !es.getCommandKey().trim().equals("")) sessionData.getCommandKey().setCpeKey(es.getCommandKey()); } String eventCodes = StringUtils.join(eventCodeIntSet.iterator(), ","); if (eventCodeStrSet.size() > 0) eventCodes += "," + StringUtils.join(eventCodeStrSet.iterator(), ","); if (eventCodes.length() > 0) { sessionData.setEventCodes(eventCodes); } } private static String getUnitId(DeviceIdStruct deviceIdStruct) throws UnsupportedEncodingException { String unitId = null; if (deviceIdStruct.getProductClass() != null && !deviceIdStruct.getProductClass().trim().equals("")) { unitId = deviceIdStruct.getOui() + "-" + deviceIdStruct.getProductClass() + "-" + deviceIdStruct.getSerialNumber(); } else { unitId = deviceIdStruct.getOui() + "-" + deviceIdStruct.getSerialNumber(); } return URLDecoder.decode(unitId, "UTF-8"); } private static void parseParameters(SessionData sessionData, Parser parser) throws TR069Exception { ParameterList parameterList = parser.getParameterList(); List<ParameterValueStruct> parameterValues = parameterList.getParameterValueList(); String keyRoot = null; CPEParameters cpeParams = null; InformParameters informParams = null; ParameterKey pk = new ParameterKey(); sessionData.setParameterKey(pk); for (ParameterValueStruct pvs : parameterValues) { if (sessionData.getKeyRoot() == null) { String paramValue = pvs.getName(); int keyRootEndPos = paramValue.indexOf("."); keyRoot = paramValue.substring(0, keyRootEndPos + 1); if (keyRoot != null && (keyRoot.equals("Device.") || keyRoot.equals("InternetGatewayDevice."))) { sessionData.setKeyRoot(keyRoot); // String configFileVersionParameter = "DeviceInfo.VendorConfigFile.1.Version"; // if (Properties.isConfigFileVersionQuirk(sessionData)) // configFileVersionParameter = "DeviceInfo.VendorConfigFile.Version"; cpeParams = new CPEParameters(keyRoot); sessionData.setCpeParameters(cpeParams); informParams = new InformParameters(keyRoot); sessionData.setInformParameters(informParams); } } if (cpeParams != null) { if (pvs.getName().equals(cpeParams.SOFTWARE_VERSION)) { cpeParams.putPvs(cpeParams.SOFTWARE_VERSION, pvs); sessionData.setSoftwareVersion(pvs.getValue()); } if (pvs.getName().equals(cpeParams.CONNECTION_URL)) cpeParams.putPvs(cpeParams.CONNECTION_URL, pvs); if (informParams != null && pvs.getName().equals(informParams.UDP_CONNECTION_URL)) informParams.putPvs(informParams.UDP_CONNECTION_URL, pvs); // if (pvs.getName().equals(cpeParams.CONFIG_VERSION)) // cpeParams.putPvs(cpeParams.CONFIG_VERSION, pvs); } if (pvs.getName().indexOf("ParameterKey") > -1) pk.setCpeKey(pvs.getValue()); } if (keyRoot == null) { throw new TR069Exception("Parsed INreq params, but no keyroot could be found, most likely because no parameters were sent in ParameterList", TR069ExceptionShortMessage.MISC); } else { String msg = "Parsed INreq params, found keyroot:" + keyRoot + ", parameterkey:" + pk.getCpeKey(); msg += ", swver:" + (cpeParams == null ? "Unknown" : ""+ cpeParams.getValue(cpeParams.SOFTWARE_VERSION)); Log.debug(INreq.class, msg); } } private static void reportKill(String unitId, boolean expected) { try { FileWriter fw = new FileWriter("kill-report-" + unitId + ".txt", true); FileWriter fwDetails = new FileWriter("kill-report-details-" + unitId + ".txt", true); if (expected) { fw.write("Booted"); fwDetails.write("\nBooted - probably a good-natured boot."); } else { fw.write("Booted (unexpected)"); fwDetails.write("\nBooted - not supposed to happen - no SPV-response was received."); } fw.close(); fwDetails.close(); } catch (Throwable t) { Log.warn(INreq.class, "Error occurred in printReport(): " + t); } } private static void logPeriodicInformTiming(SessionData sessionData) { try { if (sessionData.getUnit() != null && sessionData.isPeriodic()) { Unit unit = sessionData.getUnit(); if (unit.getUnitParameters() != null) { String PII = unit.getParameterValue(SystemParameters.PERIODIC_INTERVAL, false); String LCT = unit.getParameterValue(SystemParameters.LAST_CONNECT_TMS, false); if (PII != null && LCT != null) { long shouldConnectTms = TimestampWrapper.tmsFormat.parse(LCT).getTime() + Integer.parseInt(PII) * 1000; long diff = System.currentTimeMillis() - shouldConnectTms; if (diff > -5000 && diff < 5000) Log.info(INreq.class, "Periodic Inform recorded on time (" + diff / 1000 + " sec). Deviation: " + (diff / 10) / Integer.parseInt(PII) + " %"); else if (diff >= 5000) Log.info(INreq.class, "Periodic Inform recorded too late (" + diff / 1000 + " sec). Deviation: " + (diff / 10) / Integer.parseInt(PII) + " %"); else // diff <= -5000 Log.info(INreq.class, "Periodic Inform recorded too early (" + diff / 1000 + " sec). Deviation: " + (diff / 10) / Integer.parseInt(PII) + " %"); } } } } catch (Throwable t) { Log.warn(INreq.class, "LogPeriodicInformTiming failed - no consequence for provisioning: ", t); } } public static void process(HTTPReqResData reqRes) throws TR069Exception { try { reqRes.getRequest().setMethod(TR069Method.INFORM); Parser parser = new Parser(reqRes.getRequest().getXml()); SessionData sessionData = reqRes.getSessionData(); Header header = parser.getHeader(); reqRes.setTR069TransactionID(header.getId()); DeviceIdStruct deviceIdStruct = parser.getDeviceIdStruct(); // If unit is authenticated, the unitId is already found String unitId = sessionData.getUnitId(); if (unitId == null) unitId = getUnitId(deviceIdStruct); Context.put(Context.X, unitId, BaseCache.SESSIONDATA_CACHE_TIMEOUT); BaseCache.putSessionData(unitId, sessionData); sessionData.setUnitId(unitId); sessionData.setSerialNumber(deviceIdStruct.getSerialNumber()); parseEvents(parser, sessionData); parseParameters(sessionData, parser); sessionData.updateParametersFromDB(unitId); // Unit-object is read and populated in SessionData logPeriodicInformTiming(sessionData); ScheduledKickTask.removeUnit(unitId); if (Properties.isTestMode()) { String row = TestDatabase.database.select(sessionData.getUnitId()); if (row != null) { TestDatabaseObject tdo = new TestDatabaseObject(row); if (tdo.getRun().equals("true") && sessionData.isBooted()) { KillDatabaseObject kdo = new KillDatabaseObject(KillDatabase.database.select(sessionData.getUnitId())); reportKill(sessionData.getUnitId(), !kdo.isTestRunning()); } } } if (Properties.isDiscoveryMode() && sessionData.isFirstConnect()) { DBAccessSessionTR069 dbAccessSessionTR069 = new DBAccessSessionTR069(DBAccess.getDBI(), sessionData.getDbAccess()); dbAccessSessionTR069.writeUnittypeProfileUnit(sessionData, deviceIdStruct.getProductClass(), unitId); sessionData.setFromDB(null); sessionData.setOweraParameters(null); sessionData.updateParametersFromDB(unitId); Log.debug(INreq.class, "Unittype, profile and unit is created, since discovery mode is enabled and this is the first connect"); } sessionData.getCommandKey().setServerKey(reqRes); sessionData.getParameterKey().setServerKey(reqRes); boolean jobOk = JobLogic.checkJobOK(sessionData); sessionData.setJobUnderExecution(!jobOk); } catch (TR069Exception ex) { throw ex; } catch (SQLException e) { throw new TR069DatabaseException(e); } catch (UnsupportedEncodingException uee) { throw new TR069Exception("Not possible to decode the Unit id", TR069ExceptionShortMessage.MISC, uee); } catch (NoSuchAlgorithmException e) { throw new TR069Exception("Not possible to make a parameter key", TR069ExceptionShortMessage.MISC, e); } } }