summaryrefslogtreecommitdiffstats
path: root/src/lib/config/ccsession.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/config/ccsession.cc')
-rw-r--r--src/lib/config/ccsession.cc104
1 files changed, 103 insertions, 1 deletions
diff --git a/src/lib/config/ccsession.cc b/src/lib/config/ccsession.cc
index d094ab9bf6..10bc7286f3 100644
--- a/src/lib/config/ccsession.cc
+++ b/src/lib/config/ccsession.cc
@@ -144,7 +144,7 @@ parseCommand(ConstElementPtr& arg, ConstElementPtr command) {
command->contains(isc::cc::CC_PAYLOAD_COMMAND)) {
ConstElementPtr cmd = command->get(isc::cc::CC_PAYLOAD_COMMAND);
if (cmd->getType() == Element::list &&
- cmd->size() > 0 &&
+ !cmd->empty() &&
cmd->get(0)->getType() == Element::string) {
if (cmd->size() > 1) {
arg = cmd->get(1);
@@ -595,6 +595,8 @@ ModuleCCSession::checkModuleCommand(const std::string& cmd_str,
"Command given but no "
"command handler for module"));
}
+ } else if (unhandled_callback_) {
+ unhandled_callback_(cmd_str, target_module, arg);
}
return (ElementPtr());
}
@@ -609,6 +611,11 @@ ModuleCCSession::checkCommand() {
return (0);
}
+ // In case it is notification, eat it.
+ if (checkNotification(routing, data)) {
+ return (0);
+ }
+
/* ignore result messages (in case we're out of sync, to prevent
* pingpongs */
if (data->getType() != Element::map ||
@@ -884,5 +891,100 @@ ModuleCCSession::rpcCall(const std::string &command, const std::string &group,
}
}
+void
+ModuleCCSession::notify(const std::string& group, const std::string& name,
+ const ConstElementPtr& params)
+{
+ const ElementPtr message(Element::createMap());
+ const ElementPtr notification(Element::createList());
+ notification->add(Element::create(name));
+ if (params) {
+ notification->add(params);
+ }
+ message->set(isc::cc::CC_PAYLOAD_NOTIFICATION, notification);
+ groupSendMsg(message, isc::cc::CC_GROUP_NOTIFICATION_PREFIX + group,
+ isc::cc::CC_INSTANCE_WILDCARD,
+ isc::cc::CC_TO_WILDCARD, false);
+}
+
+ModuleCCSession::NotificationID
+ModuleCCSession::subscribeNotification(const std::string& notification_group,
+ const NotificationCallback& callback)
+{
+ // Either insert a new empty list of callbacks or get an existing one.
+ // Either way, get the iterator for its position.
+ const std::pair<SubscribedNotifications::iterator, bool>& inserted =
+ notifications_.insert(
+ std::pair<std::string, NotificationCallbacks>(notification_group,
+ NotificationCallbacks()));
+ if (inserted.second) {
+ // It was newly inserted. In that case, we need to subscribe to the
+ // group.
+ session_.subscribe(isc::cc::CC_GROUP_NOTIFICATION_PREFIX +
+ notification_group);
+ }
+ // Insert the callback to the chain
+ NotificationCallbacks& callbacks = inserted.first->second;
+ const NotificationCallbacks::iterator& callback_id =
+ callbacks.insert(callbacks.end(), callback);
+ // Just pack the iterators to form the ID
+ return (NotificationID(inserted.first, callback_id));
+}
+
+void
+ModuleCCSession::unsubscribeNotification(const NotificationID& notification) {
+ NotificationCallbacks& callbacks = notification.first->second;
+ // Remove the callback
+ callbacks.erase(notification.second);
+ // If it became empty, remove it from the map and unsubscribe
+ if (callbacks.empty()) {
+ session_.unsubscribe(isc::cc::CC_GROUP_NOTIFICATION_PREFIX +
+ notification.first->first);
+ notifications_.erase(notification.first);
+ }
+}
+
+bool
+ModuleCCSession::checkNotification(const data::ConstElementPtr& envelope,
+ const data::ConstElementPtr& msg)
+{
+ if (msg->getType() != data::Element::map) {
+ // If it's not a map, then it's not a notification
+ return (false);
+ }
+ if (msg->contains(isc::cc::CC_PAYLOAD_NOTIFICATION)) {
+ // There's a notification inside. Extract its parameters.
+ const std::string& group =
+ envelope->get(isc::cc::CC_HEADER_GROUP)->stringValue();
+ const std::string& notification_group =
+ group.substr(std::string(isc::cc::CC_GROUP_NOTIFICATION_PREFIX).
+ size());
+ const data::ConstElementPtr& notification =
+ msg->get(isc::cc::CC_PAYLOAD_NOTIFICATION);
+ // The first one is the event that happened
+ const std::string& event = notification->get(0)->stringValue();
+ // Any other params are second. But they may be missing
+ const data::ConstElementPtr params =
+ notification->size() == 1 ? data::ConstElementPtr() :
+ notification->get(1);
+ // Find the chain of notification callbacks
+ const SubscribedNotifications::iterator& chain_iter =
+ notifications_.find(notification_group);
+ if (chain_iter == notifications_.end()) {
+ // This means we no longer have any notifications for this group.
+ // This can happen legally as a race condition - if msgq sends
+ // us a notification, but we unsubscribe before we get to it
+ // in the input stream.
+ return (false);
+ }
+ BOOST_FOREACH(const NotificationCallback& callback,
+ chain_iter->second) {
+ callback(event, params);
+ }
+ return (true);
+ }
+ return (false); // Not a notification
+}
+
}
}