UtlBoolean SipSubscribeServer::enableEventType(const char* eventTypeToken, SipUserAgent* userAgent, SipPublishContentMgr* contentMgr, SipSubscribeServerEventHandler* eventHandler, SipSubscriptionMgr* subscriptionMgr) { UtlBoolean addedEvent = FALSE; UtlString eventName(eventTypeToken ? eventTypeToken : ""); lockForWrite(); // Only add the event support if it does not already exist; SubscribeServerEventData* eventData = (SubscribeServerEventData*) mEventDefinitions.find(&eventName); if(!eventData) { addedEvent = TRUE; eventData = new SubscribeServerEventData(); *((UtlString*)eventData) = eventName; eventData->mpEventSpecificUserAgent = userAgent ? userAgent : mpDefaultUserAgent; eventData->mpEventSpecificContentMgr = contentMgr ? contentMgr : mpDefaultContentMgr; eventData->mpEventSpecificHandler = eventHandler ? eventHandler : mpDefaultEventHandler; eventData->mpEventSpecificSubscriptionMgr = subscriptionMgr ? subscriptionMgr : mpDefaultSubscriptionMgr; mEventDefinitions.insert(eventData); // Register an interest in SUBSCRIBE requests and NOTIFY responses // for this event type eventData->mpEventSpecificUserAgent->addMessageObserver(*(getMessageQueue()), SIP_SUBSCRIBE_METHOD, TRUE, // requests FALSE, // not reponses TRUE, // incoming FALSE, // no outgoing eventName, NULL, NULL); eventData->mpEventSpecificUserAgent->addMessageObserver(*(getMessageQueue()), SIP_NOTIFY_METHOD, FALSE, // no requests TRUE, // reponses TRUE, // incoming FALSE, // no outgoing eventName, NULL, NULL); // Register the callback for changes that occur in the // publish content manager eventData->mpEventSpecificContentMgr->setContentChangeObserver(eventName, this, contentChangeCallback); } unlockForWrite(); return(addedEvent); }
// Adds a buffer to the playlist OsStatus MpStreamPlaylistPlayer::add(UtlString* pBuffer, int flags) { PlayListEntry* e = new PlayListEntry(); int index = mPlayListDb->entries(); e->sourceType = SourceBuffer; e->pBuffer = pBuffer; e->flags = flags; e->pQueuedEvent = new OsQueuedEvent(*getMessageQueue(), (void*)index); e->index = index ; mPlayListDb->append(e); return OS_SUCCESS; }
void SipRedirectServer::resumeRequest(RedirectPlugin::RequestSeqNo requestSeqNo, int redirectorNo) { // Create the appropriate message. RedirectResumeMsg message = RedirectResumeMsg(requestSeqNo, redirectorNo); // Send the message to the redirect server. // Note that send() copies its argument. getMessageQueue()->send(message); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipRedirectServer::resumeRequest " "Redirector %d sent message to resume request %d", redirectorNo, requestSeqNo); }
// Constructor SipPimClient::SipPimClient(SipUserAgent& userAgent, Url& presentityAor) { presentityAor.toString(mFromField); mPresentityAor = presentityAor; mpUserAgent = &userAgent; // Register to get incoming MESSAGE requests OsMsgQ* myQueue = getMessageQueue(); userAgent.addMessageObserver(*myQueue, SIP_MESSAGE_METHOD, TRUE, // requests FALSE, // responces TRUE, // incoming FALSE); // outgoing }
/// Constructor RegistrarPersist::RegistrarPersist(SipRegistrar& sipRegistrar) : OsServerTask("RegistrarPersist"), mLock(OsBSem::Q_PRIORITY, OsBSem::FULL), mIsTimerRunning(false), mPersistTimer(getMessageQueue(), 0), mRegistrar(sipRegistrar), mPersistInterval(-1) { // Get the persist interval. This configuration parameter is provided mainly for // testing and debugging. Usually it is not set explicitly in the configuration file. mRegistrar.getConfigDB()->get("SIP_REGISTRAR_PERSIST_INTERVAL", mPersistInterval); if (mPersistInterval == -1) { mPersistInterval = SIP_REGISTRAR_DEFAULT_PERSIST_INTERVAL; } OsSysLog::add(FAC_SIP, PRI_DEBUG, "RegistrarPersist::RegistrarPersist " "persist interval = %d seconds", mPersistInterval); };
UtlBoolean SipSubscribeServer::disableEventType(const char* eventTypeToken, SipUserAgent*& userAgent, SipPublishContentMgr*& contentMgr, SipSubscribeServerEventHandler*& eventHandler, SipSubscriptionMgr*& subscriptionMgr) { UtlBoolean removedEvent = FALSE; UtlString eventName(eventTypeToken ? eventTypeToken : ""); lockForWrite(); // Only add the event support if it does not already exist; SubscribeServerEventData* eventData = (SubscribeServerEventData*) mEventDefinitions.remove(&eventName); if(eventData) { removedEvent = TRUE; userAgent = eventData->mpEventSpecificUserAgent == mpDefaultUserAgent ? NULL : eventData->mpEventSpecificUserAgent; contentMgr = eventData->mpEventSpecificContentMgr == mpDefaultContentMgr ? NULL : eventData->mpEventSpecificContentMgr; eventHandler = eventData->mpEventSpecificHandler == mpDefaultEventHandler ? NULL : eventData->mpEventSpecificHandler; subscriptionMgr = eventData->mpEventSpecificSubscriptionMgr == mpDefaultSubscriptionMgr ? NULL : eventData->mpEventSpecificSubscriptionMgr; // Unregister interest in SUBSCRIBE requests and NOTIFY // responses for this event type eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue())); delete eventData; eventData = NULL; } else { userAgent = NULL; contentMgr = NULL; eventHandler = NULL; subscriptionMgr = NULL; } unlockForWrite(); return(removedEvent); }
// Destructor SipRefreshManager::~SipRefreshManager() { // Do not delete mpUserAgent ,mpDialogMgr. They // may be used else where and need to be deleted outside the // SipRefreshManager. // Stop receiving SUBSCRIBE responses mpUserAgent->removeMessageObserver(*(getMessageQueue())); // Wait until this OsServerTask has stopped or handleMethod // might access something we are about to delete here. waitUntilShutDown(); // Delete the event type strings mEventTypes.destroyAll(); // Unsubscribe to anything that is in the list stopAllRefreshes(); // mRefreshes should now be empty }
UtlBoolean SipPublishServer::disableEventType(const char* eventType) { UtlString eventName(eventType); lockForWrite(); PublishServerEventData* eventData = dynamic_cast <PublishServerEventData*> (mEventDefinitions.remove(&eventName)); if (eventData) { // Unregister interest in PUBLISH requests for this event type eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue())); delete eventData; } unlockForWrite(); return eventData != NULL; }
UtlBoolean SipSubscribeServer::disableEventType(const char* eventType) { // :TODO: We should terminate all subscriptions for this event type. UtlString eventName(eventType); lockForWrite(); SubscribeServerEventData* eventData = dynamic_cast <SubscribeServerEventData*> (mEventDefinitions.remove(&eventName)); if (eventData) { // Unregister interest in SUBSCRIBE requests and NOTIFY // responses for this event type eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue())); delete eventData; } unlockForWrite(); return eventData != NULL; }
UtlBoolean SipPublishServer::disableEventType(const char* eventTypeToken, SipUserAgent*& userAgent, SipPublishServerEventStateMgr*& eventStateMgr, SipPublishServerEventStateCompositor*& eventStateCompositor) { UtlBoolean removedEvent = FALSE; UtlString eventName(eventTypeToken ? eventTypeToken : ""); lockForWrite(); // Only add the event support if it does not already exist; PublishServerEventData* eventData = (PublishServerEventData*) mEventDefinitions.remove(&eventName); if(eventData) { removedEvent = TRUE; userAgent = eventData->mpEventSpecificUserAgent == mpDefaultUserAgent ? NULL : eventData->mpEventSpecificUserAgent; eventStateCompositor = eventData->mpEventSpecificStateCompositor == mpDefaultCompositor ? NULL : eventData->mpEventSpecificStateCompositor; eventStateMgr = eventData->mpEventSpecificStateMgr == mpDefaultEventStateMgr ? NULL : eventData->mpEventSpecificStateMgr; // Unregister interest in PUBLISH requests for this event type eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue())); delete eventData; eventData = NULL; } else { userAgent = NULL; eventStateCompositor = NULL; eventStateMgr = NULL; } unlockForWrite(); return(removedEvent); }
void SipRefreshManager::setRefreshTimer(RefreshDialogState& state, UtlBoolean isSuccessfulReschedule) { // Create and set a new timer for the failed time out period int nextResendSeconds = calculateResendTime(state.mExpirationPeriodSeconds, isSuccessfulReschedule); // If a signficant amount of time has passed since the prior // request was sent, decrease the error timeout a bit. // This is only a problem with the error case as in the // successful case we set the timer before sending the // request. if(!isSuccessfulReschedule) { long now = OsDateTime::getSecsSinceEpoch(); if(state.mPendingStartTime > 0 && now - state.mPendingStartTime > 5) { nextResendSeconds = nextResendSeconds - now + state.mPendingStartTime; if(nextResendSeconds < 30) { nextResendSeconds = 30; } } } OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipRefreshManager::setRefreshTimer setting resend timeout in %d seconds\n", nextResendSeconds); OsMsgQ* incomingQ = getMessageQueue(); OsTimer* resendTimer = new OsTimer(incomingQ, (int)&state); state.mpRefreshTimer = resendTimer; OsTime timerTime(nextResendSeconds, 0); resendTimer->oneshotAfter(timerTime); }
UtlBoolean SipPublishServer::enableEventType(const char* eventTypeToken, SipUserAgent* userAgent, SipPublishServerEventStateMgr* eventStateMgr, SipPublishServerEventStateCompositor* eventStateCompositor) { UtlBoolean addedEvent = FALSE; UtlString eventName(eventTypeToken ? eventTypeToken : ""); lockForWrite(); // Only add the event support if it does not already exist; PublishServerEventData* eventData = (PublishServerEventData*) mEventDefinitions.find(&eventName); if(!eventData) { addedEvent = TRUE; eventData = new PublishServerEventData(); *((UtlString*)eventData) = eventName; eventData->mpEventSpecificUserAgent = userAgent ? userAgent : mpDefaultUserAgent; eventData->mpEventSpecificStateCompositor = eventStateCompositor ? eventStateCompositor : mpDefaultCompositor; eventData->mpEventSpecificStateMgr = eventStateMgr ? eventStateMgr : mpDefaultEventStateMgr; mEventDefinitions.insert(eventData); // Register an interest in PUBLISH requests for this event type eventData->mpEventSpecificUserAgent->addMessageObserver(*(getMessageQueue()), SIP_PUBLISH_METHOD, TRUE, // requests FALSE, // not reponses TRUE, // incoming FALSE, // no outgoing eventName, NULL, NULL); } unlockForWrite(); return(addedEvent); }
/// Insert a message into the buffer. void SipClientWriteBuffer::insertMessage(SipMessage* message) { UtlBoolean wasEmpty = mWriteBuffer.isEmpty(); // // Let all outbound processors know about this message // if (message && mpSipUserAgent && mClientSocket && mClientSocket->isOk()) { UtlString remoteHostAddress; int remotePort; mClientSocket->getRemoteHostIp(&remoteHostAddress, &remotePort); // 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(), remoteHostAddress.data(), remotePort == PORT_NONE ? defaultPort() : remotePort, msgText.data(), msgLength); mpSipUserAgent->executeAllBufferedSipOutputProcessors(*message, remoteHostAddress.data(), remotePort == PORT_NONE ? defaultPort() : remotePort); } } // Add the message to the queue. mWriteBuffer.insert(message); // If the buffer was empty, we need to set mWriteString and // mWritePointer. if (wasEmpty) { ssize_t length; message->getBytes(&mWriteString, &length); mWritePointer = 0; } mWriteQueued = TRUE; // Check to see if our internal queue is getting too big, which means // that the socket has been blocked for writing for a long time. // We use the message queue length of this task as the limit, since // both queues are affected by the same traffic load factors. if (mWriteBuffer.entries() > (size_t) (getMessageQueue()->maxMsgs())) { // If so, abort all unsent messages and terminate this client (so // as to clear any state of the socket). Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipClientWriteBuffer[%s]::insertMessage " "mWriteBuffer has '%d' entries, exceeding the limit of maxMsgs '%d'", getName().data(), (int) mWriteBuffer.entries(), getMessageQueue()->maxMsgs()); emptyBuffer(TRUE); clientStopSelf(); } }
// Handle an incoming message // Return TRUE if the message was handled, otherwise FALSE. UtlBoolean MpMediaTask::handleMessage(OsMsg& rMsg) { UtlBoolean handled; MpFlowGraphBase* pFlowGraph; MpMediaTaskMsg* pMsg; if (rMsg.getMsgType() != OsMsg::MP_TASK_MSG) return FALSE; // the method only handles MP_TASK_MSG messages pMsg = (MpMediaTaskMsg*) &rMsg; pFlowGraph = (MpFlowGraphBase*) pMsg->getPtr1(); handled = TRUE; // until proven otherwise, assume we'll handle the msg #ifdef _PROFILE /* [ */ // Log the time it takes to handle messages other than WAIT_FOR_SIGNAL. long long start_time; if (pMsg->getMsg() != MpMediaTaskMsg::WAIT_FOR_SIGNAL) { timeval t; gettimeofday(&t, NULL); start_time = (t.tv_sec * 1000000) + t.tv_usec; } #endif /* _PROFILE ] */ if (getMessageQueue()->numMsgs() > 100) { OsSysLog::add(FAC_SIP, PRI_DEBUG, "MpMediaTask::handleMessage msgType = %d, " "queue length = %d", pMsg->getMsg(), getMessageQueue()->numMsgs()); } switch (pMsg->getMsg()) { case MpMediaTaskMsg::MANAGE: if (!handleManage(pFlowGraph)) mHandleMsgErrs++; break; case MpMediaTaskMsg::SET_FOCUS: if (!handleSetFocus(pFlowGraph)) mHandleMsgErrs++; break; case MpMediaTaskMsg::START: if (!handleStart(pFlowGraph)) mHandleMsgErrs++; break; case MpMediaTaskMsg::STOP: if (!handleStop(pFlowGraph)) mHandleMsgErrs++; break; case MpMediaTaskMsg::UNMANAGE: if (!handleUnmanage(pFlowGraph)) mHandleMsgErrs++; break; case MpMediaTaskMsg::WAIT_FOR_SIGNAL: if (!handleWaitForSignal(pMsg)) mHandleMsgErrs++; break; default: handled = FALSE; // we didn't handle the message after all break; } #ifdef _PROFILE /* [ */ // Log the time it takes to handle messages other than WAIT_FOR_SIGNAL. if (pMsg->getMsg() != MpMediaTaskMsg::WAIT_FOR_SIGNAL) { timeval t; gettimeofday(&t, NULL); long long end_time = (t.tv_sec * 1000000) + t.tv_usec; mOtherMessages.tally(end_time - start_time); } #endif /* _PROFILE ] */ return handled; }
/// Terminate all subscriptions and accept no new ones. void SipSubscribeServer::shutdown(const char* reason) { // If reason is NULL, use the default reason established by the constructor. if (!reason) { reason = mDefaultTermination; } OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSubscribeServer::shutdown reason '%s'", reason ? reason : "[null]"); lockForRead(); // Select the subscriptionChange value to describe what we're doing // with the subscriptions. enum SipSubscriptionMgr::subscriptionChange change; // Select the correct format for generating the Subscription-State value. UtlString* formatp = NULL; // We may need a temp UtlString. const char* format; if (reason == NULL) { format = "active;expires=%ld"; change = SipSubscriptionMgr::subscriptionContinues; } else if (strcmp(reason, terminationReasonSilent) == 0) { // Do not admit that the subscription is ending. format = "active;expires=%ld"; change = SipSubscriptionMgr::subscriptionTerminatedSilently; } else if (strcmp(reason, terminationReasonNone) == 0) { format = "terminated"; change = SipSubscriptionMgr::subscriptionTerminated; } else { // Allocate a UtlString and assemble the Subscription-State format in it. formatp = new UtlString(); formatp->append("terminated;reason="); formatp->append(reason); format = formatp->data(); change = SipSubscriptionMgr::subscriptionTerminated; } // For each event type that is registered, delete all the subscriptions. UtlHashBagIterator event_itor(mEventDefinitions); SubscribeServerEventData* eventData; while ((eventData = dynamic_cast <SubscribeServerEventData*> (event_itor()))) { // Unregister interest in SUBSCRIBE requests and NOTIFY // responses for this event type, so we do not service new subscriptions. eventData->mpEventSpecificUserAgent->removeMessageObserver(*(getMessageQueue())); int numSubscriptions = 0; SipMessage** notifyArray = NULL; UtlString** acceptHeaderValuesArray = NULL; UtlString** resourceIdArray = NULL; UtlString** eventTypeKeyArray = NULL; // :TODO: The four situations where NOTIFYs are generated should // be factored into a series of methods in // mpEventSpecificSubscriptionMgr that generate NOTIFYs // sequentially, and for each NOTIFY, call a common service // method that does the remaining operations and sends the // NOTIFY. // Construct a NOTIFY (without body) for every subscription, containing // the dialog-related information about each subscription. eventData->mpEventSpecificSubscriptionMgr-> createNotifiesDialogInfoEvent(static_cast <const UtlString&> (*eventData), format, numSubscriptions, acceptHeaderValuesArray, notifyArray, resourceIdArray, eventTypeKeyArray); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSubscribeServer::shutdown eventType = '%s', numSubscriptions = %d", eventData->data(), numSubscriptions); // For each NOTIFY, add the subscription-related information and then // send it. for (int notifyIndex = 0; notifyIndex < numSubscriptions; notifyIndex++) { SipMessage* notify = notifyArray[notifyIndex]; // Check to see if the dialog information could be added. // (The subscription might have been destroyed between when // it was decided to respond to it, and when the dialog information // was retrieved.) UtlString callId; notify->getCallIdField(&callId); if (!callId.isNull()) { if (change != SipSubscriptionMgr::subscriptionTerminatedSilently) { // Fill in the NOTIFY request body/content eventData->mpEventSpecificHandler-> getNotifyContent(*(resourceIdArray[notifyIndex]), *(eventTypeKeyArray[notifyIndex]), *eventData, *(eventData->mpEventSpecificContentMgr), *(acceptHeaderValuesArray[notifyIndex]), *notify, eventData->mEventSpecificFullState, NULL); // Call the application callback to edit the NOTIFY // content if that is required for this event type. // Also gets 'version' (if relevant) and 'savedEventTypeKey'. int version; UtlString savedEventTypeKey; eventData->mpEventSpecificSubscriptionMgr-> updateNotifyVersion(eventData->mpEventSpecificContentVersionCallback, *notify, version, savedEventTypeKey); // Set the Contact header. setContact(notify); // Send the NOTIFY request. eventData->mpEventSpecificUserAgent->send(*notify); } // Remove the record of the subscription. UtlString dialogHandle; notify->getDialogHandle(dialogHandle); eventData->mpEventSpecificSubscriptionMgr-> endSubscription(dialogHandle, change); } } // Free the NOTIFY requests and accept header field values. SipSubscriptionMgr::freeNotifies(numSubscriptions, acceptHeaderValuesArray, notifyArray); // Free the resource and event type arrays. for (int index = 0; index < numSubscriptions; index++) { delete resourceIdArray[index]; delete eventTypeKeyArray[index]; } delete[] resourceIdArray; delete[] eventTypeKeyArray; // Remove eventData from mEventDefinitions. mEventDefinitions.removeReference(eventData); delete eventData; } unlockForRead(); // Free the temporary UtlString, if necessary. if (formatp) { delete formatp; } lockForWrite(); mEventDefinitions.destroyAll(); unlockForWrite(); }
// Realizes the player by initiating a connection to the target, allocates // buffers, etc. OsStatus MpStreamPlayer::realize(UtlBoolean bBlock /* = TRUE */) { OsStatus status = OS_FAILED ; OsEvent eventHandle ; intptr_t eventData ; // Only proceed if we have a flow graph and the player is unrealized. if (getState() == PlayerUnrealized) { // Create an mpQueueEvent object to signal state changes in from // the MpStreamFeeder mpQueueEvent = new OsQueuedEvent(*getMessageQueue(), 0); // Realize the stream if (mSourceType == SourceUrl) { if (mpMsgQ != NULL) { MpStreamMsg msg(MpStreamMsg::STREAM_REALIZE_URL, mTarget, NULL, &eventHandle, mpQueueEvent, mFlags, (intptr_t) new Url(mUrl)) ; status = mpMsgQ->send(msg) ; } } else if (mSourceType == SourceBuffer) { if (mpMsgQ != NULL) { MpStreamMsg msg(MpStreamMsg::STREAM_REALIZE_BUFFER, mTarget, NULL, &eventHandle, mpQueueEvent, mFlags, (intptr_t) mpBuffer) ; status = mpMsgQ->send(msg) ; } } if (status == OS_SUCCESS) { // Wait for a response status = eventHandle.wait(OsTime(MAX_REALIZE_WAIT, 0)) ; if (status == OS_SUCCESS) { if (eventHandle.getEventData(eventData) == OS_SUCCESS) { mHandle = (StreamHandle) eventData ; if (mHandle != 0) mbRealized = TRUE ; } else { mHandle = NULL ; } } else { mHandle = NULL ; } } } if (mHandle == 0) { mState = PlayerDestroyed ; status = OS_FAILED ; mSemStateChange.release() ; } if (status == OS_SUCCESS) { // Start Server task if successfull if (start() == TRUE) { // Block while waiting for prefetch (if requested) if (bBlock) { while (getState() == PlayerUnrealized) { mSemStateChange.acquire(); } } else { // Wait for task to startup while (!isStarted()) { OsTask::yield() ; } } } else { syslog(FAC_STREAMING, PRI_CRIT, "Failed to create thread for MpStreamPlayer") ; // Unable to create thread; attempt to clean up status = OS_FAILED ; MpStreamMsg msgStop(MpStreamMsg::STREAM_STOP, mTarget, mHandle); mpMsgQ->send(msgStop) ; MpStreamMsg msgDestroy(MpStreamMsg::STREAM_DESTROY, mTarget, mHandle); mpMsgQ->send(msgDestroy) ; // YIKES: This is hard to recover from, we don't have a message queue // to wait for a response from the lower layers. If someone deletes // this immediately after this call, the lower layers could choke // on a now-deleted mpQueueEvent. There are two options that I can // think of: 1) garbage collect the player after some long period of // time, 2) block the thread context for some reasonable amount of // time. I'm going with #2 for now... OsTask::delay(1000) ; mbRealized = FALSE ; mState = PlayerDestroyed ; mSemStateChange.release() ; } } return status ; }
UtlBoolean SipSubscribeServer::handleSubscribe(const SipMessage& subscribeRequest) { UtlBoolean handledSubscribe = FALSE; UtlString eventName; subscribeRequest.getEventField(&eventName, NULL); // Not modifying the SubscribeServerEventData, just reading it lockForRead(); // Get the event specific handler and information SubscribeServerEventData* eventPackageInfo = (SubscribeServerEventData*) mEventDefinitions.find(&eventName); // We handle this event type if(eventPackageInfo) { handledSubscribe = TRUE; UtlString resourceId; UtlString eventTypeKey, eventType; SipSubscribeServerEventHandler* handler = eventPackageInfo->mpEventSpecificHandler; // Get the keys used to identify the event state content handler->getKeys(subscribeRequest, resourceId, eventTypeKey, eventType); SipMessage subscribeResponse; // Check if authenticated (or if it needs to be authenticated) if(handler->isAuthenticated(subscribeRequest, resourceId, eventTypeKey, subscribeResponse)) { // Check if authorized (or if authorization is required) if(handler->isAuthorized(subscribeRequest, resourceId, eventTypeKey, subscribeResponse)) { // The subscription is allowed, so update the // subscription state. Set the To field tag if // this request initiated the dialog UtlString subscribeDialogHandle; UtlBoolean isNewDialog; UtlBoolean isExpiredSubscription; eventPackageInfo->mpEventSpecificSubscriptionMgr->updateDialogInfo( subscribeRequest, resourceId, eventTypeKey, getMessageQueue(), subscribeDialogHandle, isNewDialog, isExpiredSubscription, subscribeResponse); // Send the response ASAP to minimize resend handling of request eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse); // Build a NOTIFY SipMessage notifyRequest; // Set the dialog information eventPackageInfo->mpEventSpecificSubscriptionMgr->getNotifyDialogInfo(subscribeDialogHandle, notifyRequest); // Set the NOTIFY content UtlString acceptHeaderValue; subscribeRequest.getAcceptField(acceptHeaderValue); handler->getNotifyContent(resourceId, eventTypeKey, eventType, *(eventPackageInfo->mpEventSpecificContentMgr), acceptHeaderValue, notifyRequest); // Send the notify request eventPackageInfo->mpEventSpecificUserAgent->send(notifyRequest); } // Not authorized else { // Send the response eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse); } } // Not authenticated else { // Send the response eventPackageInfo->mpEventSpecificUserAgent->send(subscribeResponse); } } // We should not have received SUBSCRIBE requests for this event type // This event type has not been enabled in this SubscribeServer else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipSubscribeServer::handleSubscribe event type: %s not enabled", eventName.data()); SipMessage eventTypeNotHandled; eventTypeNotHandled.setResponseData(&subscribeRequest, SIP_BAD_EVENT_CODE, SIP_BAD_EVENT_TEXT); mpDefaultUserAgent->send(eventTypeNotHandled); } unlockForRead(); return(handledSubscribe); }
// Constructor SipXProxyCseObserver::SipXProxyCseObserver(SipUserAgent& sipUserAgent, const UtlString& dnsName, CallStateEventWriter* pWriter ) : OsServerTask("SipXProxyCseObserver-%d", NULL, 2000), SipOutputProcessor( CSE_AGENT_OUTPUT_PROC_PRIO ), mpSipUserAgent(&sipUserAgent), mpBuilder(NULL), mpWriter(pWriter), mSequenceNumber(0), mFlushTimer(getMessageQueue(), 0), mCallTransMutex(OsMutex::Q_FIFO) { OsTime timeNow; OsDateTime::getCurTime(timeNow); UtlString event; if (mpWriter) { switch (pWriter->getLogType()) { case CallStateEventWriter::CseLogFile: mpBuilder = new CallStateEventBuilder_XML(dnsName); break; case CallStateEventWriter::CseLogDatabase: mpBuilder = new CallStateEventBuilder_DB(dnsName); break; } if (mpBuilder) { if (pWriter->openLog()) { mpBuilder->observerEvent(mSequenceNumber, timeNow, CallStateEventBuilder::ObserverReset, "SipXProxyCseObserver"); mpBuilder->finishElement(event); if (!mpWriter->writeLog(event.data())) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver initial event log write failed - disabling writer"); mpWriter = NULL; } else { mpWriter->flush(); // try to ensure that at least the sequence restart gets to the file } } else { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipXProxyCseObserver initial event log write failed - disabling writer"); mpWriter = NULL; // Set correct state even if nothing is written mpBuilder->observerEvent(mSequenceNumber, timeNow, CallStateEventBuilder::ObserverReset, ""); mpBuilder->finishElement(event); } } } // set up periodic timer to flush log file mFlushTimer.periodicEvery(OsTime(), OsTime(SipXProxyCallStateFlushInterval, 0)) ; // Register to get incoming requests sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_BYE_METHOD, TRUE, // Requests, FALSE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_INVITE_METHOD, TRUE, // Requests, FALSE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_REFER_METHOD, TRUE, // Requests, FALSE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); sipUserAgent.addSipOutputProcessor( this ); // set up periodic timer to cleanup dead calls in the CallTransMap mpCleanupTimeoutCallback = new OsCallback((void*)this, CleanupTransMap); mpCleanupMapTimer = new OsTimer(*mpCleanupTimeoutCallback); mpCleanupMapTimer->periodicEvery(OsTime(), OsTime(SipXProxyCallStateCleanupInterval, 0)) ; }
UtlBoolean SipRefreshManager::initiateRefresh(SipMessage& subscribeOrRegisterRequest, void* applicationData, const RefreshStateCallback refreshStateCallback, UtlString& earlyDialogHandle) { UtlBoolean intitialRequestSent = FALSE; // Make sure we do not have an existing dialog or refresh session state // going for the given message UtlString messageDialogHandle; subscribeOrRegisterRequest.getDialogHandle(messageDialogHandle); UtlBoolean existingRefreshState = FALSE; UtlBoolean existingDialogState = FALSE; if(!SipDialog::isEarlyDialog(messageDialogHandle)) { existingDialogState = TRUE; OsSysLog::add(FAC_SIP, PRI_ERR, "SipRefreshManager::initiateRefresh called with established dialog handle: %s", messageDialogHandle.data()); } else { OsLock localLock(mRefreshMgrMutex); // See if there is an early or established dialog for this message if(getAnyDialog(messageDialogHandle)) { existingRefreshState = TRUE; intitialRequestSent = FALSE; OsSysLog::add(FAC_SIP, PRI_ERR, "SipRefreshManager::initiateRefresh called with pre-existing refresh state: %s", messageDialogHandle.data()); } // The dialog should not exist either else if(mpDialogMgr->dialogExists(messageDialogHandle) || mpDialogMgr->earlyDialogExistsFor(messageDialogHandle)) { existingDialogState = TRUE; OsSysLog::add(FAC_SIP, PRI_ERR, "SipRefreshManager::initiateRefresh called with pre-existing dialog: %s", messageDialogHandle.data()); } } // Should not be any existing refresh or dialog states // for this message if(!existingRefreshState && !existingDialogState) { // Make sure we are registered to receive responses // for the message we are about to send UtlString method; subscribeOrRegisterRequest.getRequestMethod(&method); if(method.compareTo(SIP_REGISTER_METHOD) == 0) { lock(); if(!mReceivingRegisterResponses) { mReceivingRegisterResponses = TRUE; // receive REGISTER responses mpUserAgent->addMessageObserver(*(getMessageQueue()), SIP_REGISTER_METHOD, FALSE, // yes requests TRUE, // no responses TRUE, // incoming, FALSE, // outgoing NULL); } unlock(); } else if(method.compareTo(SIP_SUBSCRIBE_METHOD) == 0) { UtlString eventType; subscribeOrRegisterRequest.getEventField(&eventType, NULL); // Check to see if we have already registered to // receive the event type lock(); if(mEventTypes.find(&eventType) == NULL) { mEventTypes.insert(new UtlString(eventType)); // receive SUBSCRIBE responses for this event type mpUserAgent->addMessageObserver(*(getMessageQueue()), SIP_SUBSCRIBE_METHOD, FALSE, // no requests TRUE, // yes responses TRUE, // incoming, FALSE, // outgoing eventType); } unlock(); } // Create a new refresh state int requestedExpiration = 0; // returned from following call RefreshDialogState* state = createNewRefreshState(subscribeOrRegisterRequest, messageDialogHandle, applicationData, refreshStateCallback, requestedExpiration); // create a new dialog mpDialogMgr->createDialog(subscribeOrRegisterRequest, TRUE, // message from this side messageDialogHandle); // Keep track of when we send this request to be refreshed long now = OsDateTime::getSecsSinceEpoch(); state->mPendingStartTime = now; state->mRequestState = REFRESH_REQUEST_PENDING; // Set a timer at which to resend the next refresh based upon the // assumption that the request will succeed. When we receive a // failed response, we will cancel the timer and reschedule // a new timer based upon a smaller fraction of the requested // expiration period setRefreshTimer(*state, TRUE); // Resend with successful timeout OsTimer* resendTimer = state->mpRefreshTimer; // Mark the refresh state as having an outstanding request // and make a copy of the request. The copy needs to be // attached to the state before the send incase the response // comes back before we return from the send. state->mRequestState = REFRESH_REQUEST_PENDING; state->mpLastRequest = new SipMessage(subscribeOrRegisterRequest); // Add the state to the container of refresh states // No need to lock this refreshMgr earlier as this is a new // state and no one can touch it until it is in the list. lock(); mRefreshes.insert(state); unlock(); // NOTE: at this point is is no longer safe to touch the state // without locking it again. Avoid locking this refresh mgr // when something can block (e.g. like calling SipUserAgent ::send) // Send the request // Is the correct? Should we send the request first and only set // a timer if the request succeeds?? intitialRequestSent = mpUserAgent->send(subscribeOrRegisterRequest); // We do not clean up the state even if the send fails. // The application must end the refresh as the refresh // manager should retry the send if it failed if(!intitialRequestSent) { // Need to lock this refresh mgr and make sure the state // still exists. It could have been deleted while this // was unlocked above. lock(); if(stateExists(state)) { // It is now safe to touch the state again // Mark the state of the last request as having // failed, so we know to resend when the timer // fires state->mRequestState = REFRESH_REQUEST_FAILED; // The expiration should still be set to zero // the initial send failed, cancel the timer and // fire the notification. The handleMessage method // will see that the subscription or registration // has never succeeded and reshedule the timer for // a failure timeout. We cannot reschedule the // timer here as there is a race condition between // deleting the timer here (in the applications context) // and in handleMessage in this refresh manager's // context. // If the timer has not changed assume it is still safe // to touch it if(state->mpRefreshTimer == resendTimer) { stopTimerForFailureReschedule(state->mpRefreshTimer); } // Do not notify the application that the request failed // when it occurs on the first invokation. The application // will know by the return. } unlock(); } } return(intitialRequestSent); }
// Constructor SipXProxyCseObserver::SipXProxyCseObserver(SipUserAgent& sipUserAgent, const UtlString& dnsName, CallStateEventWriter* pWriter ) : OsServerTask("SipXProxyCseObserver-%d", NULL, 2000), mpSipUserAgent(&sipUserAgent), mpBuilder(NULL), mpWriter(pWriter), mSequenceNumber(0), mFlushTimer(getMessageQueue(), 0) { OsTime timeNow; OsDateTime::getCurTime(timeNow); UtlString event; if (mpWriter) { switch (pWriter->getLogType()) { case CallStateEventWriter::CseLogFile: mpBuilder = new CallStateEventBuilder_XML(dnsName); break; case CallStateEventWriter::CseLogDatabase: mpBuilder = new CallStateEventBuilder_DB(dnsName); break; } if (mpBuilder) { if (pWriter->openLog()) { mpBuilder->observerEvent(mSequenceNumber, timeNow, CallStateEventBuilder::ObserverReset, "SipXProxyCseObserver"); mpBuilder->finishElement(event); if (!mpWriter->writeLog(event.data())) { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver initial event log write failed - disabling writer"); mpWriter = NULL; } else { mpWriter->flush(); // try to ensure that at least the sequence restart gets to the file } } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipXProxyCseObserver initial event log write failed - disabling writer"); mpWriter = NULL; // Set correct state even if nothing is written mpBuilder->observerEvent(mSequenceNumber, timeNow, CallStateEventBuilder::ObserverReset, ""); mpBuilder->finishElement(event); } } } // set up periodic timer to flush log file mFlushTimer.periodicEvery(OsTime(), OsTime(SipXProxyCallStateFlushInterval, 0)) ; // Register to get incoming requests sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_BYE_METHOD, TRUE, // Requests, FALSE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_INVITE_METHOD, TRUE, // Requests, TRUE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); sipUserAgent.addMessageObserver(*getMessageQueue(), SIP_REFER_METHOD, TRUE, // Requests, FALSE, //Responses, TRUE, //Incoming, FALSE, //OutGoing, "", //eventName, NULL, // any session NULL // no observerData ); }
// Handle a timer service request. // Return TRUE if the request was handled, otherwise FALSE. UtlBoolean OsTimerTask::handleMessage(OsMsg& rMsg) { // Process a message. // If not an OS_TIMERTASK_COMMAND message, return FALSE to indicate it should be // passed to our superclass. if (rMsg.getMsgType() != OsMsg::OS_TIMERTASK_COMMAND) { return FALSE; } // Process an OS_TIMERTASK_COMMAND message. OsTimerTaskCommandMsg& message = dynamic_cast <OsTimerTaskCommandMsg&> (rMsg); // Process a OS_TIMER_SHUTDOWN message, which is special if (message.getMsgSubType() == OsTimerTaskCommandMsg::OS_TIMER_SHUTDOWN) { OsSysLog::add(FAC_KERNEL, PRI_INFO, "OsTimerTask::handleMessage OS_TIMER_SHUTDOWN seen, mState = %d", mState); // Verify that there are no other requests in the timer task's queue. assert(getMessageQueue()->isEmpty()); // Stop all the timers in the timer queue. OsTimer* link; for (OsTimer* timer = mTimerQueue; timer; timer = link) { // This lock should never block, since the application should not // be accessing the timer. OsLock lock(timer->mBSem); // Check that the application and task states are the same. // If they aren't, the application is mucking with the timer. assert(timer->mTaskState == timer->mApplicationState); // Increment the state fields, to show the timer is stopped. timer->mTaskState = timer->mApplicationState = timer->mApplicationState + 1; // Get the link field. link = timer->mTimerQueueLink; // Clear the link field of the timer. timer->mTimerQueueLink = 0; } // Empty the timer queue. mTimerQueue = 0; // Change mState so the main loop will exit. requestShutdown(); // Signal the event so our caller knows we're done. message.getEventP()->signal(0); OsSysLog::add(FAC_KERNEL, PRI_INFO, "OsTimerTask::handleMessage OS_TIMER_SHUTDOWN seen, mState = %d", mState); return TRUE; } OsTimer* timer = message.getTimerP(); #ifndef NDEBUG CHECK_VALIDITY(timer); #endif unsigned int applicationState; OsTimer::Time expiresAt; UtlBoolean periodic; OsTimer::Interval period; { OsLock lock(timer->mBSem); // mDeleting may be true, if the destructor has started running. // Decrement the outstanding message count. timer->mOutstandingMessages--; // Get mApplicationState. applicationState = timer->mApplicationState; // Get the timing information. expiresAt = timer->mExpiresAt; periodic = timer->mPeriodic; period = timer->mPeriod; } // Determine whether the timer needs to be stopped. // (The comparison between applicationState and mTaskState is really // ">", taking into account wraparound. But that is difficult to // implement, so given that mApplicationState is always >= mTaskState // by design, we can use "!=".) if (applicationState != timer->mTaskState && OsTimer::isStarted(timer->mTaskState)) { // Stop the timer. removeTimer(timer); } // Determine whether the timer needs to be started. if (applicationState != timer->mTaskState && OsTimer::isStarted(applicationState)) { // Start the timer. // Set the saved timing information. timer->mQueuedExpiresAt = expiresAt; timer->mQueuedPeriodic = periodic; timer->mQueuedPeriod = period; insertTimer(timer); } // Update the task state. timer->mTaskState = applicationState; switch (message.getMsgSubType()) { case OsTimerTaskCommandMsg::OS_TIMER_UPDATE: // No further processing is needed. break; case OsTimerTaskCommandMsg::OS_TIMER_UPDATE_SYNC: // If it is an UPDATE_SYNC message, signal the event. message.getEventP()->signal(0); break; case OsTimerTaskCommandMsg::OS_TIMER_UPDATE_DELETE: // If it is an UPDATE_DELETE, delete the timer. // Timer will not be accessed by any other thread, so we // can access it without locking. #ifndef NDEBUG // Deletion in progress. assert(timer->mDeleting); #endif // Timer should be stopped already. assert(OsTimer::isStopped(timer->mApplicationState)); // No outstanding messages. assert(timer->mOutstandingMessages == 0); #ifndef NDEBUG // Set mDeleting to FALSE to the destructor won't fail. timer->mDeleting = FALSE; #endif // Use ordinary destructor to delete the timer. // Because of the state of the timer, it will not send a message to // the timer task. delete timer; break; default: // Catch invalid values. assert(FALSE); } return TRUE; }
// The entry point for the task. // This method executes a message processing loop until either // requestShutdown(), deleteForce(), or the destructor for this object // is called. int OsTimerTask::run(void* pArg) { UtlBoolean doShutdown; OsMsg* pMsg = NULL; OsStatus res; // "now" is the current time. OsTimer::Time now = OsTimer::now(); doShutdown = FALSE; do { // Do not attempt to receive message if a timer has already fired. // (This also avoids an edge case if the timeout value is zero // or negative.) if (!(mTimerQueue && OsTimer::compareTimes(now, mTimerQueue->mQueuedExpiresAt) >= 0)) { // Set the timeout till the next timer fires. OsTime timeout; if (mTimerQueue) { OsTimer::cvtToOsTime(timeout, OsTimer::subtractTimes(mTimerQueue->mQueuedExpiresAt, now)); } else { timeout = OsTime::OS_INFINITY; } res = receiveMessage((OsMsg*&) pMsg, timeout); // wait for a message if (res == OS_SUCCESS) { // A message was received. Process it. doShutdown = isShuttingDown(); if (!doShutdown) { // comply with shutdown if (!handleMessage(*pMsg)) // process the message { OsServerTask::handleMessage(*pMsg); } } if (!pMsg->getSentFromISR()) { pMsg->releaseMsg(); // free the message } } else { assert(pMsg==NULL); } now = OsTimer::now(); // Update our record of the current time. } // Now check for timers that have expired. while (mTimerQueue && OsTimer::compareTimes(now, mTimerQueue->mQueuedExpiresAt) >= 0) { // Fire the the timer (and remove it from the queue). OsTimer* timer = mTimerQueue; mTimerQueue = timer->mTimerQueueLink; // Clear the timer's mTimerQueueLink to indicate it is not // in the timer queue. timer->mTimerQueueLink = 0; fireTimer(timer); } if (OsSysLog::willLog(FAC_KERNEL, PRI_WARNING)) { // Check to see if timer firing took too long. OsTimer::Time after = OsTimer::now(); OsTimer::Time t = OsTimer::subtractTimes(after, now); if (t >= 1000000 /* 1 second */) { OsSysLog::add(FAC_KERNEL, PRI_WARNING, "OsTimerTask::run firing took %"PRId64" usecs," " queue length = %d, before fire = %"PRId64", after fire = %"PRId64, t, getMessageQueue()->numMsgs(), now, after); } } } while (!doShutdown); OsSysLog::add(FAC_KERNEL, PRI_INFO, "OsTimerTask::run OsTimerTask shutting down"); return 0; // and then exit }
// Thread execution code. int SipClient::run(void* runArg) { OsMsg* pMsg = NULL; OsStatus res; // Buffer to hold data read from the socket but not yet parsed // into incoming SIP messages. UtlString readBuffer; bool waitingToReportErr = FALSE; // controls whether to read-select on socket bool tcpOnErrWaitForSend = TRUE; int repeatedEOFs = 0; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run start " "tcpOnErrWaitForSend-%d waitingToReportErr-%d mbTcpOnErrWaitForSend-%d repeatedEOFs-%d", mName.data(), tcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs); // Wait structure: struct pollfd fds[2]; // Incoming message on the message queue (to be sent on the socket). fds[0].fd = mPipeReadingFd; // Socket ready to write (to continue sending message). // Socket ready to read (message to be received). do { assert(repeatedEOFs < 20); // The file descriptor for the socket may changemsg->getSendAddress(&fromIpAddress, &fromPort);, as OsSocket's // can be re-opened. fds[1].fd = mClientSocket->getSocketDescriptor(); // Initialize the revents members. // This may not be necessary (the man page is not clear), but // Valgrind flags 'fds[*].revents' as undefined if they aren't // initialized. fds[0].revents = 0; fds[1].revents = 0; fds[0].events = POLLIN; // only read-select on pipe // For non-blocking connect failures, don't read-select on socket if // the initial read showed an error but we have to wait to report it. if (!waitingToReportErr) { // This is the normal path. // Read the socket only if the socket is not shared. // If it is shared, the ancestral SipClient will read it. // If multiple threads attempt to read the socket, poll() may // succeed but another may read the data, leaving us to block on // read. fds[1].events = mbSharedSocket ? 0 : POLLIN; // Set wait for writing the socket if there is queued messages to // send. if (mWriteQueued) { // Wait for output on the socket to not block. fds[1].events |= POLLOUT; } } else { // just waiting to report error, ignore the socket fds[1].fd =-1; fds[1].events = 0; } // If there is residual data in the read buffer, // pretend the socket is ready to read. if (!readBuffer.isNull()) { fds[1].revents = POLLIN; } else { // Otherwise, call poll() to wait. int resPoll = poll(&fds[0], sizeof (fds) / sizeof (fds[0]), POLL_TIMEOUT); assert(resPoll >= 0 || (resPoll == -1 && errno == EINTR)); if (resPoll != 0) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run " "resPoll= %d revents: fd[0]= %x fd[1]= %x", mName.data(), resPoll, fds[0].revents, fds[1].revents ); } } if ((fds[1].revents & (POLLERR | POLLHUP)) != 0) { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run " "SipMessage::poll error(%d) ", mName.data(), errno); if (OsSocket::isFramed(mClientSocket->getIpProtocol())) { Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SipClient[%s]::run " "SipMessage::poll error(%d) got POLLERR | POLLHUP on UDP socket", mName.data(), errno); } else // eg. tcp socket // This client's socket is a connection-oriented protocol and the // connection has been terminated (probably by the remote end). // We must terminate the SipClient. // We drop the queued messages, but we do not report them to // SipUserAgent as failed sends. This will cause SipUserAgent to // retry the send using the same transport (rather than continuing // to the next transport), which should cause a new connection to // be made to the remote end. { // On non-blocking connect failures, we need to get the first send message // in order to successfully trigger the protocol fallback mechanism if (!tcpOnErrWaitForSend) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } else { fds[1].revents &= ~(POLLERR | POLLHUP); // clear error bit if waiting waitingToReportErr = TRUE; } } } // Check for message queue messages (fds[0]) before checking the socket(fds[1]), // to make sure that we process shutdown messages promptly, even // if we would be spinning trying to service the socket. else if ((fds[0].revents & POLLIN) != 0) { // Poll finished because the pipe is ready to read. // (One byte in pipe means message available in queue.) // Only a SipClient with a derived SipClientWriteBuffer // uses the pipe in the Sip message send process // Check to see how many messages are in the queue. int numberMsgs = (getMessageQueue())->numMsgs(); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run got pipe-select " "Number of Messages waiting: %d", mName.data(), numberMsgs); int i; char buffer[1]; for (i = 0; i < numberMsgs; i++) { // Receive the messages. res = receiveMessage((OsMsg*&) pMsg, OsTime::NO_WAIT); assert(res == OS_SUCCESS); // Normally, this is a SIP message for the write buffer. Once we have gotten // here, we are able to report any initial non-blocking connect error. mbTcpOnErrWaitForSend = FALSE; tcpOnErrWaitForSend = FALSE; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run got pipe-select " "mbTcpOnErrWaitForSend-%d waitingToReportErr-%d mbTcpOnErrWaitForSend-%d repeatedEOFs-%d", mName.data(), mbTcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs); // Read 1 byte from the pipe to clear it for this message. One byte is // inserted into the pipe for each message. assert(read(mPipeReadingFd, &buffer, 1) == 1); if (!handleMessage(*pMsg)) // process the message (from queue) { OsServerTask::handleMessage(*pMsg); } if (!pMsg->getSentFromISR()) { pMsg->releaseMsg(); // free the message } // In order to report an unframed(eg TCP) socket error to SipUserAgent dispatcher, // the error must be carried in a sip message from the client's message queue. // The message holds all the identifying information. if (waitingToReportErr) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } } } // end reading msg-available-for-output-queue pipe else if ((fds[1].revents & POLLOUT) != 0) { // Poll finished because socket is ready to write. // Call method to continue writing data. writeMore(); } else if ((fds[1].revents & POLLIN) != 0) { // Poll finished because socket is ready to read. // Read message. // Must allocate a new message because SipUserAgent::dispatch will // take ownership of it. SipMessage* msg = new SipMessage; int res = msg->read(mClientSocket, HTTP_DEFAULT_SOCKET_BUFFER_SIZE, &readBuffer); if (res >= 65536) { // // This is more than the allowable size of a SIP message. Discard! // UtlString remoteHostAddress; int remoteHostPort; msg->getSendAddress(&remoteHostAddress, &remoteHostPort); OS_LOG_WARNING(FAC_SIP, "Received a SIP Message (" << res << " bytes) beyond the maximum allowable size from host " << remoteHostAddress.data() << ":" << remoteHostPort); delete msg; readBuffer.remove(0); continue; } // Use readBuffer to hold any unparsed data after the message // we read. // Note that if a message was successfully parsed, readBuffer // still contains as its prefix the characters of that message. // We save them for logging purposes below and will delete them later. UtlString remoteHostAddress; int remoteHostPort; msg->getSendAddress(&remoteHostAddress, &remoteHostPort); if (!mClientSocket->isSameHost(remoteHostAddress.data(), mLocalHostAddress.data())) { try { if (!remoteHostAddress.isNull()) { boost::asio::ip::address remoteIp = boost::asio::ip::address::from_string(remoteHostAddress.data()); if (rateLimit().isBannedAddress(remoteIp)) { delete msg; readBuffer.remove(0); continue; } rateLimit().logPacket(remoteIp, 0); } } catch(const std::exception& e) { Os::Logger::instance().log(FAC_SIP_INCOMING, PRI_CRIT, "SipClient[%s]::run rate limit exception: %s", mName.data(), e.what()); } } // Note that input was processed at this time. touch(); // // Count the CR/LF to see if this is a keep-alive // int crlfCount = 0; for (int i = 0; i < res; i++) { if (readBuffer(i) == '\r' || readBuffer(i) == '\n') { crlfCount++; } else { break; } } if (res == crlfCount) { repeatedEOFs = 0; // The 'message' was a keepalive (CR-LF or CR-LF-CR-LF). UtlString fromIpAddress; int fromPort; UtlString buffer; int bufferLen; // send one CRLF set in the reply buffer.append("\r\n"); bufferLen = buffer.length(); // Get the send address for response. msg->getSendAddress(&fromIpAddress, &fromPort); if ( !portIsValid(fromPort)) { fromPort = defaultPort(); } // Log the message at DEBUG level. // Only bother processing if the logs are enabled if ( mpSipUserAgent->isMessageLoggingEnabled() || Os::Logger::instance().willLog(FAC_SIP_INCOMING, PRI_DEBUG) ) { UtlString logMessage; logMessage.append("Read keepalive message:\n"); logMessage.append("----Local Host:"); logMessage.append(mLocalHostAddress); logMessage.append("---- Port: "); logMessage.appendNumber( portIsValid(mLocalHostPort) ? mLocalHostPort : defaultPort()); logMessage.append("----\n"); logMessage.append("----Remote Host:"); logMessage.append(fromIpAddress); logMessage.append("---- Port: "); logMessage.appendNumber( portIsValid(fromPort) ? fromPort : defaultPort()); logMessage.append("----\n"); logMessage.append(readBuffer.data(), res); UtlString messageString; logMessage.append(messageString); logMessage.append("====================END====================\n"); // Don't bother to send the message to the SipUserAgent for its internal log. // Write the message to the syslog. Os::Logger::instance().log(FAC_SIP_INCOMING, PRI_DEBUG, "%s", logMessage.data()); } // send the CR-LF response message switch (mSocketType) { case OsSocket::TCP: { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run send TCP keep-alive CR-LF response, ", mName.data()); SipClientSendMsg sendMsg(OsMsg::OS_EVENT, SipClientSendMsg::SIP_CLIENT_SEND_KEEP_ALIVE, fromIpAddress, fromPort); handleMessage(sendMsg); // add newly created keep-alive to write buffer } break; case OsSocket::UDP: { Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run send UDP keep-alive CR-LF response, ", mName.data()); (dynamic_cast <OsDatagramSocket*> (mClientSocket))->write(buffer.data(), bufferLen, fromIpAddress, fromPort); } break; default: break; } // Delete the SipMessage allocated above, which is no longer needed. delete msg; // Now that logging is done, remove the parsed bytes and // remember any unparsed input for later use. readBuffer.remove(0, res); } // end keep-alive msg else if (res > 0) // got message, but not keep-alive { // Message successfully read. repeatedEOFs = 0; // Do preliminary processing of message to log it, // clean up its data, and extract any needed source address. preprocessMessage(*msg, readBuffer, res); // Dispatch the message. // dispatch() takes ownership of *msg. mpSipUserAgent->dispatch(msg); // Now that logging is done, remove the parsed bytes and // remember any unparsed input for later use. readBuffer.remove(0, res); } // end process read of >0 bytes else { // Something went wrong while reading the message. // (Possibly EOF on a connection-oriented socket.) repeatedEOFs++; // Delete the SipMessage allocated above, which is no longer needed. delete msg; Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run SipMessage::read returns %d (error(%d) or EOF), " "readBuffer = '%.1000s'", mName.data(), res, errno, readBuffer.data()); Os::Logger::instance().log(FAC_SIP, PRI_DEBUG, "SipClient[%s]::run error wait status " "tcpOnErrWaitForSend-%d waitingToReportErr-%d " "mbTcpOnErrWaitForSend-%d repeatedEOFs-%d " "protocol %d framed %d", mName.data(), tcpOnErrWaitForSend, waitingToReportErr, mbTcpOnErrWaitForSend, repeatedEOFs, mClientSocket->getIpProtocol(), OsSocket::isFramed(mClientSocket->getIpProtocol())); // If the socket is not framed (is connection-oriented), // we need to abort the connection and post a message // :TODO: This doesn't work right for framed connection-oriented // protocols (like SCTP), but OsSocket doesn't have an EOF-query // method -- we need to close all connection-oriented // sockets as well in case it was an EOF. // Define a virtual function that returns the correct bit. if (!OsSocket::isFramed(mClientSocket->getIpProtocol())) { // On non-blocking connect failures, we need to get the first send message // in order to successfully trigger the protocol fallback mechanism if (!tcpOnErrWaitForSend) { // Return all buffered messages with a transport error indication. emptyBuffer(TRUE); clientStopSelf(); } else { fds[1].revents &= ~(POLLERR | POLLHUP); // clear error bit if waiting waitingToReportErr = TRUE; } } // Delete the data read so far, which will not have been // deleted by HttpMessage::read. readBuffer.remove(0); } } // end POLLIN reading socket } while (isStarted()); return 0; // and then exit }