void SipImpliedSubscriptions::buildSubscribeRequest( const SipMessage& registerMessage ,int duration ,SipMessage& subscribeRequest ,UtlString& callId ,UtlString& fromTag ,UtlString& fromUri ) { UtlString registrationValue; UtlString tagNameValuePair; UtlString contactUri; int sequenceNumber = 0; // Get the From URL, and change the tag Url fromUrl; registerMessage.getFromUrl( fromUrl ); fromUrl.removeFieldParameter("tag"); // discard from tag from REGISTER registerMessage.getFromUri( &fromUri ); (void) registerMessage.getContactUri(0, &contactUri); (void) registerMessage.getCSeqField(&sequenceNumber, ®istrationValue); Url toUrl; registerMessage.getToUrl( toUrl ); toUrl.removeFieldParameter("tag"); UtlString toUri; registerMessage.getToUri( &toUri ); registerMessage.getCallIdField( &callId ); callId.prepend("implied-mwi-"); // Build a from tag for the SUBSCRIBE // - hash the call id so that it will be the same on each refresh UtlString callIdHash; NetMd5Codec::encode( callId.data(), callIdHash ); fromUrl.setFieldParameter("tag", callIdHash.data() ); fromTag = callIdHash; // for constructing the nonce subscribeRequest.setVoicemailData( fromUrl.toString() // From: ,toUrl.toString() // To: ,toUri.data() // request URI ,contactUri.data() // taken from registration ,callId.data() ,++sequenceNumber ,duration ); /* * Rewrite the event field to add our extension parameter to * ensure that the registration and subscription are synchronized. */ const char* standardEventHeader = subscribeRequest.getHeaderValue(0, SIP_EVENT_FIELD); UtlString extendedEventHeader(standardEventHeader); extendedEventHeader.append(";" SIPX_IMPLIED_SUB "="); char durationString[12]; sprintf(durationString, "%d", duration); extendedEventHeader.append(durationString); subscribeRequest.setHeaderValue(SIP_EVENT_FIELD, extendedEventHeader.data(), 0); }
/// wrapper function for all reg-info event tests bool ContactSetTest(UtlString regContactxml, UtlString requestUri, UtlString route) { bool ret = FALSE; instantiateAllTestFixtures( "resource-lists2.xml", "subscription1", "credential1", "sip:127.0.0.1:45141", FALSE); // receive the reg-info subscribe SipMessage request; while(getNextMessageFromRlsClientUnderTest( request, 5 ) ) { UtlString method; request.getRequestMethod(&method); if(!request.isResponse() && 0 == method.compareTo(SIP_SUBSCRIBE_METHOD) ) { // Accept the Subscription, regardless of whether it for a 'dialog' or 'reg' event // in order to stop retransmissions SipMessage regResponse; regResponse.setResponseData(&request, 202, "Accepted", "sip:127.0.0.1:45141"); SipMessage * dispatchedMessage = new SipMessage(regResponse); pResourceServerUnderTest->mClientUserAgent.dispatch(dispatchedMessage); // Deal with the two events separately UtlString eventField; request.getEventField(eventField); if(0 == eventField.compareTo("reg")) { UtlString contactInfo; request.getContactUri(0, &contactInfo); UtlString callid; request.getCallIdField(&callid); int cseq; request.getCSeqField(&cseq, NULL); Url toField; regResponse.getToUrl(toField); SipMessage regNotify; regNotify.setNotifyData(&request, 1, "", "", "reg"); UtlString regInfo ("<?xml version=\"1.0\"?>\r\n" "<reginfo xmlns=\"urn:ietf:params:xml:ns:reginfo\" " "xmlns:gr=\"urn:ietf:params:xml:ns:gruuinfo\" version=\"911\" state=\"full\">\r\n" " <registration aor=\"sip:[email protected]\" id=\"sip:[email protected]\" state=\"active\">\r\n " " <contact id=\"sip:[email protected]@@<"); regInfo.append(contactInfo); regInfo.append(">\" state=\"active\" event=\"registered\" q=\"1\" callid=\""); regInfo.append(callid); regInfo.append("\" cseq=\""); regInfo.appendNumber(cseq); regInfo.append("\">\r\n"); regInfo.append(regContactxml); regInfo.append(" </contact>\r\n" " </registration>\r\n" "</reginfo>"); HttpBody * newBody = new HttpBody (regInfo, strlen(regInfo), "application/reginfo+xml"); regNotify.setContentType("application/reginfo+xml"); regNotify.setBody(newBody); // Set the From field the same as the to field from the 202 response, as it // contains the dialog identifying to tags regNotify.setRawFromField(toField.toString().data()); sendToRlsServerUnderTest( regNotify ); } else if(0 == eventField.compareTo("dialog")) { // If we find a dialog event subscription with the request uri and route // that we are looking for, mark the test as passed UtlString uri; UtlString myRoute; request.getRequestUri(&uri); request.getRouteField(&myRoute); if(0 == uri.compareTo(requestUri) && 0 == route.compareTo(myRoute)) { ret = true; } } } } return ret; }
void SipDialog::updateDialogData(const SipMessage& message) { UtlString messageCallId; message.getCallIdField(&messageCallId); Url messageFromUrl; message.getFromUrl(messageFromUrl); UtlString messageFromTag; messageFromUrl.getFieldParameter("tag", messageFromTag); Url messageToUrl; message.getToUrl(messageToUrl); UtlString messageToTag; messageToUrl.getFieldParameter("tag", messageToTag); int cSeq; UtlString method; message.getCSeqField(&cSeq, &method); int responseCode = message.getResponseStatusCode(); // Figure out if the request is from the local or // the remote side if(isTransactionLocallyInitiated(messageCallId, messageFromTag, messageToTag)) { // This message is part of a transaction initiated by // the local side of the dialog if(cSeq > mLastLocalCseq) { mLastLocalCseq = cSeq; } if(cSeq >= mLastLocalCseq) { // Always update the contact if it is set UtlString messageContact; // Get the Contact value, but as an addr-spec. if(message.getContactUri(0, &messageContact) && !messageContact.isNull()) { if(message.isResponse()) { mRemoteContact.fromString(messageContact, TRUE); } else { mLocalContact.fromString(messageContact, TRUE); } } } // Cannot assume that we only establish a dialog with the // initial cseq. For example if there is an authentication // challenge, the dialog will not be established until the // second transaction. if(cSeq == mLastLocalCseq) { // A successful response to an INVITE or SUBSCRIBE // make this early dialog a set up dialog if(mLocalInitiatedDialog && message.isResponse() && responseCode >= SIP_2XX_CLASS_CODE && // successful dialog setup responseCode < SIP_3XX_CLASS_CODE && mRemoteTag.isNull() && // tag not set mRouteSet.isNull()) // have not yet set the route set { // Change this early dialog to a set up dialog. // The tag gets set in the 2xx response // so we need to update the URL message.getToUrl(mRemoteField); mRemoteField.getFieldParameter("tag", mRemoteTag); // Need to get the route set as well // Make sure the Request Method is allowed to set Record-Routes if(message.isRecordRouteAccepted()) { message.buildRouteField(&mRouteSet); } } } } else if(isTransactionRemotelyInitiated(messageCallId, messageFromTag, messageToTag)) { int prevRemoteCseq = mLastRemoteCseq; // This message is part of a transaction initiated by // the callee/destination of the session if(cSeq > mLastRemoteCseq) { mLastRemoteCseq = cSeq; } if(cSeq >= mLastRemoteCseq) { // Always update the contact if it is set UtlString messageContact; // Get the Contact value, but as an addr-spec. if(message.getContactUri(0, &messageContact) && !messageContact.isNull()) { if(message.isResponse()) { mLocalContact.fromString(messageContact, TRUE); } else { mRemoteContact.fromString(messageContact, TRUE); } } } // First transaction from the otherside if(cSeq == mLastRemoteCseq && prevRemoteCseq == -1) { // A response (e.g. NOTIFY) can come before we get the // successful response to the initial transaction if(!mLocalInitiatedDialog && !message.isResponse() && mRemoteTag.isNull()) // tag not set { // Change this early dialog to a set up dialog. // The tag gets set in the 2xx response // so we need to update the URL message.getFromUrl(mRemoteField); mRemoteField.getFieldParameter("tag", mRemoteTag); } } // First successful response from the local side if(cSeq == mLastRemoteCseq) { if(!mLocalInitiatedDialog && message.isResponse() && responseCode >= SIP_2XX_CLASS_CODE && // successful dialog setup responseCode < SIP_3XX_CLASS_CODE && mLocalTag.isNull()) { // Update the local tag message.getToUrl(mLocalField); mLocalField.getFieldParameter("tag", mLocalTag); } } } }
void AppearanceTest() { instantiateAllTestFixtures( "appearance-groups1.xml", "subscription1", "credential1", "177.0.0.1:54140"); UtlString sharedUri = "sip:[email protected]:54140"; UtlString app1uri = "sip:127.0.0.1:45141"; UtlString dialogHandle; // receive the reg-info subscribe SipMessage request; UtlString b; ssize_t l; while(getNextMessageFromAppearanceAgentUnderTest( request, 5 )) { request.getBytes(&b, &l); OsSysLog::add(FAC_RLS, PRI_DEBUG, "got message %s", b.data()); UtlString method; request.getRequestMethod(&method); if(!request.isResponse() && 0 == method.compareTo(SIP_SUBSCRIBE_METHOD) ) { // Accept the Subscription, regardless of whether it for a 'dialog' or 'reg' event // in order to stop retransmissions SipMessage regResponse; regResponse.setResponseData(&request, 202, "Accepted", app1uri); SipMessage * dispatchedMessage = new SipMessage(regResponse); dispatchedMessage->getBytes(&b, &l); OsSysLog::add(FAC_RLS, PRI_DEBUG, "sent message %s", b.data()); pAppearanceAgentUnderTest->mServerUserAgent.dispatch(dispatchedMessage); // Deal with the two events separately UtlString eventField; request.getEventField(eventField); if(0 == eventField.compareTo("reg")) { UtlString contactInfo; request.getContactUri(0, &contactInfo); UtlString callid; request.getCallIdField(&callid); int cseq; request.getCSeqField(&cseq, NULL); Url toField; regResponse.getToUrl(toField); SipMessage regNotify; regNotify.setNotifyData(&request, 1, "", "", "reg"); UtlString regInfo ("<?xml version=\"1.0\"?>\r\n" "<reginfo xmlns=\"urn:ietf:params:xml:ns:reginfo\" " "xmlns:gr=\"urn:ietf:params:xml:ns:gruuinfo\" version=\"911\" state=\"full\">\r\n" " <registration aor=\"sip:[email protected]:54140\" id=\"sip:[email protected]:54140\" state=\"active\">\r\n " " <contact id=\"sip:[email protected]:54140@@<"); regInfo.append(contactInfo); regInfo.append(">\" state=\"active\" event=\"registered\" q=\"1\" callid=\""); regInfo.append(callid); regInfo.append("\" cseq=\""); regInfo.appendNumber(cseq); regInfo.append("\">\r\n"); regInfo.append("<uri>"); regInfo.append(app1uri); regInfo.append("</uri>"); regInfo.append(" </contact>\r\n" " </registration>\r\n" "</reginfo>"); HttpBody * newBody = new HttpBody (regInfo, strlen(regInfo), "application/reginfo+xml"); regNotify.setContentType("application/reginfo+xml"); regNotify.setBody(newBody); // Set the From field the same as the to field from the 202 response, as it // contains the dialog identifying to tags regNotify.setRawFromField(toField.toString().data()); sendToAppearanceAgentUnderTest( regNotify ); regNotify.getBytes(&b, &l); OsSysLog::add(FAC_RLS, PRI_DEBUG, "sent reg NOTIFY to AppAgent"); OsSysLog::add(FAC_RLS, PRI_DEBUG, "sent message %s", b.data()); } else if (0 == eventField.compareTo(SLA_EVENT_TYPE)) { // should send empty NOTIFY, but no one will care // save dialogHandle for this subscription/Appearance (ignore retransmissions) if (dialogHandle.isNull()) { SipMessage fake(b); fake.getDialogHandle(dialogHandle); OsSysLog::add(FAC_RLS, PRI_DEBUG, "got SUBSCRIBE(sla) request: dialogHandle %s", dialogHandle.data()); } } } } CPPUNIT_ASSERT( !dialogHandle.isNull() ); OsSysLog::add(FAC_RLS, PRI_DEBUG, "we now have an Appearance - test it"); AppearanceGroup* pAppGroup = pAppearanceAgentUnderTest->getAppearanceGroupSet(). findAppearanceGroup(sharedUri); CPPUNIT_ASSERT( pAppGroup ); Appearance* pApp = pAppGroup->findAppearance(dialogHandle); CPPUNIT_ASSERT( pApp ); ASSERT_STR_EQUAL( app1uri.data(), pApp->getUri()->data() ); // test adding a new dialog const char* dialogEventString = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"0\" state=\"partial\" entity=\"sip:[email protected]:54140\">\n" "<dialog id=\"1\" call-id=\"[email protected]\" local-tag=\"264460498\" remote-tag=\"1c10982\" direction=\"recipient\">\n" "<state>confirmed</state>\n" "<local>\n" "<identity>[email protected]:5120</identity>\n" "<target uri=\"sip:[email protected]:5120\">\n" "<param pname=\"x-line-id\" pval=\"0\"/>\n" "<param pname=\"+sip.rendering\" pval=\"yes\"/>\n" "</target>\n" "</local>\n" "<remote>\n" "<identity>[email protected]</identity>\n" "</remote>\n" "</dialog>\n" "</dialog-info>\n" ; SipDialogEvent dialogEvent(dialogEventString); bool bFullContentChanged = false; bool bPartialContentChanged = pApp->updateState(&dialogEvent, bFullContentChanged); CPPUNIT_ASSERT(bPartialContentChanged); CPPUNIT_ASSERT(bFullContentChanged); pApp->dumpState(); CPPUNIT_ASSERT(pApp->appearanceIsBusy()); CPPUNIT_ASSERT(pApp->appearanceIdIsSeized("0")); CPPUNIT_ASSERT(!pApp->appearanceIdIsSeized("1")); // simulate user putting the call on hold const char* dialogEventString2 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<dialog-info xmlns=\"urn:ietf:params:xml:ns:dialog-info\" version=\"0\" state=\"partial\" entity=\"sip:[email protected]:54140\">\n" "<dialog id=\"1\" call-id=\"[email protected]\" local-tag=\"264460498\" remote-tag=\"1c10982\" direction=\"recipient\">\n" "<state>confirmed</state>\n" "<local>\n" "<identity>[email protected]:5120</identity>\n" "<target uri=\"sip:[email protected]:5120\">\n" "<param pname=\"x-line-id\" pval=\"0\"/>\n" "<param pname=\"+sip.rendering\" pval=\"no\"/>\n" "</target>\n" "</local>\n" "<remote>\n" "<identity>[email protected]</identity>\n" "</remote>\n" "</dialog>\n" "</dialog-info>\n" ; SipDialogEvent dialogEvent2(dialogEventString2); bPartialContentChanged = pApp->updateState(&dialogEvent2, bFullContentChanged); CPPUNIT_ASSERT(bPartialContentChanged); CPPUNIT_ASSERT(bFullContentChanged); pApp->dumpState(); CPPUNIT_ASSERT(!pApp->appearanceIsBusy()); CPPUNIT_ASSERT(pApp->appearanceIdIsSeized("0")); CPPUNIT_ASSERT(!pApp->appearanceIdIsSeized("1")); // test MESSAGE debug handling const char* message = "MESSAGE sip:[email protected]:54140 SIP/2.0\r\n" "From: <sip:[email protected]>;tag=17211757-9E4FBD78\r\n" "To: <sip:[email protected]:54140>\r\n" "CSeq: 1 MESSAGE\r\n" "Call-ID: 51405734-b9be4835-dcd9d196\r\n" "Contact: <sip:[email protected]>\r\n" "Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, INFO, MESSAGE, SUBSCRIBE, NOTIFY, PRACK, UPDATE, REFER\r\n" "Event: dialog\r\n" "User-Agent: UnitTest\r\n" "Accept-Language: en\r\n" "Accept: application/dialog-info+xml\r\n" "Max-Forwards: 70\r\n" "Expires: 3600\r\n" "Content-Length: 0\r\n" "\r\n"; // send the MESSAGE SipMessage messageRequest( message, strlen( message ) ); CPPUNIT_ASSERT( sendToAppearanceAgentUnderTest( messageRequest ) ); // receive the 200 OK response SipMessage response; CPPUNIT_ASSERT( getNextMessageFromAppearanceAgentUnderTest( response, 5 ) ); CPPUNIT_ASSERT( response.isResponse() ); CPPUNIT_ASSERT( response.getResponseStatusCode() == SIP_OK_CODE ); }