UtlBoolean DialogEventPublisher::handleMessage(OsMsg& rMsg) { SipDialog sipDialog; UtlString sipDialogContent; Url requestUrl; UtlString entity; UtlString* pEntity; char dialogId[10]; SipDialogEvent* pThisCall; Dialog* pDialog; UtlString localTag, remoteTag; Url localIdentity, remoteIdentity; Url localTarget, remoteTarget; UtlString identity, displayName; OsTime receivedTime; int numOldContents; HttpBody* oldContent[1]; int length; UtlString dialogEvent; // React to telephony events if(rMsg.getMsgSubType()== TaoMessage::EVENT) { TaoMessage* taoMessage = (TaoMessage*)&rMsg; int taoEventId = taoMessage->getTaoObjHandle(); UtlString argList(taoMessage->getArgList()); TaoString arg(argList, TAOMESSAGE_DELIMITER); #ifdef DEBUGGING dumpTaoMessageArgs(taoEventId, arg) ; #endif UtlBoolean localConnection = atoi(arg[TAO_OFFER_PARAM_LOCAL_CONNECTION]); UtlString callId = arg[TAO_OFFER_PARAM_CALLID] ; UtlString address = arg[TAO_OFFER_PARAM_ADDRESS] ; switch (taoEventId) { case PtEvent::CONNECTION_OFFERED: mpCallManager->getSipDialog(callId, address, sipDialog); #ifdef DEBUGGING sipDialog.toString(sipDialogContent); OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", sipDialogContent.data()); #endif sipDialog.getRemoteRequestUri(entity); OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: Call arrived: callId %s address %s requestUrl %s", callId.data(), address.data(), entity.data()); if (entity.isNull()) { OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call arrived: callId %s address %s without requestUrl", callId.data(), address.data()); break; } else { requestUrl = Url(entity); requestUrl.getIdentity(entity); } // Create a dialog event if has not been created yet pThisCall = (SipDialogEvent *) mCalls.findValue(&entity); if (pThisCall == NULL) { pEntity = new UtlString(entity); pThisCall = new SipDialogEvent(STATE, entity); mCalls.insertKeyAndValue(pEntity, pThisCall); OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: insert DialogEvent object %p to the list", pThisCall); } // Create the dialog element sipDialog.getLocalField(localIdentity); localIdentity.getFieldParameter("tag", localTag); sipDialog.getRemoteField(remoteIdentity); remoteIdentity.getFieldParameter("tag", remoteTag); sprintf(dialogId, "%ld", mDialogId); mDialogId++; pDialog = new Dialog(dialogId, callId, localTag, remoteTag, "recipient"); pDialog->setState(STATE_EARLY, NULL, NULL); localIdentity.getIdentity(identity); localIdentity.getDisplayName(displayName); pDialog->setLocalIdentity(identity, displayName); remoteIdentity.getIdentity(identity); remoteIdentity.getDisplayName(displayName); pDialog->setRemoteIdentity(identity, displayName); sipDialog.getLocalContact(localTarget); pDialog->setLocalTarget(localTarget.toString()); sipDialog.getRemoteContact(remoteTarget); pDialog->setRemoteTarget(remoteTarget.toString()); pDialog->setDuration(OsDateTime::getSecsSinceEpoch()); pThisCall->insertDialog(pDialog); // Insert it into the active call list pThisCall->buildBody(); // Send the content to the subscribe server if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent)) { pThisCall->getBytes(&dialogEvent, &length); OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call arrived - DialogEvent %s\n was not successfully published to the subscribe server", dialogEvent.data()); } break; case PtEvent::CONNECTION_ESTABLISHED: if (localConnection) { mpCallManager->getSipDialog(callId, address, sipDialog); #ifdef DEBUGGING sipDialog.toString(sipDialogContent); OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", sipDialogContent.data()); #endif sipDialog.getRemoteRequestUri(entity); OsSysLog::add(FAC_SIP, PRI_DEBUG, "Call connected: callId %s address %s with request %s", callId.data(), address.data(), entity.data()); if (entity.isNull()) { OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call connected: callId %s address %s without requestUrl", callId.data(), address.data()); break; } else { requestUrl = Url(entity); requestUrl.getIdentity(entity); } pThisCall = (SipDialogEvent *) mCalls.findValue(&entity); if (pThisCall == NULL) { pEntity = new UtlString(entity); pThisCall = new SipDialogEvent(STATE, entity); // Insert it into the active call list mCalls.insertKeyAndValue(pEntity, pThisCall); } // Get the new callId because it might be changed sipDialog.getCallId(callId); pDialog = pThisCall->getDialog(callId); // Update the dialog content if exist if (pDialog) { sipDialog.getLocalField(localIdentity); localIdentity.getFieldParameter("tag", localTag); sipDialog.getRemoteField(remoteIdentity); remoteIdentity.getFieldParameter("tag", remoteTag); pDialog->setTags(localTag, remoteTag); sipDialog.getLocalContact(localTarget); pDialog->setLocalTarget(localTarget.toString()); sipDialog.getRemoteContact(remoteTarget); pDialog->setRemoteTarget(remoteTarget.toString()); pDialog->setState(STATE_CONFIRMED, NULL, NULL); } else { // Create a new dialog element sipDialog.getLocalField(localIdentity); localIdentity.getFieldParameter("tag", localTag); sipDialog.getRemoteField(remoteIdentity); remoteIdentity.getFieldParameter("tag", remoteTag); sprintf(dialogId, "%ld", mDialogId); mDialogId++; pDialog = new Dialog(dialogId, callId, localTag, remoteTag, "recipient"); pDialog->setState(STATE_CONFIRMED, NULL, NULL); localIdentity.getIdentity(identity); localIdentity.getDisplayName(displayName); pDialog->setLocalIdentity(identity, displayName); remoteIdentity.getIdentity(identity); remoteIdentity.getDisplayName(displayName); pDialog->setRemoteIdentity(identity, displayName); sipDialog.getLocalContact(localTarget); pDialog->setLocalTarget(localTarget.toString()); sipDialog.getRemoteContact(remoteTarget); pDialog->setRemoteTarget(remoteTarget.toString()); pDialog->setDuration(OsDateTime::getSecsSinceEpoch()); pThisCall->insertDialog(pDialog); } pThisCall->buildBody(); // Publish the content to the subscribe server if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent)) { pThisCall->getBytes(&dialogEvent, &length); OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call connected - DialogEvent %s\n was not successfully published to the subscribe server", dialogEvent.data()); } } break; case PtEvent::CONNECTION_DISCONNECTED: if (!localConnection) { mpCallManager->getSipDialog(callId, address, sipDialog); #ifdef DEBUGGING sipDialog.toString(sipDialogContent); OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: sipDialog = %s", sipDialogContent.data()); #endif sipDialog.getLocalContact(requestUrl); requestUrl.getIdentity(entity); OsSysLog::add(FAC_SIP, PRI_DEBUG, "Call dropped: %s address %s with entity %s", callId.data(), address.data(), entity.data()); if (entity.isNull()) { OsSysLog::add(FAC_SIP, PRI_WARNING, "DialogEventPublisher:: Call dropped: callId %s address %s without requestUrl", callId.data(), address.data()); break; } // Get the new callId because it might be changed sipDialog.getCallId(callId); // Remove the call from the pool and clean up the call pThisCall = (SipDialogEvent *) mCalls.findValue(&entity); if (pThisCall) { pDialog = pThisCall->getDialog(callId); if (pDialog) { pDialog->setState(STATE_TERMINATED, NULL, NULL); pThisCall->buildBody(); // Publish the content to the subscribe server if (!mpSipPublishContentMgr->publish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, (HttpBody**)&pThisCall, 1, numOldContents, oldContent)) { pThisCall->getBytes(&dialogEvent, &length); OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - DialogEvent %s\n was not successfully published to the subscribe server", dialogEvent.data()); } // Remove the dialog from the dialog event package pDialog = pThisCall->removeDialog(pDialog); delete pDialog; } if (pThisCall->isEmpty()) { // Unpublisher the content from the subscribe server if (!mpSipPublishContentMgr->unpublish(entity.data(), DIALOG_EVENT_TYPE, DIALOG_EVENT_TYPE, 1, numOldContents, oldContent)) { pThisCall->getBytes(&dialogEvent, &length); OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - DialogEvent %s\n was not successfully unpublished to the subscribe server", dialogEvent.data()); } UtlContainable *foundValue; mCalls.removeKeyAndValue(pEntity, foundValue); if (foundValue) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "DialogEventPublisher:: remove DialogEvent object %p from the list", pThisCall); pThisCall = (SipDialogEvent *) foundValue; delete pThisCall; delete pEntity; } } } else { OsSysLog::add(FAC_SIP, PRI_ERR, "DialogEventPublisher:: Call dropped - no entity %s founded in the active call list", entity.data()); } } break; case PtEvent::CONNECTION_FAILED: OsSysLog::add(FAC_SIP, PRI_WARNING, "Connection failed on call: %s", callId.data()); break; } } return(TRUE); }
/// Process an incoming NOTIFY from an Appearance. Always sends a response. void AppearanceGroup::handleNotifyRequest(const UtlString* dialogHandle, const SipMessage* msg) { SipMessage response; Appearance* pThisAppearance = findAppearance(*dialogHandle); if ( !pThisAppearance ) { UtlString swappedDialogHandle; mAppearanceGroupSet->swapTags(*dialogHandle, swappedDialogHandle); pThisAppearance = findAppearance(swappedDialogHandle); if ( !pThisAppearance ) { // should never happen, since the NOTIFY was sent straight to the Appearance Os::Logger::instance().log(FAC_SAA, PRI_WARNING, "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY from unknown subscription, dialogHandle %s", dialogHandle->data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 481, "Subscription does not exist"); getAppearanceAgent()->getServerUserAgent().send(response); return; } } UtlString contactUri = pThisAppearance->getUri()->data(); // check that event type is supported UtlString eventType; msg->getEventField(eventType); if (eventType != SLA_EVENT_TYPE) { Os::Logger::instance().log(FAC_SAA, PRI_INFO, "AppearanceGroup::handleNotifyRequest: ignoring NOTIFY(%s): not an SLA event", eventType.data()); response.setOkResponseData(msg, NULL); getAppearanceAgent()->getServerUserAgent().send(response); return; } // Get the NOTIFY content. const char* content; ssize_t l; const HttpBody* body = msg->getBody(); if (body) { body->getBytes(&content, &l); } else { Os::Logger::instance().log(FAC_SAA, PRI_WARNING, "AppearanceGroup::handleNotifyRequest: could not get NOTIFY content, dialogHandle %s", dialogHandle->data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 493, "Undecipherable"); getAppearanceAgent()->getServerUserAgent().send(response); return; } SipDialogEvent* lContent = new SipDialogEvent(content); UtlString state; UtlString entity; lContent->getState(state); lContent->getEntity(entity); UtlString dialogState = STATE_TERMINATED; UtlString event; UtlString code; UtlString appearanceId; if (state == STATE_TERMINATED) { // probably not needed now that SipSubscribeClient checks for NOTIFY with terminated state // our subscription to this Appearance has terminated. Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest: subscription to %s has been terminated", contactUri.data()); // terminate any non-held dialogs? or all dialogs? } Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest: %s update from %s", state.data(), contactUri.data()); // Assign each dialog a globally-unique ID, if not done yet UtlSListIterator* itor = lContent->getDialogIterator(); Dialog* pDialog; while ( (pDialog = dynamic_cast <Dialog*> ((*itor)())) ) { UtlString dialogId; UtlString uniqueDialogId; UtlString rendering; pDialog->getDialogId(dialogId); pDialog->getLocalParameter("x-line-id", appearanceId); pDialog->getLocalParameter("+sip.rendering", rendering); pDialog->getState(dialogState, event, code); // Ignore calls with no appearanceId - these are considered "exclusive". // (e.g. MoH calls are private to the set involved) // These dialogs are not forwarded on to other sets in either partial or full updates. if ( appearanceId == "" ) { Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest skipping call with no appearance info"); delete lContent->removeDialog(pDialog); continue; } if ( dialogId.contains("@@") ) { // this is one of our identifiers already uniqueDialogId = dialogId; } else { // make a guaranteed unique dialog id, by // prepending to each id value the call-id of the subscription // from which the dialog event was obtained, with "@@" as a separator msg->getCallIdField(&uniqueDialogId); uniqueDialogId.append("@@"); uniqueDialogId.append(dialogId); pDialog->setDialogId(uniqueDialogId); } Os::Logger::instance().log(FAC_SAA, PRI_INFO, "AppearanceGroup::handleNotifyRequest: " "%s update from %s: dialogId %s, x-line-id %s, state %s(%s)", state.data(), contactUri.data(), uniqueDialogId.data(), appearanceId.data(), dialogState.data(), rendering.data()); } delete itor; // Check to see if this appearance (of the Appearance) is available bool okToProceed = true; if ( state == "partial" && dialogState == "trying" ) { UtlHashMapIterator appitor(mAppearances); UtlString* handle; while ( okToProceed && (handle = dynamic_cast <UtlString*> (appitor()))) { Appearance* inst = dynamic_cast <Appearance*> (appitor.value()); okToProceed = !inst->appearanceIdIsSeized(appearanceId); } } bool bSendPartialContent = false; bool bSendFullContent = false; // Send the response. if (okToProceed) { response.setOkResponseData(msg, NULL); } else { Os::Logger::instance().log(FAC_SAA, PRI_DEBUG, "AppearanceGroup::handleNotifyRequest '%s' appearanceId %s is busy", entity.data(), appearanceId.data()); response.setInterfaceIpPort(msg->getInterfaceIp(), msg->getInterfacePort()); response.setResponseData(msg, 409, "Conflict"); } getAppearanceAgent()->getServerUserAgent().send(response); if (okToProceed) { if (lContent) { // Send the content to the proper Appearance instance, so it can // save these dialogs, and set flag to indicate whether they should be sent in partial update bSendPartialContent = pThisAppearance->updateState(lContent, bSendFullContent); } // Publish full and partial updates to the SipPublishContentMgr publish(bSendFullContent, bSendPartialContent, lContent); } // Adjust the expiration of the subscription if the set has the line "seized" // and return it to the longer default if it does not. UtlHashMapIterator appitor(mAppearances); UtlString* handle; while ( (handle = dynamic_cast <UtlString*> (appitor()))) { Appearance* inst = dynamic_cast <Appearance*> (appitor.value()); // if set has line seized, use short subscription timer if ( inst->appearanceIsBusy() ) { inst->setResubscribeInterval(true); } else { inst->setResubscribeInterval(false); } } if (lContent) { delete lContent; } }