// 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(); }
// 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(); }
// 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(); }
// 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()); } }