diff options
Diffstat (limited to 'src/lib/config/ccsession.cc')
-rw-r--r-- | src/lib/config/ccsession.cc | 104 |
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 +} + } } |