Improve socket-activated service handling

This patch provides a more generic way of handling socket-activated
services like dropbear. A socket-activated service only has base socket
unit and spawns service unit with instance name on incoming connection,
so the instanced units of it need to be ignored. And whether a service
is socket-activated can be determined by checking the existance of its
service object path.

Tested:
* Two socket-activated service, dropbear and obmc-console-ssh, can be
  controlled as expected.
* Instances of socket-activated services are no loger added to monitor
  list.

Change-Id: If8faa2248e5794a410f804125410608aa69b858d
Signed-off-by: Jiaqing Zhao <jiaqing.zhao@intel.com>
diff --git a/inc/srvcfg_manager.hpp b/inc/srvcfg_manager.hpp
index f94e4ea..f70d6a0 100644
--- a/inc/srvcfg_manager.hpp
+++ b/inc/srvcfg_manager.hpp
@@ -99,8 +99,7 @@
     bool unitEnabledState = false;
     bool unitRunningState = false;
 
-    // dropbear is handled specially because it is a socket-activated service.
-    bool isDropBearService = false;
+    bool isSocketActivatedService = false;
     std::string subStateValue;
 
     bool isMaskedOut();
diff --git a/src/main.cpp b/src/main.cpp
index 3d67800..8e7a8a7 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -23,6 +23,7 @@
 
 #include <filesystem>
 #include <fstream>
+#include <unordered_map>
 
 std::unique_ptr<boost::asio::steady_timer> timer = nullptr;
 std::unique_ptr<boost::asio::steady_timer> initTimer = nullptr;
@@ -35,9 +36,11 @@
 
 // Base service name list. All instance of these services and
 // units(service/socket) will be managed by this daemon.
-static std::array<std::string, 6> serviceNames = {
-    "phosphor-ipmi-net", "bmcweb",       "phosphor-ipmi-kcs",
-    "start-ipkvm",       "obmc-console", "dropbear"};
+static std::unordered_map<std::string /* unitName */,
+                          bool /* isSocketActivated */>
+    managedServices = {{"phosphor-ipmi-net", false}, {"bmcweb", false},
+                       {"phosphor-ipmi-kcs", false}, {"start-ipkvm", false},
+                       {"obmc-console", false},      {"dropbear", true}};
 
 enum class UnitType
 {
@@ -118,9 +121,14 @@
             std::get<static_cast<int>(ListUnitElements::name)>(unit);
         auto [unitName, type, instanceName] =
             getUnitNameTypeAndInstance(fullUnitName);
-        if (std::find(serviceNames.begin(), serviceNames.end(), unitName) !=
-            serviceNames.end())
+        if (managedServices.count(unitName))
         {
+            // For socket-activated units, ignore all its instances
+            if (managedServices.at(unitName) == true && !instanceName.empty())
+            {
+                continue;
+            }
+
             std::string instantiatedUnitName =
                 unitName + addInstanceName(instanceName, "_40");
             boost::replace_all(instantiatedUnitName, "-", "_2d");
diff --git a/src/srvcfg_manager.cpp b/src/srvcfg_manager.cpp
index 9840cc4..36857b8 100644
--- a/src/srvcfg_manager.cpp
+++ b/src/srvcfg_manager.cpp
@@ -231,7 +231,7 @@
 void ServiceConfig::queryAndUpdateProperties()
 {
     std::string objectPath =
-        isDropBearService ? socketObjectPath : serviceObjectPath;
+        isSocketActivatedService ? socketObjectPath : serviceObjectPath;
     if (objectPath.empty())
     {
         return;
@@ -333,10 +333,7 @@
     instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
     socketObjectPath(socketObjPath_)
 {
-    if (baseUnitName == "dropbear")
-    {
-        isDropBearService = true;
-    }
+    isSocketActivatedService = serviceObjectPath.empty();
     instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
     updatedFlag = 0;
     queryAndUpdateProperties();
@@ -375,15 +372,16 @@
         {
             systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
         }
-        if (!isDropBearService)
+        if (!isSocketActivatedService)
         {
             systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
         }
         else
         {
-            // Get the ListUnits property, find all the services of
-            // `dropbear@<ip><port>.service` and stop the service through
-            // the systemdUnitAction method
+            // For socket-activated service, each connection will spawn a
+            // service instance from template. Need to find all spawned service
+            // `<unitName>@<attribute>.service` and stop them through the
+            // systemdUnitAction method
             boost::system::error_code ec;
             auto listUnits =
                 conn->yield_method_call<std::vector<ListUnitsType>>(
@@ -400,7 +398,7 @@
                 const auto& status =
                     std::get<static_cast<int>(ListUnitElements::subState)>(
                         unit);
-                if (service.find("dropbear@") != std::string::npos &&
+                if (service.find(baseUnitName + "@") != std::string::npos &&
                     service.find(".service") != std::string::npos &&
                     status == subStateRunning)
                 {
@@ -451,7 +449,7 @@
         {
             unitFiles = {getServiceUnitName()};
         }
-        else if (!socketObjectPath.empty() && isDropBearService)
+        else if (serviceObjectPath.empty())
         {
             unitFiles = {getSocketUnitName()};
         }
@@ -479,7 +477,7 @@
             systemdUnitAction(conn, yield, getSocketUnitName(),
                               sysdRestartUnit);
         }
-        if (!isDropBearService)
+        if (!serviceObjectPath.empty())
         {
             systemdUnitAction(conn, yield, getServiceUnitName(),
                               sysdRestartUnit);