// Queue a message to be sent to the specified address and port. UtlBoolean SipClient::sendTo(SipMessage& message, const char* address, int port) { UtlBoolean sendOk; if (mClientSocket) { // If port == PORT_NONE, get the correct default port for this // transport method. int portToSendTo = ( port == PORT_NONE ? defaultPort() : port ); // We are about to post a message that will cause the // SIP message to be sent. Notify the user agent so // that it can offer the message to all its registered // output processors. ssize_t msgLength = 0; UtlString msgText; message.getBytes(&msgText, &msgLength, true); if (msgLength) { system_tap_sip_tx( mLocalHostAddress.data(), portIsValid(mLocalHostPort) ? mLocalHostPort : defaultPort(), address, portToSendTo, msgText.data(), msgLength); mpSipUserAgent->executeAllSipOutputProcessors( message, address, portToSendTo ); } // Create message to queue. SipClientSendMsg sendMsg(OsMsg::OS_EVENT, SipClientSendMsg::SIP_CLIENT_SEND, message, address, portToSendTo ); // Post the message to the task's queue. OsStatus status = postMessage(sendMsg, OsTime::NO_WAIT); sendOk = status == OS_SUCCESS; if (!sendOk) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipClient[%s]::sendTo attempt to post message failed", mName.data()); } } else { Os::Logger::instance().log(FAC_SIP, PRI_CRIT, "SipClient[%s]::sendTo called for client without socket", mName.data() ); sendOk = FALSE; } return sendOk; }
UtlBoolean SipSubscribeServerEventHandler::getNotifyContent(const UtlString& resourceId, const UtlString& eventTypeKey, const UtlString& eventType, SipPublishContentMgr& contentMgr, const char* acceptHeaderValue, SipMessage& notifyRequest, int& version) { UtlBoolean gotBody = FALSE; // Default behavior is to just go get the content from // the content manager and attach it to the notify HttpBody* messageBody = NULL; UtlBoolean isDefaultEventContent; gotBody = contentMgr.getContent(resourceId, eventTypeKey, eventType, acceptHeaderValue, messageBody, version, isDefaultEventContent); // The body will be freed with the NOTIFY message. if(messageBody) { const char* contentTypePtr = messageBody->getContentType(); UtlString contentType; if(contentTypePtr) { contentType = contentTypePtr; } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipSubscribeServerEventHandler::getNotifyContent body published for resourceId: '%s' eventTypeKey: '%s' with no content type", resourceId.data() ? resourceId.data() : "<null>", eventTypeKey.data() ? eventTypeKey.data() : "<null>"); contentType = "text/unknown"; } notifyRequest.setContentType(contentType); notifyRequest.setBody(messageBody); UtlString request; ssize_t requestLength; notifyRequest.getBytes(&request, &requestLength); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSubscribeServerEventHandler::getNotifyContent resourceId '%s', eventTypeKey '%s' contentType '%s' NOTIFY message length = %zu, message = '%s'", resourceId.data(), eventTypeKey.data(), contentType.data(), requestLength, request.data()); } return(gotBody); }
UtlBoolean SipUserAgentStateless::sendTo(SipMessage& message, const char* sendAddress, const char* sendProtocol, int sendPort) { UtlBoolean sendOk = FALSE; if(sendAddress && *sendAddress && mpUdpServer) { if (!portIsValid(sendPort)) { sendPort = SIP_PORT; } sendOk = mpUdpServer->sendTo(message, sendAddress, sendPort); } // Log the message if (isMessageLoggingEnabled()) { UtlString messageStatus; char messageChars[200]; if(sendOk) sprintf(messageChars, "Sent message %s port:%d:\n", sendAddress, sendPort); else sprintf(messageChars, "Failed to send message %s port:%d:\n", sendAddress, sendPort); messageStatus = messageChars; UtlString msgBytes; int msgLen; message.getBytes(&msgBytes, &msgLen); msgBytes.insert(0, messageStatus); msgBytes.append("--------------------END--------------------\n"); logMessage(msgBytes.data(), msgBytes.length()); } return(sendOk); }
//functions UtlBoolean SubscribeServerThread::handleMessage(OsMsg& eventMessage) { // Only handle SIP messages if (eventMessage.getMsgType() != OsMsg::PHONE_APP || eventMessage.getMsgSubType() != SipMessage::NET_SIP_MESSAGE) { return FALSE ; } const SipMessage* message = ((SipMessageEvent&)eventMessage).getMessage(); UtlString userKey; UtlString uri; SipMessage finalResponse; // Test for request/response processing code path if (!message->isResponse()) { // this is a request, so authenticate and authorize the request if ( isValidDomain( message, &finalResponse ) ) { UtlString eventPackage; UtlString id; UtlHashMap otherParams; message->getEventField(&eventPackage, &id, &otherParams); StatusPluginReference* pluginContainer = mPluginTable->getPlugin( eventPackage ); if( pluginContainer ) { //check in credential database if authentication needed UtlString authenticatedUser, authenticatedRealm; if( isAuthenticated ( message, &finalResponse, authenticatedUser, authenticatedRealm ) ) { if ( isAuthorized ( message, &finalResponse, pluginContainer ) ) { // fetch the plugin SubscribeServerPluginBase* plugin = pluginContainer->getPlugin(); if (plugin) { int timeNow = (int)OsDateTime::getSecsSinceEpoch(); int grantedExpiration; UtlString newToTag; // add the subscription to the IMDB SubscribeStatus isSubscriptionAdded = addSubscription(timeNow, message, mDefaultDomain, eventPackage, id, otherParams, newToTag, grantedExpiration); otherParams.destroyAll(); switch ( isSubscriptionAdded ) { case STATUS_SUCCESS: // create response - 202 Accepted Response finalResponse.setResponseData( message, SIP_ACCEPTED_CODE, SIP_ACCEPTED_TEXT); // Set the granted subscription time. finalResponse.setExpiresField(grantedExpiration); plugin->handleSubscribeRequest( *message, finalResponse, authenticatedUser.data(), authenticatedRealm.data(), mDefaultDomain.data()); // ensure that the contact returned will route back to here // (the default supplied by SipUserAgent will not). { UtlString requestUri; message->getRequestUri(&requestUri); finalResponse.setContactField(requestUri); } break; case STATUS_TO_BE_REMOVED: // create response - 202 Accepted Response finalResponse.setResponseData( message, SIP_ACCEPTED_CODE, SIP_ACCEPTED_TEXT); // Set the granted subscription time. finalResponse.setExpiresField(grantedExpiration); plugin->handleSubscribeRequest( *message, finalResponse, authenticatedUser.data(), authenticatedRealm.data(), mDefaultDomain.data()); // ensure that the contact returned will route back to here // (the default supplied by SipUserAgent will not). { UtlString requestUri; message->getRequestUri(&requestUri); finalResponse.setContactField(requestUri); } // Now that final NOTIFY has been sent, remove row removeSubscription(message); break; case STATUS_LESS_THAN_MINEXPIRES: // (already logged in addSubscription) // send 423 Subscription Too Brief response finalResponse.setResponseData( message, SIP_TOO_BRIEF_CODE, SIP_TOO_BRIEF_TEXT ); finalResponse.setHeaderValue( SIP_MIN_EXPIRES_FIELD, mMinExpiresTimeStr, 0 ); break; case STATUS_INVALID_REQUEST: OsSysLog::add(FAC_SIP, PRI_ERR, "SubscribeServerThread::handleMessage()" "Subscription Could Not Be Added " SIP_BAD_REQUEST_TEXT ); finalResponse.setResponseData( message, SIP_BAD_REQUEST_CODE, SIP_BAD_REQUEST_TEXT ); break; case STATUS_FORBIDDEN: OsSysLog::add(FAC_SIP, PRI_ERR, "SubscribeServerThread::handleMessage()" "Subscription Could Not Be Added " SIP_FORBIDDEN_TEXT ); finalResponse.setResponseData( message, SIP_FORBIDDEN_CODE, SIP_FORBIDDEN_TEXT); break; case STATUS_NOT_FOUND: OsSysLog::add(FAC_SIP, PRI_ERR, "SubscribeServerThread::handleMessage()" "Subscription Could Not Be Added " SIP_NOT_FOUND_TEXT ); finalResponse.setResponseData( message, SIP_NOT_FOUND_CODE, SIP_NOT_FOUND_TEXT ); break; case STATUS_BAD_SUBSCRIPTION: // send 481 Subscription Does Not Exist response OsSysLog::add(FAC_SIP, PRI_DEBUG, "SubscribeServerThread::handleMessage()" "Subscription to be renewed does not exist " SIP_BAD_SUBSCRIPTION_TEXT ); finalResponse.setResponseData( message, SIP_BAD_SUBSCRIPTION_CODE, SIP_BAD_SUBSCRIPTION_TEXT ); break; case STATUS_INTERNAL_ERROR: default: OsSysLog::add(FAC_SIP, PRI_ERR, "SubscribeServerThread::handleMessage()" "Subscription Could Not Be Added " "Status %d from addSubscription", isSubscriptionAdded ); finalResponse.setResponseData( message, SIP_SERVER_INTERNAL_ERROR_CODE, "Subscription database error" ); } // Apply the new to-tag, if any, to the response. if (!newToTag.isNull()) { finalResponse.setToFieldTag(newToTag); } } else { OsSysLog::add(FAC_SIP, PRI_CRIT, "SubscribeServerThread::handleMessage()" " container->getPlugin failed for '%s'", eventPackage.data() ); finalResponse.setResponseData( message, SIP_SERVER_INTERNAL_ERROR_CODE, SIP_SERVER_INTERNAL_ERROR_TEXT ); } } else { // not authorized - the response was created in isAuthorized } } else { // not authenticated - the response was created in isAuthenticated } } else // no plugin found for this event type { OsSysLog::add(FAC_SIP, PRI_WARNING, "SubscribeServerThread::handleMessage()" " Request denied - " SIP_BAD_EVENT_TEXT ); finalResponse.setResponseData( message, SIP_BAD_EVENT_CODE, "Event type not supported" ); } // send final response UtlString finalMessageStr; ssize_t finalMessageLen; finalResponse.getBytes(&finalMessageStr, &finalMessageLen); OsSysLog::add(FAC_SIP, PRI_DEBUG, "\n----------------------------------\n" "Sending final response\n%s",finalMessageStr.data()); mpSipUserAgent->setUserAgentHeader( finalResponse ); mpSipUserAgent->send( finalResponse ); } else // Invalid domain { const char* notFoundMsg = SIP_NOT_FOUND_TEXT " Invalid Domain"; finalResponse.setResponseData(message, SIP_NOT_FOUND_CODE, notFoundMsg ); mpSipUserAgent->setUserAgentHeader( finalResponse ); mpSipUserAgent->send( finalResponse ); } } else // response { // The server may send us back a "481" response, if it does we need // to remove the subscription from the SubscriptionDB as the callid // that it corresponds to is stale (probably the phone was rebooted) // In the above case, RFC 3265 says we MUST remove the subscription. // It also says (essentially) that any error that does not imply a retry // SHOULD remove the subscription. We will interpret this to be any // 4xx code _except_ 408 timeout (because that may be a transient error). int responseCode = message->getResponseStatusCode(); if ( responseCode >= SIP_4XX_CLASS_CODE && responseCode != SIP_REQUEST_TIMEOUT_CODE ) { // remove the subscription removeErrorSubscription ( *message ); } } return TRUE; }
UtlBoolean CommandMsgProcessor::handleMessage(OsMsg& eventMessage) { int msgType = eventMessage.getMsgType(); // int msgSubType = eventMessage.getMsgSubType(); if(msgType == OsMsg::PHONE_APP) // && msgSubType == CP_SIP_MESSAGE) { osPrintf("CommandMsgProcessor::handleMessage Got a message\n"); int messageType = ((SipMessageEvent&)eventMessage).getMessageStatus(); const SipMessage* sipMsg = ((SipMessageEvent&)eventMessage).getMessage(); UtlString callId; if(sipMsg) { osPrintf("numRespondToMessages: %d isResponse: %d messageType: %d TransErro: %d\n", numRespondToMessages, sipMsg->isResponse(), messageType, SipMessageEvent::TRANSPORT_ERROR); if((numRespondToMessages == -1 || numRespondToMessages > 0) && !sipMsg->isResponse() && messageType != SipMessageEvent::TRANSPORT_ERROR) { osPrintf("valid message\n"); if(numRespondToMessages > 0) { numRespondToMessages--; } SipMessage response; if(mpResponseMessage) { response = *mpResponseMessage; } response.setResponseData(sipMsg, responseStatusCode, responseStatusText.data()); UtlString address; int port; UtlString protocol; UtlString tag; sipMsg->getToAddress(&address, &port, &protocol, NULL, NULL, &tag) ; if( tag.isNull()) { int tagNum = rand(); char tag[100]; sprintf(tag, "%d", tagNum); UtlString tagWithDot(tag); tagWithDot.append(".34756498567498567"); response.setToFieldTag(tagWithDot); } UtlString msgBytes; int msgLen; response.getBytes(&msgBytes, &msgLen); osPrintf("%s",msgBytes.data()); if(mpLastResponseMessage) { delete mpLastResponseMessage; mpLastResponseMessage = NULL; } // Keep a copy of the last response sent mpLastResponseMessage = new SipMessage(response); if(userAgent->send(response)) { osPrintf("Sent response\n"); } else { osPrintf("Send failed\n"); } } } } return(TRUE); }
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 ); }
// Constructor SipPersistentSubscriptionMgr::SipPersistentSubscriptionMgr( const UtlString& component, const UtlString& domain, const UtlString& fileName) : mComponent(component), mDomain(domain), mSubscriptionDBInstance(SubscriptionDB::getInstance(fileName)), mPersistenceTimer(mPersistTask.getMessageQueue(), 0), mPersistTask(mSubscriptionDBInstance) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr:: " "mComponent = '%s', mDomain = '%s', fileName = '%s'", mComponent.data(), mDomain.data(), fileName.data()); // Start the persist task. mPersistTask.start(); // Read the subscription table and initialize the SipSubscriptionMgr. unsigned long now = OsDateTime::getSecsSinceEpoch(); ResultSet rs; mSubscriptionDBInstance->getAllRows(rs); UtlSListIterator itor(rs); UtlHashMap* rowp; while ((rowp = dynamic_cast <UtlHashMap*> (itor()))) { if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG)) { UtlString out; UtlHashMapIterator itor(*rowp); UtlString* key; UtlContainable* value; while ((key = dynamic_cast <UtlString*> (itor()))) { value = itor.value(); if (!out.isNull()) { out.append(", "); } out.append(*key); out.append(" = "); if (value->getContainableType() == UtlString::TYPE) { out.append("'"); out.append(*(dynamic_cast <UtlString*> (value))); out.append("'"); } else if (value->getContainableType() == UtlInt::TYPE) { out.appendNumber((int) (*(dynamic_cast <UtlInt*> (value)))); } else { out.append(value->getContainableType()); } } OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr:: " "table row: %s", out.data()); } // First, filter for rows that have the right component and have // not yet expired. UtlString* componentp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gComponentKey)); assert(componentp); int expires = *(dynamic_cast <UtlInt*> (rowp->findValue(&SubscriptionDB::gExpiresKey))); if (componentp->compareTo(mComponent) == 0 && expires - now >= 0) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr:: " "loading row"); // Extract the values from the row. const UtlString* top = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gToKey)); const UtlString* fromp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gFromKey)); const UtlString* callidp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gCallidKey)); const UtlString* eventtypep = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gEventtypeKey)); const UtlString* eventidp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gIdKey)); // Correct the null string if it is returned as // SPECIAL_IMDB_NULL_VALUE. if (eventidp->compareTo(special_imdb_null_value) == 0) { eventidp = &null_string; } int subcseq = *(dynamic_cast <UtlInt*> (rowp->findValue(&SubscriptionDB::gSubscribecseqKey))); const UtlString* urip = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gUriKey)); const UtlString* contactp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gContactKey)); const UtlString* routep = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gRecordrouteKey)); // Correct the null string if it is returned as // SPECIAL_IMDB_NULL_VALUE. if (routep->compareTo(special_imdb_null_value) == 0) { routep = &null_string; } int notifycseq = *(dynamic_cast <UtlInt*> (rowp->findValue(&SubscriptionDB::gNotifycseqKey))); const UtlString* acceptp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gAcceptKey)); int version = *(dynamic_cast <UtlInt*> (rowp->findValue(&SubscriptionDB::gVersionKey))); const UtlString* keyp = dynamic_cast <UtlString*> (rowp->findValue(&SubscriptionDB::gKeyKey)); // Use SipSubscriptionMgr to update the in-memory data. // Construct a fake SUBSCRIBE request to carry most of the data // that updateDialogInfo needs. SipMessage subscribeRequest; OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr:: expires = %d, now = %d", (int) expires, (int) now); subscribeRequest.setSubscribeData(urip->data(), fromp->data(), top->data(), callidp->data(), subcseq, eventtypep->data(), acceptp->data(), eventidp->data(), contactp->data(), NULL, expires - now); // Install the saved Route as a set of Record-Route headers in the // SUBSCRIBE, so that insertDialogInfo will find and record the route. Url route_url; UtlString route_url_string; UtlString route_string(*routep); UtlString remainder_string; int route_index; for (route_index = 0; !route_string.isNull() && route_url.fromString(route_string, Url::NameAddr, &remainder_string); route_string = remainder_string, route_index++) { route_url.toString(route_url_string); subscribeRequest.setRecordRouteField(route_url_string.data(), route_index); } if (OsSysLog::willLog(FAC_SIP, PRI_DEBUG)) { UtlString m, d; ssize_t l; subscribeRequest.getBytes(&m, &l, FALSE); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipPersistentSubscriptionMgr:: subscribeRequest = '%s'", m.data()); } // Variables to hold the output of insertDialogInfo. UtlString subscribeDialogHandle; UtlBoolean isNew; UtlBoolean ret = SipSubscriptionMgr::insertDialogInfo(subscribeRequest, // *keyp is the resource that // is subscribed to. *keyp, *eventtypep, expires, notifycseq, version, subscribeDialogHandle, isNew); if (!ret) { OsSysLog::add(FAC_SIP, PRI_ERR, "SipPersistentSubscriptionMgr:: " "SipSubscriptionMgr::insertDialogInfo failed keyp = '%s', eventtypep = '%s', subscribeDialogHandle = '%s'", keyp->data(), eventtypep->data(), subscribeDialogHandle.data()); } else { // Set the next NOTIFY CSeq value. // (The data in IMDB has already been set.) SipSubscriptionMgr::setNextNotifyCSeq(subscribeDialogHandle, notifycseq, version); } } } }
/// Write as much of the buffered messages as can be written. // Executed by the thread. void SipClientWriteBuffer::writeMore() { // 'exit_loop' will be set to TRUE if an attempt to write does // not write any bytes, and we will then return. UtlBoolean exit_loop = FALSE; while (mWriteQueued && !exit_loop) { if (mWritePointer >= mWriteString.length()) { // We have written all of the first message. // Pop it and set up to write the next message. delete mWriteBuffer.get(); mWriteString.remove(0); mWritePointer = 0; mWriteQueued = ! mWriteBuffer.isEmpty(); if (mWriteQueued) { // get the message on the head of the queue, and figure out which kind it is UtlContainable* nextMsg = mWriteBuffer.first(); SipMessage* sipMsg; UtlString* keepAliveMsg; if ((sipMsg = dynamic_cast<SipMessage*>(nextMsg))) // a SIP message { ssize_t length; sipMsg->getBytes(&mWriteString, &length); } else if ((keepAliveMsg = dynamic_cast<UtlString*>(nextMsg))) // a keepalive CRLF { mWriteString.append(*keepAliveMsg); } else { Os::Logger::instance().log(FAC_SIP, PRI_CRIT, "SipClientWriteBuffer[%s]::writeMore " "unrecognized message type in queue", mName.data()); assert(false); delete mWriteBuffer.get(); mWriteQueued = mWriteBuffer.isEmpty(); } } } else { // Some portion of the first message remains to be written. // If the socket has failed, attempt to reconnect it. // :NOTE: OsConnectionSocket::reconnect isn't implemented. if (!mClientSocket->isOk()) { mClientSocket->reconnect(); } // Calculate the length to write. int length = mWriteString.length() - mWritePointer; // ret is the value returned from write attempt. // -1 means an error was seen. int ret; if (mClientSocket->isOk()) { // Write what we can. ret = mClientSocket->write(mWriteString.data() + mWritePointer, length); // Theoretically, ret > 0, since the socket is ready for writing, // but it appears that that ret can be 0. } else { // Record the error. ret = -1; // Set a special errno value, which hopefully is not a real value. errno = 1000; } if (ret > 0) { // We successfully sent some data, perhaps all of the // remainder of the first message. // Update the last-activity time. touch(); // Update the state variables. mWritePointer += ret; } else if (ret == 0) { // No data sent, even though (in our caller) poll() // reported the socket was ready to write. exit_loop = TRUE; } else { // Error while writing. Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipClientWriteBuffer[%s]::writeMore " "OsSocket::write() returned %d, errno = %d", getName().data(), ret, errno); // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); // Because TCP is a connection protocol, we know that we cannot // send successfully any more and so should shut down this client. clientStopSelf(); // Exit the loop so handleMessage() can process the stop request. exit_loop = TRUE; } } } }