UtlBoolean SipRefreshManager::getAcceptedExpiration(RefreshDialogState* state, const SipMessage& sipResponse, int& expirationPeriod) { UtlString method; UtlBoolean foundExpiration = FALSE; int cseq; sipResponse.getCSeqField(&cseq, &method); if(method.compareTo(SIP_REGISTER_METHOD) == 0) { // Get the presumably first contact in the REGISTER request // so that we can find the same contact in the response and // find out what the expiration is UtlString requestContact; Url requestContactUri; if(state && state->mpLastRequest && state->mpLastRequest->getContactEntry(0, &requestContact)) { requestContactUri = requestContact; } // Register could have it in the Contact header UtlString responseContactValue; int contactIndex = 0; while(sipResponse.getContactEntry(contactIndex , &responseContactValue)) { // Get the expires parameter for the contact if it exists Url contactUri(responseContactValue); if(requestContactUri.isUserHostPortEqual(contactUri)) { UtlString contactExpiresParameter; if(contactUri.getFieldParameter(SIP_EXPIRES_FIELD, contactExpiresParameter) && !contactExpiresParameter.isNull()) { foundExpiration = TRUE; // Convert to int expirationPeriod = atoi(contactExpiresParameter); } } contactIndex++; } } if(!foundExpiration) { // Not sure if we care if this is a request or response foundExpiration = sipResponse.getExpiresField(&expirationPeriod); } return(foundExpiration); }
UtlBoolean SipRefreshManager::getInitialExpiration(const SipMessage& sipRequest, int& expirationPeriod) { UtlString method; UtlBoolean foundExpiration = FALSE; sipRequest.getRequestMethod(&method); if(method.compareTo(SIP_REGISTER_METHOD) == 0) { // Register could have it in the Contact header UtlString requestContactValue; if(sipRequest.getContactEntry(0 , &requestContactValue)) { // Get the expires parameter for the contact if it exists Url contactUri(requestContactValue); UtlString contactExpiresParameter; if(contactUri.getFieldParameter(SIP_EXPIRES_FIELD, contactExpiresParameter) && !contactExpiresParameter.isNull()) { foundExpiration = TRUE; // Convert to int expirationPeriod = atoi(contactExpiresParameter); } } } if(!foundExpiration) { // Not sure if we care if this is a request or response foundExpiration = sipRequest.getExpiresField(&expirationPeriod); } return(foundExpiration); }
AuthPlugin::AuthResult TransferControl::authorizeAndModify(const UtlString& id, /**< The authenticated identity of the * request originator, if any (the null * string if not). * This is in the form of a SIP uri * identity value as used in the * credentials database (user@domain) * without the scheme or any parameters. */ const Url& requestUri, ///< parsed target Uri RouteState& routeState, ///< the state for this request. const UtlString& method,///< the request method AuthResult priorResult,///< results from earlier plugins. SipMessage& request, ///< see AuthPlugin wrt modifying bool bSpiralingRequest, ///< request spiraling indication UtlString& reason ///< rejection reason ) { AuthResult result = CONTINUE; // get the call-id to use in logging UtlString callId; request.getCallIdField(&callId); UtlString hostAddress; int hostPort; UtlString hostProtocols; //requestUri.getHostAddress(hostAddress); //request.getContactUri(0, &hostAddress);; request.getContactAddress(0, &hostAddress,&hostPort,&hostProtocols); if (DENY != priorResult) { if (method.compareTo(SIP_REFER_METHOD) == 0) { UtlString targetStr; if (request.getReferToField(targetStr)) { Url target(targetStr, Url::NameAddr); // parse the target URL UtlString targetMethod; if ( Url::SipUrlScheme == target.getScheme() /* REFER can create requests other than INVITE: we don't care about those * * so check that the method is INVITE or is unspecified (INVITE is the default) */ && ( ! target.getUrlParameter(SIP_METHOD_URI_PARAMETER, targetMethod) || (0==targetMethod.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase)) )) { if (id.isNull()) { // UnAuthenticated REFER. Do challenge the REFER to confirm the // identity of the transferor. Note: prior to XECS-2487, we used to challenge // only the unauthenticated REFERs that didn't carry a Replaces header. // The fix for XECS-2487 now requires that all unauthenticated REFERs // be challenged so that consultative transfers get routed properly // when user-based gateway section is used. See tracker for the details if (mpSipRouter->isLocalDomain(target)) { //White list of two servets to let Exchange REFER to sipXecs endpoints if (hostAddress.compareTo(server1, UtlString::ignoreCase) == 0 || hostAddress.compareTo(server2, UtlString::ignoreCase) == 0) { Os::Logger::instance().log(FAC_AUTH, PRI_INFO, "TransferControl[%s]::authorizeAndModify " "Whitelist host '%s' in call '%s'", mInstanceName.data(),hostAddress.data(),callId.data() ); result = ALLOW; //Whitelist matched so allow the transfer }else{ Os::Logger::instance().log(FAC_AUTH, PRI_INFO, "TransferControl[%s]::authorizeAndModify " "challenging transfer in call '%s' from host '%s'", mInstanceName.data(), callId.data(),hostAddress.data() ); result = DENY; // we need an identity to attach to the Refer-To URI } } else { /* * This is a transfer to a target outside our domain, so let it go * unchallenged. See XECS-806 */ Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify " "allowing foriegn transfer in call '%s'", mInstanceName.data(), callId.data() ); // Add the References to the refer-to. Adding the callId field as a reference // header (will be used in resulting INVITE) in the Refer-To provides us // with enough information to be able to logically tie the calls together. // Useful for CDR records. UtlString refcallId(callId); refcallId.append(";rel=refer"); target.setHeaderParameter(SIP_REFERENCES_FIELD, refcallId.data()); Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify " "adding Reference field [%s] to refer-to", mInstanceName.data(), callId.data() ); request.setReferToField(target.toString().data()); result = ALLOW; } } else { UtlString contactString; request.getContactEntry(0, &contactString); Url contactUri( contactString ); UtlString userId; contactUri.getUserId(contactString); Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl::authorizeAndModify - Contact field is: %s ", contactString.data()); if (contactString != "callcontroller") { // Authenticated REFER // annotate the refer-to with the authenticated controller identity SipXauthIdentity controllerIdentity; controllerIdentity.setIdentity(id); controllerIdentity.encodeUri(target); // add the References to the refer-to. UtlString refcallId(callId); refcallId.append(";rel=refer"); target.setHeaderParameter(SIP_REFERENCES_FIELD, refcallId.data()); Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify " "adding Reference field [%s] to refer-to", mInstanceName.data(), callId.data() ); request.setReferToField(target.toString().data()); } } } else { Os::Logger::instance().log(FAC_AUTH, PRI_WARNING, "TransferControl[%s]::authorizeAndModify " "unrecognized refer target '%s' for call '%s'", mInstanceName.data(), targetStr.data(), callId.data() ); } } else { // REFER without a Refer-To header... incorrect, but just ignore it. Os::Logger::instance().log(FAC_AUTH, PRI_WARNING, "TransferControl[%s]::authorizeAndModify " "REFER method without Refer-To in call '%s'", mInstanceName.data(), callId.data() ); } } else if (method.compareTo(SIP_INVITE_METHOD) == 0) { UtlString targetCallId; UtlString targetFromTag; UtlString targetToTag; if (request.getReplacesData(targetCallId, targetToTag, targetFromTag)) { /* * This is an INVITE with Replaces: probably either the completion * of a call pickup or a consultative transfer. * In any case, it will not create a new call - just connect something * to an existing call - so we don't need to make any new authorization * decisions. */ result = ALLOW; } else { // INVITE without Replaces: is not a transfer - ignore it. } } else { // neither REFER nor INVITE, so is not a transfer - ignore it. } } else { // Some earlier plugin already denied this - don't waste time figuring it out. Os::Logger::instance().log(FAC_AUTH, PRI_DEBUG, "TransferControl[%s]::authorizeAndModify " "prior authorization result %s for call %s", mInstanceName.data(), AuthResultStr(priorResult), callId.data() ); } return result; }
UtlBoolean SipPersistentSubscriptionMgr::updateDialogInfo( const SipMessage& subscribeRequest, UtlString& resourceId, UtlString& eventTypeKey, UtlString& eventType, UtlString& subscribeDialogHandle, UtlBoolean& isNew, UtlBoolean& isSubscriptionExpired, SipMessage& subscribeResponse, SipSubscribeServerEventHandler& handler) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr::updateDialogInfo " "resourceId = '%s', eventTypeKey = '%s'", resourceId.data(), eventTypeKey.data()); UtlBoolean ret; // Call SipSubscriptionMgr to update the in-memory data. ret = SipSubscriptionMgr::updateDialogInfo(subscribeRequest, resourceId, eventTypeKey, eventType, subscribeDialogHandle, isNew, isSubscriptionExpired, subscribeResponse, handler); // If that succeeded, update the IMDB. if (ret) { UtlString requestUri; UtlString callId; UtlString contactEntry; UtlString to; UtlString from; UtlString route; UtlString accept; subscribeRequest.getRequestUri(&requestUri); subscribeRequest.getCallIdField(&callId); subscribeRequest.getContactEntry(0, &contactEntry); subscribeRequest.getToField(&to); subscribeRequest.getFromField(&from); subscribeRequest.buildRouteField(&route); accept.append(subscribeRequest.getHeaderValue(0, SIP_ACCEPT_FIELD)); int expires = 0; subscribeResponse.getExpiresField(&expires); expires += OsDateTime::getSecsSinceEpoch(); int subscribeCseq; UtlString subscribeCseqMethod; subscribeRequest.getCSeqField(&subscribeCseq, &subscribeCseqMethod); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr::updateDialogInfo " "mComponent = '%s', requestUri = '%s', callId = '%s', contactEntry = '%s', expires = %d, to = '%s', from = '%s', key = '%s', route = '%s', accept = '%s'", mComponent.data(), requestUri.data(), callId.data(), contactEntry.data(), expires, to.data(), from.data(), resourceId.data(), route.data(), accept.data()); // Attempt to update an existing row. int now = (int)OsDateTime::getSecsSinceEpoch(); ret = mSubscriptionDBInstance->updateSubscribeUnexpiredSubscription( mComponent, to, from, callId, eventTypeKey, "", now, expires, subscribeCseq); if (!ret) { // Add a new row. // This call assumes that eventTypeKey is OK for use as the <eventtype>, // and that the NOTIFY CSeq's will start at 1. 0 is used as // the initial XML version. ret = mSubscriptionDBInstance->insertRow( mComponent, requestUri, callId, contactEntry, expires, subscribeCseq, eventTypeKey, "", to, from, resourceId, route, 1, accept, 0); if (!ret) { OsSysLog::add(FAC_SIP, PRI_ERR, "SipPersistantSubscriptionMgr::addSubscription " "Could not update or insert record in database"); } } // Start the save timer. mPersistenceTimer.oneshotAfter(sPersistInterval); } return ret; }
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage) { int msgType = eventMessage.getMsgType(); switch (msgType) { case OsMsg::OS_EVENT: switch (eventMessage.getMsgSubType()) { case OsEventMsg::NOTIFY: if (mpWriter) { mpWriter->flush(); } break; } break ; case OsMsg::PHONE_APP: { SipMessage* sipMsg; if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus()) { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver::handleMessage transport error"); } else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage())) { UtlString method; int rspStatus = 0; UtlString rspText; UtlString contact; UtlString toTag; enum { UnInteresting, aCallRequest, aCallSetup, aCallFailure, aCallEnd, aCallTransfer } thisMsgIs = UnInteresting; Url toUrl; sipMsg->getToUrl(toUrl); // explicitly, an INVITE Request toUrl.getFieldParameter("tag", toTag); if (!sipMsg->isResponse()) { // sipMsg is a Request sipMsg->getRequestMethod(&method); if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase)) { if (toTag.isNull()) { thisMsgIs = aCallRequest; } } else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase)) { thisMsgIs = aCallTransfer; sipMsg->getContactEntry(0, &contact); } else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase)) { thisMsgIs = aCallEnd; // no additional information needed } else { // other request methods are not interesting } } else // this is a response { int seq; if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field { if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase)) { // Responses to INVITES are handled differently based on whether // or not the INVITE is dialog-forming. If dialog-forming, // any final response above 400 is considered a failure for CDR // purposes. If not dialog-forming, then any final response above 400 // except 401 Unauthorized, 407 Proxy Authentication Required and // 408 Request Timeout will terminate. If we're in a dialog then // only 408 (Request Timeout) and 481 (Call/Transaction does not exist) // will terminate the dialog. rspStatus = sipMsg->getResponseStatusCode(); if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure { // a failure code - this is a potential CallFailure - Call Resolver will determine. thisMsgIs = aCallFailure; sipMsg->getResponseStatusText(&rspText); } else if ( ( rspStatus >= SIP_2XX_CLASS_CODE ) && ( rspStatus < SIP_3XX_CLASS_CODE ) ) { thisMsgIs = aCallSetup; sipMsg->getContactEntry(0, &contact); } } else { // responses to non-INVITES are not interesting } } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response"); } } # ifdef LOG_DEBUG OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s", ( thisMsgIs == UnInteresting ? "UnInteresting" : thisMsgIs == aCallEnd ? "a Call End" : thisMsgIs == aCallFailure ? "a Call Failure" : thisMsgIs == aCallRequest ? "a call Request" : thisMsgIs == aCallSetup ? "a Call Setup" : thisMsgIs == aCallTransfer ? "a Call Transfer" : "BROKEN" )); # endif if (thisMsgIs != UnInteresting) { // collect the sequence data mSequenceNumber++; OsTime timeNow; OsDateTime::getCurTime(timeNow); // collect the dialog information UtlString callId; sipMsg->getCallIdField(&callId); Url toUrl; sipMsg->getToUrl(toUrl); UtlString toTag; toUrl.getFieldParameter("tag", toTag); Url fromUrl; sipMsg->getFromUrl(fromUrl); UtlString fromTag; fromUrl.getFieldParameter("tag", fromTag); // collect the To and From UtlString toField; sipMsg->getToField(&toField); UtlString fromField; sipMsg->getFromField(&fromField); UtlString referTo; UtlString referredBy; UtlString requestUri; sipMsg->getReferToField(referTo); sipMsg->getReferredByField(referredBy); sipMsg->getRequestUri(&requestUri); UtlString responseMethod; int cseqNumber; sipMsg->getCSeqField(&cseqNumber, &responseMethod); // generate the call state event record if (mpBuilder) { switch (thisMsgIs) { case aCallRequest: mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact); break; case aCallSetup: mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact); break; case aCallFailure: mpBuilder->callFailureEvent(mSequenceNumber, timeNow, rspStatus, rspText); break; case aCallEnd: mpBuilder->callEndEvent(mSequenceNumber, timeNow); break; case aCallTransfer: mpBuilder->callTransferEvent(mSequenceNumber, timeNow, contact, referTo, referredBy, requestUri); break; default: // shouldn't be possible to get here OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs"); break; } mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField); UtlString via; for (int i=0; sipMsg->getViaField(&via, i); i++) { mpBuilder->addEventVia(via); } mpBuilder->completeCallEvent(); // get the completed record UtlString event; mpBuilder->finishElement(event); if (mpWriter) { mpWriter->writeLog(event.data()); } } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!"); } } } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL"); } } break; default: { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType ); } } // end switch (msgType) return(TRUE); }
UtlBoolean SipXProxyCseObserver::handleMessage(OsMsg& eventMessage) { int msgType = eventMessage.getMsgType(); switch (msgType) { case OsMsg::OS_EVENT: switch (eventMessage.getMsgSubType()) { case OsEventMsg::NOTIFY: if (mpWriter) { mpWriter->flush(); } break; } break ; case OsMsg::PHONE_APP: { SipMessage* sipMsg; if(SipMessageEvent::TRANSPORT_ERROR == ((SipMessageEvent&)eventMessage).getMessageStatus()) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver::handleMessage transport error"); } else if((sipMsg = (SipMessage*)((SipMessageEvent&)eventMessage).getMessage())) { UtlString method; int rspStatus = 0; UtlString rspText; UtlString contact; UtlString toTag; enum { UnInteresting, aCallRequest, aCallSetup, aCallFailure, aCallEnd, aCallTransfer } thisMsgIs = UnInteresting; Url toUrl; sipMsg->getToUrl(toUrl); // explicitly, an INVITE Request toUrl.getFieldParameter("tag", toTag); if (!sipMsg->isResponse()) { // sipMsg is a Request sipMsg->getRequestMethod(&method); if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase)) { if (toTag.isNull()) { sipMsg->getContactEntry(0, &contact); thisMsgIs = aCallRequest; } } else if (0==method.compareTo(SIP_REFER_METHOD, UtlString::ignoreCase)) { thisMsgIs = aCallTransfer; sipMsg->getContactEntry(0, &contact); } else if (0==method.compareTo(SIP_BYE_METHOD, UtlString::ignoreCase)) { thisMsgIs = aCallEnd; // no additional information needed } else { // other request methods are not interesting } } else // this is a response { int seq; if (sipMsg->getCSeqField(&seq, &method)) // get the method out of cseq field { if (0==method.compareTo(SIP_INVITE_METHOD, UtlString::ignoreCase)) { // Responses to INVITES are handled differently based on whether // or not the INVITE is dialog-forming. If dialog-forming, // any final response above 400 is considered a failure for CDR // purposes. If not dialog-forming, then any final response above 400 // except 401 Unauthorized, 407 Proxy Authentication Required and // 408 Request Timeout will terminate. If we're in a dialog then // only 408 (Request Timeout) and 481 (Call/Transaction does not exist) // will terminate the dialog. rspStatus = sipMsg->getResponseStatusCode(); if (rspStatus >= SIP_4XX_CLASS_CODE) // any failure { // a failure code - this is a potential CallFailure - Call Resolver will determine. thisMsgIs = aCallFailure; sipMsg->getResponseStatusText(&rspText); } else if ( ( rspStatus >= SIP_2XX_CLASS_CODE ) && ( rspStatus < SIP_3XX_CLASS_CODE ) ) { thisMsgIs = aCallSetup; sipMsg->getContactEntry(0, &contact); } } else { // responses to non-INVITES are not interesting } } else { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no Cseq in response"); } } # ifdef LOG_DEBUG Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipXProxyCseObserver message is %s", ( thisMsgIs == UnInteresting ? "UnInteresting" : thisMsgIs == aCallEnd ? "a Call End" : thisMsgIs == aCallFailure ? "a Call Failure" : thisMsgIs == aCallRequest ? "a call Request" : thisMsgIs == aCallSetup ? "a Call Setup" : thisMsgIs == aCallTransfer ? "a Call Transfer" : "BROKEN" )); # endif if (thisMsgIs != UnInteresting) { // collect the sequence data mSequenceNumber++; OsTime timeNow; OsDateTime::getCurTime(timeNow); // collect the dialog information UtlString callId; sipMsg->getCallIdField(&callId); Url toUrl; sipMsg->getToUrl(toUrl); UtlString toTag; toUrl.getFieldParameter("tag", toTag); Url fromUrl; sipMsg->getFromUrl(fromUrl); UtlString fromTag; fromUrl.getFieldParameter("tag", fromTag); // collect the To and From UtlString toField; sipMsg->getToField(&toField); UtlString fromField; sipMsg->getFromField(&fromField); // collect the branch Id (i.e. transaction id) and via count. UtlString viaValue; int viaCount; UtlString branchId; viaCount = sipMsg->getCountHeaderFields(SIP_VIA_FIELD); viaCount = viaCount + sipMsg->getCountHeaderFields(SIP_SHORT_VIA_FIELD); if ( sipMsg->getViaFieldSubField( &viaValue, 0 ) ) { sipMsg->getViaTag( viaValue, "branch", branchId ); } UtlString referTo; UtlString referredBy; UtlString requestUri; UtlString references; UtlString replaces_callId; UtlString replaces_toTag; UtlString replaces_fromTag; UtlString matchingIdentityHeader; SipXauthIdentity sipxIdentity(*sipMsg, matchingIdentityHeader, true,SipXauthIdentity::allowUnbound); sipMsg->getReferToField(referTo); sipMsg->getReferredByField(referredBy); sipMsg->getRequestUri(&requestUri); sipMsg->getReferencesField(&references); if (sipMsg->getReplacesData(replaces_callId, replaces_toTag, replaces_fromTag)) { if (references.length() != 0) { references.append(","); } references.append(replaces_callId); references.append(";rel=xfer"); } UtlString responseMethod; UtlString calleeRoute; int cseqNumber; sipMsg->getCSeqField(&cseqNumber, &responseMethod); BranchTimePair* callIdBranchIdTime; // generate the call state event record if (mpBuilder) { UtlString identity; UtlString recordRoute; bool routeFound = false; bool paiPresent = false; switch (thisMsgIs) { case aCallRequest: if (sipxIdentity.getIdentity(identity)) { paiPresent = true; } if ( branchId && branchId.data() ) { mCallTransMutex.acquire(); unsigned long currentTime = OsDateTime::getSecsSinceEpoch(); UtlString* keyCallId = new UtlString(callId); BranchTimePair* valBranchTimePair = new BranchTimePair(branchId.data(), ¤tTime, &paiPresent); if (NULL == mCallTransMap.insertKeyAndValue(keyCallId, valBranchTimePair) ) { // Unable to add callId to map so it must already be present. delete keyCallId; delete valBranchTimePair; // Check if the paiPresent value is set to true or not. // If not set and we now have a PAI for this call, set it and generate another call request state event // with this info. Otherwise skip over. if ( paiPresent ) { callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId); if ( callIdBranchIdTime && (*callIdBranchIdTime->getPaiPresent() == false) ) { // need to generate another call request event in order to state originator is internal. callIdBranchIdTime->setPaiPresent(&paiPresent); } else { mCallTransMutex.release(); return(TRUE); } } else { mCallTransMutex.release(); return(TRUE); } } mCallTransMutex.release(); } mpBuilder->callRequestEvent(mSequenceNumber, timeNow, contact, references, branchId, viaCount, paiPresent); break; case aCallSetup: // Clear out from the map only if rspStatus is higher than 200 as its possible to receive multiple 200 messages. // If the response is 200, the call in the map will be cleared out when the call ends. mCallTransMutex.acquire(); callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId); if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) { if ( rspStatus > SIP_2XX_CLASS_CODE ) { mCallTransMap.destroy(&callId); } mCallTransMutex.release(); } else { // CallId/BranchId are either not found or doesn't match. Not a final response. mCallTransMutex.release(); return(TRUE); } for (int rrNum = 0; (!routeFound && sipMsg->getRecordRouteUri(rrNum, &recordRoute)); rrNum++ ) { Url recordRouteUrl(recordRoute); if (mpSipUserAgent->isMyHostAlias(recordRouteUrl)) { // This is a record route for our proxy, extract Call tags if they exist. recordRouteUrl.getUrlParameter(SIP_SIPX_CALL_DEST_FIELD, calleeRoute, 0); routeFound = true; } } mpBuilder->callSetupEvent(mSequenceNumber, timeNow, contact, calleeRoute, branchId, viaCount); break; case aCallFailure: // Failure case means that the response code is > 400. If the call is found // in the map, then this is a final response. Delete from the map and build an event. mCallTransMutex.acquire(); callIdBranchIdTime = (BranchTimePair*) mCallTransMap.findValue(&callId); if ( callIdBranchIdTime && (0 == branchId.compareTo(callIdBranchIdTime)) ) { mCallTransMap.destroy(&callId); mCallTransMutex.release(); if ( rspStatus != SIP_PROXY_AUTH_REQ_CODE ) { mpBuilder->callFailureEvent(mSequenceNumber, timeNow, branchId, viaCount, rspStatus, rspText); } else { // response was an authentication required. Don't build a CSE for these as a new Invite will // occur. return(TRUE); } } else { // Call was not found in the map so this is not a final response. Ignore it. mCallTransMutex.release(); return(TRUE); } break; case aCallEnd: mCallTransMutex.acquire(); mCallTransMap.destroy(&callId); mCallTransMutex.release(); mpBuilder->callEndEvent(mSequenceNumber, timeNow); break; case aCallTransfer: mpBuilder->callTransferEvent(mSequenceNumber, timeNow, contact, referTo, referredBy, requestUri); break; default: // shouldn't be possible to get here Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid thisMsgIs"); break; } mpBuilder->addCallData(cseqNumber, callId, fromTag, toTag, fromField, toField); UtlString via; for (int i=0; sipMsg->getViaField(&via, i); i++) { mpBuilder->addEventVia(via); } mpBuilder->completeCallEvent(); // get the completed record UtlString event; mpBuilder->finishElement(event); if (mpWriter) { mpWriter->writeLog(event.data()); } } else { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver - no CallStateEventBuilder!"); } } } else { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver getMessage returned NULL"); } } break; default: { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver invalid message type %d", msgType ); } } // end switch (msgType) return(TRUE); }