void SIPNict::onReceivedMessage(SIPMessage::Ptr pMsg, SIPTransportSession::Ptr pTransport) { SIPTransaction::Ptr pTransaction = static_cast<SIPTransaction::WeakPtr*>(_owner)->lock(); if (!pTransaction) return; int state = pTransaction->getState(); if (!pMsg->isResponse() || state == SIPTransaction::TRN_STATE_TERMINATED || state == COMPLETED) return; bool is2xx = pMsg->is2xx(); SIPTransaction::Ptr pParent = pTransaction->getParent(); switch (pTransaction->getState()) { case SIPTransaction::TRN_STATE_IDLE: case TRYING: if (pMsg->is1xx()) { pTransaction->setState(PROCEEDING); if (!pTransaction->isParent() && pParent && pParent->getState() < PROCEEDING) pParent->setState(PROCEEDING); pTransaction->informTU(pMsg, pTransport); } else { if (pTransaction->isParent() && !is2xx) { // // If we are the parent or this is and error response // cancel e and f timers // cancelTimerE(); cancelTimerF(); } else if (!pTransaction->isParent() && is2xx) { // // If this is a branch and it is a 2xx reponse, // then cancel both parents timers as sell // cancelTimerE(); cancelTimerF(); if (pParent) { pParent->fsm()->cancelTimerE(); pParent->fsm()->cancelTimerF(); pParent->setState(COMPLETED); } } else if (!pTransaction->isParent() && !is2xx) { // // If this is a branch and it is an error reponse, // then cancel both parent timers as well if there // is only one branch // cancelTimerE(); cancelTimerF(); if (pParent && pParent->getBranchCount() == 1) { pParent->fsm()->cancelTimerE(); pParent->fsm()->cancelTimerF(); pParent->setState(COMPLETED); } } pTransaction->setState(COMPLETED); pTransaction->informTU(pMsg, pTransport); if (!pTransport->isReliableTransport()) { // // Start the longest time we want to handle retransmissions of 200 OK // startTimerK(); } else { pTransaction->setState(SIPTransaction::TRN_STATE_TERMINATED); if (is2xx || pTransaction->allBranchesCompleted()) { if (pParent) pParent->setState(SIPTransaction::TRN_STATE_TERMINATED); } } } break; case PROCEEDING: if (pMsg->is1xx()) { pTransaction->informTU(pMsg, pTransport); } else { if (pTransaction->isParent() && !is2xx) { // // If we are the parent or this is and error response // cancel e and f timers // cancelTimerE(); cancelTimerF(); } else if (!pTransaction->isParent() && is2xx) { // // If this is a branch and it is a 2xx reponse, // then cancel both parent timers as sell // cancelTimerE(); cancelTimerF(); if (pParent) { pParent->fsm()->cancelTimerE(); pParent->fsm()->cancelTimerF(); pParent->setState(COMPLETED); } } else if (!pTransaction->isParent() && !is2xx) { // // If this is a branch and it is an error reponse, // then cancel both parent timers as well if there // is only one branch // cancelTimerE(); cancelTimerF(); if (pParent) { if (pParent->getBranchCount() == 1) { pParent->fsm()->cancelTimerE(); pParent->fsm()->cancelTimerF(); pParent->setState(COMPLETED); } } } pTransaction->setState(COMPLETED); pTransaction->informTU(pMsg, pTransport); if (!pTransport->isReliableTransport()) { // // Start the longest time we want to handle retransmissions of 200 OK // startTimerK(); } else { pTransaction->setState(SIPTransaction::TRN_STATE_TERMINATED); if (is2xx || pTransaction->allBranchesCompleted()) if (pParent) pParent->setState(SIPTransaction::TRN_STATE_TERMINATED); } } break; case COMPLETED: break; } if (pTransaction->getState() == SIPTransaction::TRN_STATE_TERMINATED) pTransaction->terminate(); if (pParent && pParent->getState() == SIPTransaction::TRN_STATE_TERMINATED) pParent->terminate(); }
void SIPFSMDispatch::onReceivedMessage(SIPMessage::Ptr pMsg, SIPTransportSession::Ptr pTransport) { if (!pTransport->isEndpoint() && pTransport->getLastReadCount() < MIN_DATAGRAM_SIZE && !pTransport->isReliableTransport()) { // // datagram is too short to be a SIP Message // Bailing out. Take note that streamed connection // can split SIP messages to smaller frames // and the last frame can be smaller than MIN_DATAGRAM_SIZE // so we do not impose a limit for streams // return; } try { pMsg->parse(); } catch(OSS::Exception e) { std::ostringstream logMsg; logMsg << "Incoming message failed to be parsed - " << e.message() << " LEN: " << pTransport->getLastReadCount() << " SRC: " << pTransport->getRemoteAddress().toIpPortString(); OSS::log_warning(logMsg.str()); return; } std::string id; if (!pMsg->getTransactionId(id)) return; // don't throw here // we don't have control over what we receive from the transport SIPTransaction::Ptr trn; SIPTransaction::Type transactionType = SIPTransaction::TYPE_UNKNOWN; if (pMsg->isRequest()) { if (OSS::string_caseless_starts_with(pMsg->startLine(), "invite")) { transactionType = SIPTransaction::TYPE_IST; if (_istBlocker.has(id)) { OSS_LOG_WARNING("Blocked request retransmission - " << pMsg->startLine()); return; } trn = _ist.findTransaction(pMsg, pTransport); } else if (OSS::string_caseless_starts_with(pMsg->startLine(), "ack")) { // // ACK for error responses will get matched to a transaction // transactionType = SIPTransaction::TYPE_IST; trn = _ist.findTransaction(pMsg, pTransport, false); } else { transactionType = SIPTransaction::TYPE_NIST; trn = _nist.findTransaction(pMsg, pTransport); } } else if (!pMsg->isRequest()) { std::string cseq; cseq = pMsg->hdrGet(OSS::SIP::HDR_CSEQ); if (OSS::string_caseless_ends_with(cseq, "invite")) { transactionType = SIPTransaction::TYPE_ICT; trn = _ict.findTransaction(pMsg, pTransport, false); } else { transactionType = SIPTransaction::TYPE_NICT; trn = _nict.findTransaction(pMsg, pTransport, false); } } if (trn) { std::ostringstream logMsg; if (!trn->getLogId().empty()) { logMsg << trn->getLogId() << "Found Transaction " << trn->getId(); OSS::log_debug(logMsg.str()); } else { trn->setLogId(pMsg->createContextId(true)); logMsg << trn->getLogId() << "Transaction " << trn->getId() << " CREATED"; OSS::log_information(logMsg.str()); } } if (!trn) { // // We did not get a transaction, check if this is an ack and find the IST ACK transaction // if (transactionType == SIPTransaction::TYPE_IST && pMsg->isRequest("ACK")) { // // No IST is existing in the ackable Pool. // Report this ACK as orphaned to the UA CORE // if (_ackOr2xxTransactionHandler) _ackOr2xxTransactionHandler(pMsg, pTransport); } else if (transactionType == SIPTransaction::TYPE_ICT && pMsg->is2xx()) { if (_ackOr2xxTransactionHandler) _ackOr2xxTransactionHandler(pMsg, pTransport); } else { std::ostringstream logMsg; logMsg << pMsg->createContextId(true) << "Unable to match incoming request to a transaction - " << pMsg->startLine(); OSS::log_warning(logMsg.str()); } } else { if (!trn->transportService()) { // // This is a newly created transaction // trn->transportService() = &_transport; trn->transport() = pTransport; } trn->onReceivedMessage(pMsg, pTransport); } }