Exemple #1
0
// Destructor
SubscriptionSet::~SubscriptionSet()
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "SubscriptionSet::~ mUri = '%s'",
                 mUri.data());

   // Delete this SubscriptionSet from mSubscribeMap.
   getResourceListSet()->deleteSubscribeMapping(&mSubscriptionEarlyDialogHandle);

   // Terminate the master subscription.
   UtlBoolean ret;
   ret = getResourceListServer()->getSubscribeClient().
      endSubscription(mSubscriptionEarlyDialogHandle.data());
   OsSysLog::add(FAC_RLS,
                 ret ? PRI_DEBUG : PRI_WARNING,
                 "SubscriptionSet::~ endSubscription %s mUri = '%s', mSubscriptionEarlyDialogHandle = '%s'",
                 ret ? "succeeded" : "failed",
                 mUri.data(),
                 mSubscriptionEarlyDialogHandle.data());

   // Delete all the child subscriptions.

   // First, send their termination content.
   UtlSListIterator itor(mSubscriptions);
   ResourceInstance* inst;
   while ((inst = dynamic_cast <ResourceInstance*> (itor())))
   {
      // Set the state of the resource instance to terminated.
      // We do not know what their termination reason is.
      // (:TODO: But it might be possible to determine that.)
      inst->terminateContent("terminated");
   }

   // Since we are about to delete the ResourceInstances, we have to
   // publish their terminated state now or forgo doing so.
   getResourceCached()->setToBePublished(TRUE);

   // Delete the ResourceInstance objects.
   mSubscriptions.destroyAll();

   // Record that the content has been changed again and needs to be
   // published.
   getResourceCached()->setToBePublished();
}
Exemple #2
0
// Process a termination of the subscription of this ResourceInstance.
void ResourceInstance::terminateContent(const char* subscriptionState)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ResourceInstance::terminateContent mInstanceName = '%s', subscriptionState = '%s'",
                 mInstanceName.data(), subscriptionState);

   // Remove the content.
   mContent.remove(0);
   mContentPresent = FALSE;
   destroyXmlDialogs();

   // Update the subscription state.
   mSubscriptionState = subscriptionState;
   // Tell the ResourceCached to generate and publish new content.
   // The resource will be deleted the next time
   // ResourceCache::purgeTerminated() is called.
   getResourceCached()->setToBePublished();
}
Exemple #3
0
// Constructor
ResourceInstance::ResourceInstance(SubscriptionSet* parent,
                                   const char* instanceName,
                                   const char* subscriptionState) :
   mSubscriptionSet(parent),
   mInstanceName(instanceName),
   mSubscriptionState(subscriptionState),
   mContentPresent(FALSE)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ResourceInstance:: mInstanceName = '%s', mSubscriptionSet = '%s', subscriptionState = '%s'",
                 mInstanceName.data(), mSubscriptionSet->getUri()->data(),
                 subscriptionState);

   // Add this ResourceInstance to mNotifyMap.
   getResourceListSet()->addNotifyMapping(mInstanceName, this);

   // Publish the state with the new instance.
   getResourceCached()->setToBePublished();
}
Exemple #4
0
// Process a notify event callback.
void ResourceInstance::notifyEventCallback(const UtlString* dialogHandle,
                                           const UtlString* content)
{
   OsSysLog::add(FAC_RLS, PRI_DEBUG,
                 "ResourceInstance::notifyEventCallback mInstanceName = '%s', content = '%s'",
                 mInstanceName.data(), content->data());
   // Set to true if we find publishable data.
   bool publish = false;

   // Set the subscription state to "active".
   mSubscriptionState = "active";

   // Save the content as text for the RFC 4662 resource list events.
   mContent.remove(0);
   mContent.append(*content);
   mContentPresent = TRUE;

   // Dissect the XML for each dialog event and store it in a map
   // so we can construct BroadWorks-style resource list events
   // (which have to have full state).

   // Initialize Tiny XML document object.
   TiXmlDocument xmlDialogEvent;
   TiXmlNode* dialog_info_node;
   if (
       // Load the XML into it.
       xmlDialogEvent.Parse(mContent.data()) &&
       // Find the top element, which should be a <dialog-info>.
       (dialog_info_node = xmlDialogEvent.FirstChild("dialog-info")) != NULL &&
       dialog_info_node->Type() == TiXmlNode::ELEMENT)
   {
      // Check the state attribute.
      const char* p = dialog_info_node->ToElement()->Attribute("state");
      if (p && strcmp(p, "full") == 0)
      {
         // If the state is "full", terminate all non-terminated dialogs.  (XECS-1668)
         terminateXmlDialogs();
         publish = true;
         OsSysLog::add(FAC_RLS, PRI_DEBUG,
                       "ResourceInstance::notifyEventCallback all non-terminated dialogs");
      }

      // Find all the <dialog> elements.
      for (TiXmlNode* dialog_node = 0;
           (dialog_node = dialog_info_node->IterateChildren("dialog",
                                                            dialog_node));
         )
      {
         if (dialog_node->Type() == TiXmlNode::ELEMENT)
         {
            TiXmlElement* dialog_element = dialog_node->ToElement();

            // Determine if the <dialog> is a bogus report of a NAT Keepalive
            // OPTIONS message, as reported by Polycom SPIP firmware 3.1.2.
            // (XTRN-425)  If so, ignore it.

#ifdef NAT_KEEPALIVE_DETECT
            const char* call_id_attr = dialog_element->Attribute("call-id");
            // Reject <dialog>s on the narrowest grounds, that is, only if the
            // call-id attribute is present and contains NAT_KEEPALIVE_SIGNATURE.
            const bool ok =
               !(call_id_attr &&
                 strstr(call_id_attr,
                        NAT_KEEPALIVE_SIGNATURE) != NULL);
#else
            const bool ok = true;
#endif
            if (ok)
            {
               // Now that we've got a <dialog> element, edit it to fit
               // into a consolidated event notice.
               publish = true;

               // Prepend the resource instance name to the 'id'
               // attribute, so it is unique within the <resource>.
               UtlString id(mInstanceName);
               // mInstanceName is guaranteed to not contain ';', because
               // it is a dialog handle that we generate by concatenating
               // the Call-Id and tags using ',' as a separator.  And ';'
               // may not appear in Call-Ids or tags.
               id.append(";");
               id.append(dialog_element->Attribute("id"));
               dialog_element->SetAttribute("id", id.data());

               // Prepare the display name, so we can insert it easily
               // when we generate consolidated events.
               // Find or add the <local> element.
               TiXmlNode* local = dialog_element->FirstChild("local");
               if (!local)
               {
                  local = dialog_element->LinkEndChild(new TiXmlElement("local"));
               }
               // Find or add the <local><identity> element.
               TiXmlNode* identity = local->FirstChild("identity");
               if (!identity)
               {
                  identity =
                     local->LinkEndChild(new TiXmlElement("identity"));
               }
               // Clear the display attribute.
               identity->ToElement()->SetAttribute("display", "");

               // Put the resource URI as the content of the
               // <local><identity> element.
               // First, remove all text children.
               TiXmlNode* child;
               for (TiXmlNode* prev_child = 0;
                    (child = identity->IterateChildren(prev_child));
                  )
               {
                  if (child->Type() == TiXmlNode::TEXT)
                  {
                     identity->RemoveChild(child);
                     // Leave prev_child unchanged.
                  }
                  else
                  {
                     prev_child = child;
                  }
               }
               // Insert a text child containing the URI.
               identity->LinkEndChild(new TiXmlText(getResourceCached()->
                                                    getUri()->data()));

               // Now that we have the XML all nice and pretty, store a copy of
               // it in mXmlDialogs.
               // Clone the XML and create a UtlVoidPtr to wrap it.
               TiXmlElement* alloc_xml = dialog_element->Clone()->ToElement();

               // Look for an earlier version of this dialog in the hash map.
               UtlVoidPtr* p = dynamic_cast <UtlVoidPtr*> (mXmlDialogs.findValue(&id));
               if (p)
               {
                  // Replace the old XML with new XML.
                  delete static_cast <TiXmlElement*> (p->getValue());
                  p->setValue(alloc_xml);
                  OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                "ResourceInstance::notifyEventCallback replaced dialog with id '%s'",
                                id.data());
               }
               else
               {
                  // Check that we don't have too many dialogs.
                  if (mXmlDialogs.entries() <
                      getResourceListServer()->getMaxDialogsInResInst())
                  {
                     mXmlDialogs.insertKeyAndValue(new UtlString(id),
                                                   new UtlVoidPtr(alloc_xml));
                     OsSysLog::add(FAC_RLS, PRI_DEBUG,
                                   "ResourceInstance::notifyEventCallback added dialog with id '%s'",
                                   id.data());
                  }
                  else
                  {
                     // Free alloc_xml, because we aren't saving a pointer to it.
                     delete alloc_xml;
                     OsSysLog::add(FAC_RLS, PRI_ERR,
                                   "ResourceInstance::notifyEventCallback cannot add dialog with id '%s', already %zu in ResourceInstance '%s'",                                id.data(), mXmlDialogs.entries(),
                                   mInstanceName.data());
                  }
               }
            }
            else
            {
               // The <dialog> was rejected because it appears to report
               // a NAT Maintainer OPTIONS message.
               // We log this at DEBUG level because if these appear,
               // there is likely to be one every 20 seconds.
               OsSysLog::add(FAC_RLS, PRI_DEBUG,
                             "ResourceInstance::notifyEventCallback "
                             "ignored <dialog> reporting a NAT Keepalive message "
                             "in subscription dialog handle '%s' - "
                             "see XTRN-426",
                             mInstanceName.data());
            }
         }
      }
   }
   else
   {
      // Report error parsing XML.
      OsSysLog::add(FAC_RLS, PRI_ERR,
                    "ResourceInstance::notifyEventCallback "
                    "Dialog event from '%s' not parsable.",
                    getResourceCached()->getUri()->data());
      OsSysLog::add(FAC_RLS, PRI_INFO,
                    "ResourceInstance::notifyEventCallback "
                    "Dialog event content is '%s'",
                    content->data());
      // Throw away the content, since we cannot generate matching
      // consolidated content.
      mContentPresent = FALSE;
      mContent.remove(0);
      destroyXmlDialogs();
   }

   // Get the change published, if we found <dialog> that was not incorrect.
   if (publish)
   {
      getResourceCached()->setToBePublished(FALSE, getResourceCached()->getUri());
   }
}