Fix DB table/column mismatch and stale PID noise on startup
build_data.py created 'profiles' but mac_manager queries 'mac_profiles'. Columns category/model renamed to device_type/device_name. device_type values aligned with _CATEGORY_MAP in mac_manager (streaming, smart_tv, phone, tablet, smart_speaker, iot, printer, gaming). ja3_fingerprints.db table renamed from 'fingerprints' to 'ja3_profiles' and expanded with all columns ja3_spoofer queries (name, description, cipher_suites, extensions, elliptic_curves, ec_point_formats as JSON). StateManager.reset_module_status() clears stale 'running' entries on startup so watchdog doesn't flag old-session PIDs as dead modules. Engine.start_all() calls reset before launch and does a 3s post-startup liveness check, logging any modules that crashed immediately after fork.
This commit is contained in:
+32
-3
@@ -363,8 +363,12 @@ class Engine:
|
||||
|
||||
def start_all(self) -> dict[str, bool]:
|
||||
"""Start all registered modules in dependency order."""
|
||||
# Clear stale PIDs from any previous run so the watchdog does not
|
||||
# report modules from the old session as dead.
|
||||
self.state.reset_module_status()
|
||||
|
||||
order = _topo_sort(self._modules)
|
||||
|
||||
|
||||
# Instantiate and start CaptureBus for passive modules
|
||||
iface = self.config.get("network", {}).get("primary_interface")
|
||||
if iface:
|
||||
@@ -376,17 +380,42 @@ class Engine:
|
||||
except Exception as e:
|
||||
logger.error("Failed to start CaptureBus: %s", e)
|
||||
self.capture_bus = None
|
||||
|
||||
|
||||
# Inject capture_bus into module configs for passive modules
|
||||
# Some modules use "capture_bus", others "_capture_bus" — inject both
|
||||
for name, entry in self._modules.items():
|
||||
if getattr(entry.module_class, "requires_capture_bus", False):
|
||||
entry.config["capture_bus"] = self.capture_bus
|
||||
entry.config["_capture_bus"] = self.capture_bus
|
||||
|
||||
|
||||
results = {}
|
||||
for name in order:
|
||||
results[name] = self.start(name)
|
||||
|
||||
# Post-startup liveness check: wait for module processes to settle,
|
||||
# then verify each one is still alive and log a clear summary.
|
||||
time.sleep(3)
|
||||
alive, dead = [], []
|
||||
with self._lock:
|
||||
for name, entry in self._modules.items():
|
||||
if results.get(name):
|
||||
if entry.process and entry.process.is_alive():
|
||||
alive.append(name)
|
||||
else:
|
||||
dead.append(name)
|
||||
# Update state so watchdog doesn't double-report
|
||||
self.state.set_module_status(name, "stopped")
|
||||
|
||||
if dead:
|
||||
logger.error(
|
||||
"Startup check: %d modules died immediately after launch: %s",
|
||||
len(dead), ", ".join(dead),
|
||||
)
|
||||
logger.info(
|
||||
"Startup check complete — running: %d, failed: %d",
|
||||
len(alive), len(dead),
|
||||
)
|
||||
|
||||
return results
|
||||
|
||||
def stop_all(self, timeout: float = 5.0) -> None:
|
||||
|
||||
@@ -232,6 +232,28 @@ class StateManager:
|
||||
for r in rows
|
||||
}
|
||||
|
||||
def reset_module_status(self) -> None:
|
||||
"""Mark all running modules as stopped.
|
||||
|
||||
Called at engine startup to clear stale PIDs from a previous run.
|
||||
Without this, the watchdog picks up old PIDs and reports dead modules
|
||||
that were never started in the current session.
|
||||
"""
|
||||
conn = self._get_write_conn()
|
||||
try:
|
||||
conn.execute("BEGIN IMMEDIATE")
|
||||
conn.execute(
|
||||
"UPDATE module_status SET status='stopped', pid=NULL, updated=? "
|
||||
"WHERE status='running'",
|
||||
(time.time(),),
|
||||
)
|
||||
conn.commit()
|
||||
except Exception:
|
||||
try:
|
||||
conn.rollback()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Write queue
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user