max_pigs = ThreadConfig::get_instance_max();
assert(max_pigs > 0);
+ ThreadConfig::start_watchdog();
// maximum number of state change notifications per pig
constexpr unsigned max_grunts = static_cast<unsigned>(Analyzer::State::NUM_STATES);
{ "utc", Parameter::PT_BOOL, nullptr, "false",
"use UTC instead of local time for timestamps" },
+ { "watchdog_timer", Parameter::PT_INT, "0:60", "0",
+ "watchdog timer for packet threads (seconds, 0 to disable)" },
+
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
else if (v.is("name"))
name = v.get_string();
+ else if ( v.is("watchdog_timer") )
+ sc->set_watchdog(v.get_uint16());
+
return true;
}
log_dir.clear();
}
+void SnortConfig::set_watchdog(uint16_t n)
+{
+ watchdog_timer = n;
+}
+
void SnortConfig::set_dirty_pig(bool enabled)
{
dirty_pig = enabled;
// chown() use this later, -1 means no change to user_id/group_id
int user_id = -1;
int group_id = -1;
-
+ uint16_t watchdog_timer = 0;
bool dirty_pig = false;
std::string chroot_dir; /* -t or config chroot */
void set_no_logging_timestamps(bool);
void set_obfuscate(bool);
void set_obfuscation_mask(const char*);
+ void set_overlay_trace_config(TraceConfig*);
void set_include_path(const char*);
void set_process_all_events(bool);
void set_rule_db_dir(const char*);
void set_uid(const char*);
void set_umask(uint32_t);
void set_utc(bool);
- void set_overlay_trace_config(TraceConfig*);
+ void set_watchdog(uint16_t);
SO_PUBLIC bool set_latency_enable();
//------------------------------------------------------
#include "thread_config.h"
+#include <atomic>
#include <hwloc.h>
+#include "analyzer_command.h"
#include "log/messages.h"
+#include "main/snort_config.h"
+#include "time/periodic.h"
#include "utils/util.h"
#ifdef UNIT_TEST
implement_thread_affinity(get_thread_type(), DEFAULT_THREAD_ID);
}
+// watchdog stuff
+struct Watchdog
+{
+ Watchdog(uint16_t tm) : seconds_count(tm)
+ {
+ resp = new std::atomic_bool[ThreadConfig::get_instance_max()];
+ }
+ ~Watchdog() { delete[] resp; }
+ void kick();
+ bool waiting = false;
+ std::atomic_bool* resp;
+ uint16_t seconds_count;
+};
+
+class WatchdogKick : public AnalyzerCommand
+{
+public:
+ WatchdogKick(Watchdog* d) : dog(d) { dog->waiting = true; }
+ bool execute(Analyzer&, void**) override
+ {
+ dog->resp[get_instance_id()] = true;
+ return true;
+ }
+ const char* stringify() override { return "WATCHDOG_KICK"; }
+
+ ~WatchdogKick() override { dog->waiting = false; }
+private:
+ Watchdog* dog;
+};
+
+void Watchdog::kick()
+{
+ unsigned max = ThreadConfig::get_instance_max();
+ if ( waiting )
+ {
+ int n = 0;
+ WarningMessage("Packet processing thread is unresponsive, aborting Snort!\n");
+ WarningMessage("Unresponsive thread ID: ");
+ for ( unsigned i = 0; i < max; ++i )
+ if ( !resp[i] )
+ WarningMessage("%d ", i);
+ WarningMessage("\n");
+ abort();
+ }
+
+ for ( unsigned i = 0; i < max; ++i )
+ resp[i] = false;
+
+ main_broadcast_command(new WatchdogKick(this), nullptr);
+}
+
+static void s_watchdog_handler(void*)
+{
+ static Watchdog s_dog(SnortConfig::get_conf()->watchdog_timer);
+ if ( SnortConfig::get_conf()->watchdog_timer > 0 )
+ {
+ if ( s_dog.seconds_count > 0 )
+ s_dog.seconds_count--;
+ else
+ {
+ s_dog.kick();
+ s_dog.seconds_count = SnortConfig::get_conf()->watchdog_timer;
+ }
+ }
+}
+
+void ThreadConfig::start_watchdog()
+{
+ Periodic::register_handler(s_watchdog_handler, nullptr, 0, 1000);
+}
+
// -----------------------------------------------------------------------------
// unit tests
static void set_instance_max(unsigned);
static unsigned get_instance_max();
static void term();
+ static void start_watchdog();
~ThreadConfig();
void set_thread_affinity(SThreadType, unsigned id, CpuSet*);