From 0577b212080e42b44b3ddb10e4e460217fbb3a47 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 8 Nov 2023 19:02:20 +0000 Subject: [PATCH] update --- src/tmx/TmxUtils/src/SNMPClient.cpp | 5 +- .../RSUHealthMonitorPlugin/CMakeLists.txt | 2 +- .../RSUHealthMonitorPlugin/manifest.json | 2 +- .../src/RSUHealthMonitorPlugin.cpp | 148 +++++++++++------- .../src/RSUHealthMonitorPlugin.h | 10 +- 5 files changed, 106 insertions(+), 61 deletions(-) diff --git a/src/tmx/TmxUtils/src/SNMPClient.cpp b/src/tmx/TmxUtils/src/SNMPClient.cpp index e6d1a5c80..d872978ca 100644 --- a/src/tmx/TmxUtils/src/SNMPClient.cpp +++ b/src/tmx/TmxUtils/src/SNMPClient.cpp @@ -160,7 +160,7 @@ namespace tmx::utils { } } - PLOG(logERROR) << "Created OID for input: " << input_oid; + PLOG(logINFO) << "Created OID for input: " << input_oid; } // Send the request int status = snmp_synch_response(ss, pdu, &response); @@ -183,6 +183,7 @@ namespace tmx::utils { PLOG(logDEBUG1) << "Integer value in object: " << val.val_int; } else{ + snmp_free_pdu(response); PLOG(logERROR) << "Response specifies type integer, but no integer value found"; return false; } @@ -199,11 +200,13 @@ namespace tmx::utils { } else{ + snmp_free_pdu(response); PLOG(logERROR) << "Response specifies type string, but no string value found"; return false; } } else{ + snmp_free_pdu(response); PLOG(logERROR) << "Received a message type which isn't an integer or string"; return false; } diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt b/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt index 52fc01004..995f8254c 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt +++ b/src/v2i-hub/RSUHealthMonitorPlugin/CMakeLists.txt @@ -10,4 +10,4 @@ find_library(libasn1c .) BuildTmxPlugin() TARGET_INCLUDE_DIRECTORIES(${PROJECT_NAME} PUBLIC ${NETSNMP_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC tmxutils ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP} ${NETSNMP_LIBRARIES} jsoncpp) \ No newline at end of file +TARGET_LINK_LIBRARIES(${PROJECT_NAME} PUBLIC tmxutils ${NETSNMPAGENT} ${NETSNMPMIBS} ${NETSNMP} ${NETSNMP_LIBRARIES} jsoncpp NemaTode) \ No newline at end of file diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json b/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json index 11fccff61..1737e8123 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json +++ b/src/v2i-hub/RSUHealthMonitorPlugin/manifest.json @@ -39,7 +39,7 @@ }, { "key":"RSUOIDConfigMap", - "default":"{\"RSUOIDConfig\":[{\"RsuField\":\"rsuGpsOutputString\",\"OID\":\"iso.0.15628.4.1.8.5.0\"},{\"RsuField\":\"rsuID\",\"OID\":\"iso.0.15628.4.1.17.4.0\"},{\"RsuField\":\"rsuMibVersion\",\"OID\":\"iso.0.15628.4.1.17.1.0\"},{\"RsuField\":\"rsuFirmwareVersion\",\"OID\":\"iso.0.15628.4.1.17.2.0 \"},{\"RsuField\":\"rsuManufacturer\",\"OID\":\"iso.0.15628.4.1.17.5.0\"},{\"RsuField\":\"rsuIFMIndex\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMPsid\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMDsrcMsgId\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMTxMode\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMTxChannel\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMEnable\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuIFMStatus\",\"OID\":\"iso.3.6.1.2.1.1.7.0\"},{\"RsuField\":\"rsuMode\",\"OID\":\"iso.0.15628.4.1.99.0\"}]}", + "default":"{\"RSUOIDConfig\":[{\"RsuField\":\"rsuGpsOutputString\",\"OID\":\"iso.0.15628.4.1.8.5.0\",\"Required\":false},{\"RsuField\":\"rsuID\",\"OID\":\"iso.0.15628.4.1.17.4.0\",\"Required\":false},{\"RsuField\":\"rsuMibVersion\",\"OID\":\"iso.0.15628.4.1.17.1.0\",\"Required\":false},{\"RsuField\":\"rsuFirmwareVersion\",\"OID\":\"iso.0.15628.4.1.17.2.0 \",\"Required\":false},{\"RsuField\":\"rsuManufacturer\",\"OID\":\"iso.0.15628.4.1.17.5.0\",\"Required\":false},{\"RsuField\":\"rsuIFMIndex\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMPsid\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMDsrcMsgId\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMTxMode\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMTxChannel\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMEnable\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuIFMStatus\",\"OID\":\"iso.3.6.1.2.1.1.7.0\",\"Required\":false},{\"RsuField\":\"rsuMode\",\"OID\":\"iso.0.15628.4.1.99.0\",\"Required\":false}]}", "description":"OID (Object Identifier) uniquely identify managed objects in a MIB database." } ] diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.cpp b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.cpp index 11135fcb4..3ea196bc5 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.cpp +++ b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.cpp @@ -29,18 +29,6 @@ namespace RSUHealthMonitor string rsuOIDMapJsonStr; GetConfigValue("RSUOIDConfigMap", rsuOIDMapJsonStr); UpdateRSUOIDConfig(rsuOIDMapJsonStr); - - // Create SNMP client and use SNMP V3 protocol - try - { - _snmpClientPtr = std::make_shared(_rsuIp, _snmpPort, "", _securityUser, "authNoPriv", _authPassPhrase, 3); - PLOG(logINFO) << "Updated SNMP client call: RSU IP: " << _rsuIp << ", RSU port: " << _snmpPort << ", User: " << _securityUser << ", auth pass phrase: " << _authPassPhrase << ", security level: " - << "authNoPriv"; - } - catch (std::exception &ex) - { - PLOG(logERROR) << "Cannot create SNMP client due to an error. The error message is: " << ex.what(); - } } void RSUHealthMonitorPlugin::UpdateRSUOIDConfig(string &json_str) @@ -67,7 +55,7 @@ namespace RSUHealthMonitor RSUOIDConfig config; config.field = child.second.get("RsuField"); config.oid = child.second.get("OID"); - PLOG(logINFO) << "RSU OID Config: Field: " << config.field << ", OID: " << config.oid; + config.required = child.second.get("Required"); // Add RSU OID to the map _rsuOIDConfigMap.push_back(config); } @@ -88,63 +76,112 @@ namespace RSUHealthMonitor { while (true) { - PLOG(logDEBUG) << "RSU status update call at every " << _interval << "seconds!"; - // Broadcast the RSU status info when there are any RSU responses. - string json_str = getRSUstatus(); - if (json_str.length() > 0) + try { - tmx::messages::RSUStatusMessage sendRsuStatusMsg; - sendRsuStatusMsg.set_contents(json_str); - BroadcastMessage(sendRsuStatusMsg); + auto rsuStatusJson = getRSUstatus(); + + if (!rsuStatusJson.empty()) + { + vector rsuStatusFields; + for (auto const &field : rsuStatusJson.getMemberNames()) + { + rsuStatusFields.push_back(field); + } + // Only broadcast RSU status when all required fields are present. + if (isAllRequiredFieldsPresent(rsuStatusFields)) + { + Json::FastWriter fasterWirter; + string json_str = fasterWirter.write(rsuStatusJson); + tmx::messages::RSUStatusMessage sendRsuStatusMsg; + sendRsuStatusMsg.set_contents(json_str); + BroadcastMessage(sendRsuStatusMsg); + PLOG(logINFO) << "Broadcast RSU status: " << json_str; + } + } + } + catch (std::exception &ex) + { + PLOG(logERROR) << ex.what(); } this_thread::sleep_for(chrono::seconds(_interval)); } } - string RSUHealthMonitorPlugin::getRSUstatus() + Json::Value RSUHealthMonitorPlugin::getRSUstatus() { + if (_rsuOIDConfigMap.size() == 0) + { + PLOG(logERROR) << "RSU status update call failed due to RSUOIDConfigMap is empty!"; + return Json::nullValue; + } + PLOG(logDEBUG) << "RSU status update call at every " << _interval << " seconds!\n"; + + // Create SNMP client and use SNMP V3 protocol + auto _snmpClientPtr = std::make_unique(_rsuIp, _snmpPort, "", _securityUser, "authNoPriv", _authPassPhrase, 3); + PLOG(logINFO) << "Updated SNMP client call: RSU IP: " << _rsuIp << ", RSU port: " << _snmpPort << ", User: " << _securityUser << ", auth pass phrase: " << _authPassPhrase << ", security level: " + << "authNoPriv"; + if (_snmpClientPtr == nullptr) + { + PLOG(logERROR) << "Error creating SNMP client!"; + return Json::nullValue; + } + Json::Value rsuStatuJson; // Sending RSU SNMP call for each field as each field has its own OID. - for_each(_rsuOIDConfigMap.begin(), _rsuOIDConfigMap.end(), [this, &rsuStatuJson](RSUOIDConfig &config) - { - try + for (auto &config : _rsuOIDConfigMap) + { + try + { + PLOG(logINFO) << "SNMP RSU status call for field:" << config.field << ", OID: " << config.oid; + snmp_response_obj responseVal; + auto success = _snmpClientPtr->process_snmp_request(config.oid, request_type::GET, responseVal); + if (!success) + { + // If any snmp request failed, stop any furthur snmp requests using the same current snmp session as the next OID will not be created. + break; + } + else if (success && responseVal.type == snmp_response_obj::response_type::INTEGER) + { + rsuStatuJson[config.field] = responseVal.val_int; + } + else if (success && responseVal.type == snmp_response_obj::response_type::STRING) + { + string response_str(responseVal.val_string.begin(), responseVal.val_string.end()); + PLOG(logDEBUG) << "String value in response: " << response_str; + // Proess GPS nmea string + if (boost::iequals("rsuGpsOutputString", config.field)) { - PLOG(logINFO) << "SNMP RSU status call for field:"<< config.field << ", OID: " << config.oid; - snmp_response_obj responseVal; - if(_snmpClientPtr != nullptr) - { - _snmpClientPtr->process_snmp_request(config.oid, request_type::GET, responseVal); - if(responseVal.type == snmp_response_obj::response_type::INTEGER) - { - rsuStatuJson[config.field] = responseVal.val_int; - } - else if(responseVal.type == snmp_response_obj::response_type::STRING) - { - string response_str(responseVal.val_string.begin(), responseVal.val_string.end()); - if(boost::iequals("rsuGpsOutputString", config.field)) - { - auto gps = ParseGPS(response_str); - rsuStatuJson["rsuGpsOutputStringLatitude"] = gps[0]; - rsuStatuJson["rsuGpsOutputStringLongitude"] = gps[1]; - }else{ - rsuStatuJson[config.field] = response_str; - } - } - } + auto gps = ParseGPS(response_str); + rsuStatuJson["rsuGpsOutputStringLatitude"] = gps[0]; + rsuStatuJson["rsuGpsOutputStringLongitude"] = gps[1]; } - catch (std::exception &ex) + else { - PLOG(logERROR) << "SNMP call failure due to: " << ex.what(); - } }); + rsuStatuJson[config.field] = response_str; + } + } + } + catch (std::exception &ex) + { + PLOG(logERROR) << "SNMP call failure due to: " << ex.what(); + } + } + return rsuStatuJson; + } - if (!rsuStatuJson.empty()) + bool RSUHealthMonitorPlugin::isAllRequiredFieldsPresent(vector fields) + { + bool isAllPresent = true; + for (auto &config : _rsuOIDConfigMap) { - Json::FastWriter fasterWirter; - string json_str = fasterWirter.write(rsuStatuJson); - return json_str; + if (config.required && std::find(fields.begin(), fields.end(), config.field) == fields.end()) + { + isAllPresent = false; + PLOG(logWARNING) << "No broadcast as required field " << config.field << " is not present!"; + } } - return ""; + return isAllPresent; } std::map RSUHealthMonitorPlugin::ParseGPS(const std::string &gps_nmea_data) @@ -161,9 +198,8 @@ namespace RSUHealthMonitor std::stringstream sss; sss << std::setprecision(8) << std::fixed << gps.fix.longitude << std::endl; auto longitude_str = sss.str(); - boost::erase_all(longitude_str, "."); - boost::erase_all(latitude_str, "."); result.insert({std::stol(latitude_str), std::stol(longitude_str)}); + PLOG(logDEBUG) << "Parse GPS NMEA string: " << gps_nmea_data << ". Result (Latitude, Longitude): (" << latitude_str << "," << longitude_str << ")"; } catch (nmea::NMEAParseError &e) { diff --git a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.h b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.h index c7b00a5ef..e1c4c53af 100755 --- a/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.h +++ b/src/v2i-hub/RSUHealthMonitorPlugin/src/RSUHealthMonitorPlugin.h @@ -11,6 +11,7 @@ #include #include "RSUStatusMessage.h" #include +#include using namespace tmx::utils; using namespace std; @@ -23,6 +24,7 @@ namespace RSUHealthMonitor { string field; string oid; + bool required; // Indicate whether this field is required to before broadcasting the RSU status. }; class RSUHealthMonitorPlugin : public PluginClient @@ -35,7 +37,7 @@ namespace RSUHealthMonitor string _authPassPhrase; string _securityUser; vector _rsuOIDConfigMap; - std::shared_ptr _snmpClientPtr; + // std::shared_ptr _snmpClientPtr; /** * @brief Update RSU OID configuration map with input JSON string. * @param JSON string with RSU OID configuration. @@ -48,13 +50,17 @@ namespace RSUHealthMonitor /** * @brief Sending SNMP requests to get info for each field in the _rsuOIDConfigMap, and return the RSU status in JSON string */ - string getRSUstatus(); + Json::Value getRSUstatus(); /** * @brief Parse NMEA GPS sentense and return GPS related data * @param gps_nmea_data NMEA GPS sentense * @return map A map of latitude and longitude */ std::map ParseGPS(const std::string &gps_nmea_data); + /** + * @brief determine if all required fields in the RSU config map _rsuOIDConfigMap present in the input fields + */ + bool isAllRequiredFieldsPresent(vector fields); public: RSUHealthMonitorPlugin(std::string name);