uint32_t RuleSetPrivate::upsertRule(const Rule& match_rule, const Rule& new_rule, const bool parent_insensitive) { std::unique_lock<std::mutex> op_lock(_op_mutex); Pointer<Rule> matching_rule; for (auto& rule_ptr : _rules) { if (rule_ptr->internal()->appliesTo(match_rule, parent_insensitive)) { if (!matching_rule) { matching_rule = rule_ptr; } else { throw Exception("Rule set upsert", "rule", "Cannot upsert; multiple matching rules"); } } } if (matching_rule) { const uint32_t id = matching_rule->getRuleID(); *matching_rule = new_rule; matching_rule->setRuleID(id); return id; } else { return appendRule(new_rule, Rule::LastID, /*lock=*/false); } }
void RuleSetPrivate::save(std::ostream& stream) const { std::unique_lock<std::mutex> io_lock(_io_mutex); std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto const& rule : _rules) { const std::string rule_string = rule->toString(); stream << rule_string << std::endl; } }
Pointer<Rule> RuleSetPrivate::getRule(uint32_t id) { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto const& rule : _rules) { if (rule->getRuleID() == id) { return rule; } } throw Exception("Rule set lookup", "rule id", "id doesn't exist"); }
Pointer<const Rule> RuleSetPrivate::getRule(uint32_t seqn) { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto const& rule : _rules) { if (rule->getSeqn() == seqn) { return rule; } } throw std::out_of_range("Rule not found"); }
uint32_t RuleSetPrivate::appendRule(const Rule& rule, uint32_t parent_id, bool lock) { std::unique_lock<std::mutex> op_lock(_op_mutex, std::defer_lock); if (lock) { op_lock.lock(); } auto rule_ptr = makePointer<Rule>(rule); /* * If the rule doesn't already have a sequence number * assigned, do it now. Otherwise update the sequence * number counter so that we don't generate a duplicit * one if assignID() gets called in the future. */ if (rule_ptr->getRuleID() == Rule::DefaultID) { assignID(rule_ptr); } else { _id_next = std::max(_id_next.load(), rule_ptr->getRuleID() + 1); } /* Initialize conditions */ rule_ptr->internal()->initConditions(_interface_ptr); /* Append the rule to the main rule table */ if (parent_id == Rule::LastID) { _rules.push_back(rule_ptr); } else if (parent_id == 0) { _rules.insert(_rules.begin(), rule_ptr); } else { bool parent_found = false; for (auto it = _rules.begin(); it != _rules.end(); ++it) { const Rule& rule = **it; if (rule.getRuleID() == parent_id) { _rules.insert(it+1, rule_ptr); parent_found = true; break; } } if (!parent_found) { throw Exception("Rule set append", "rule", "Invalid parent ID"); } } /* If the rule is timed, put it into the priority queue */ if (rule_ptr->getTimeoutSeconds() > 0) { _rules_timed.push(rule_ptr); } return rule_ptr->getRuleID(); }
bool RuleSetPrivate::removeRule(uint32_t id) { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto it = _rules.begin(); it != _rules.end(); ++it) { auto const& rule_ptr = *it; if (rule_ptr->getRuleID() == id) { _rules.erase(it); return true; } } /* FIXME: Remove the rule from the priority queue too */ throw Exception("Rule set remove", "rule id", "id doesn't exist"); }
bool RuleSetPrivate::removeRule(uint32_t seqn) { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto it = _rules.begin(); it != _rules.end(); ++it) { auto const& rule_ptr = *it; if (rule_ptr->getSeqn() == seqn) { _rules.erase(it); return true; } } /* FIXME: Remove the rule from the priority queue too */ return false; }
Pointer<Rule> RuleSetPrivate::getFirstMatchingRule(Pointer<const Rule> device_rule, uint32_t from_id) const { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto& rule_ptr : _rules) { if (rule_ptr->internal()->appliesToWithConditions(*device_rule, /*with_update*/true)) { return rule_ptr; } } Pointer<Rule> default_rule = makePointer<Rule>(); default_rule->setRuleID(Rule::ImplicitID); default_rule->setTarget(_default_target); return default_rule; }
Pointer<const Rule> RuleSetPrivate::getFirstMatchingRule(Pointer<const Rule> device_rule, uint32_t from_seqn) { std::unique_lock<std::mutex> op_lock(_op_mutex); for (auto const& rule_ptr : _rules) { if (rule_ptr->appliesTo(device_rule)) { return rule_ptr; } } Pointer<Rule> default_rule = makePointer<Rule>(); default_rule->setSeqn(Rule::SeqnDefault); default_rule->setTarget(_default_target); default_rule->setAction(_default_action); return default_rule; }
Pointer<Rule> RuleSetPrivate::getTimedOutRule() { std::unique_lock<std::mutex> op_lock(_op_mutex); if (_rules_timed.size() < 1) { return nullptr; } Pointer<Rule> oldest_rule = _rules_timed.top(); std::chrono::steady_clock::time_point tp_current = \ std::chrono::steady_clock::now(); if ((tp_current - oldest_rule->internal()->metadata().tp_created) \ < std::chrono::seconds(oldest_rule->getTimeoutSeconds())) { return nullptr; } else { _rules_timed.pop(); } return oldest_rule; }
uint32_t RuleSetPrivate::appendRule(const Rule& rule, uint32_t parent_seqn) { std::unique_lock<std::mutex> op_lock(_op_mutex); auto rule_ptr = makePointer<Rule>(rule); /* Assign a unique sequence number to the rule */ assignSeqn(rule_ptr); /* Set time */ rule_ptr->setTimePointAdded(std::chrono::steady_clock::now()); /* Append the rule to the main rule table */ if (parent_seqn == Rule::SeqnLast) { _rules.push_back(rule_ptr); } else if (parent_seqn == 0) { _rules.insert(_rules.begin(), rule_ptr); } else { bool parent_found = false; for (auto it = _rules.begin(); it != _rules.end(); ++it) { const Rule& rule = **it; if (rule.getSeqn() == parent_seqn) { _rules.insert(it+1, rule_ptr); parent_found = true; break; } } if (!parent_found) { throw std::runtime_error("Invalid parent_seqn"); } } /* If the rule is timed, put it into the priority queue */ if (rule_ptr->getTimeoutSeconds() > 0) { _rules_timed.push(rule_ptr); } return rule_ptr->getSeqn(); }
void RuleSetPrivate::setDefaultAction(const String& action) { std::unique_lock<std::mutex> op_lock(_op_mutex); _default_action = action; }
Rule::Target RuleSetPrivate::getDefaultTarget() const { std::unique_lock<std::mutex> op_lock(_op_mutex); return _default_target; }
void RuleSetPrivate::setDefaultTarget(Rule::Target target) { std::unique_lock<std::mutex> op_lock(_op_mutex); _default_target = target; }