diff --git a/apps/announce_transfer/AnnounceTransfer.cpp b/apps/announce_transfer/AnnounceTransfer.cpp index 1bea3e3b..34e2b79f 100644 --- a/apps/announce_transfer/AnnounceTransfer.cpp +++ b/apps/announce_transfer/AnnounceTransfer.cpp @@ -181,7 +181,7 @@ void AnnounceTransferDialog::onSipRequest(const AmSipRequest& req) } -void AnnounceTransferDialog::onSipReply(const AmSipReply& rep, int old_dlg_status) { +void AnnounceTransferDialog::onSipReply(const AmSipReply& rep, int old_dlg_status, const string& trans_method) { if ((status==Transfering ||status==Hangup) && dlg.get_uac_trans_method(rep.cseq) == "REFER") { if (rep.code >= 300) { @@ -191,7 +191,7 @@ void AnnounceTransferDialog::onSipReply(const AmSipReply& rep, int old_dlg_statu } } - AmSession::onSipReply(rep, old_dlg_status); + AmSession::onSipReply(rep, old_dlg_status, trans_method); } void AnnounceTransferDialog::onBye(const AmSipRequest& req) diff --git a/apps/announce_transfer/AnnounceTransfer.h b/apps/announce_transfer/AnnounceTransfer.h index b2840401..8849e3f3 100644 --- a/apps/announce_transfer/AnnounceTransfer.h +++ b/apps/announce_transfer/AnnounceTransfer.h @@ -72,7 +72,7 @@ public: void startSession(); void onBye(const AmSipRequest& req); void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& rep, int old_dlg_status); + void onSipReply(const AmSipReply& rep, int old_dlg_status, const string& trans_method); void onDtmf(int event, int duration_msec) {} void process(AmEvent* event); diff --git a/apps/auth_b2b/AuthB2B.cpp b/apps/auth_b2b/AuthB2B.cpp index 9de578c7..45f76a49 100644 --- a/apps/auth_b2b/AuthB2B.cpp +++ b/apps/auth_b2b/AuthB2B.cpp @@ -314,15 +314,15 @@ inline UACAuthCred* AuthB2BCalleeSession::getCredentials() { return &credentials; } -void AuthB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status) { +void AuthB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { if (NULL == auth) { - AmB2BCalleeSession::onSipReply(reply,old_dlg_status); + AmB2BCalleeSession::onSipReply(reply,old_dlg_status,trans_method); return; } unsigned int cseq_before = dlg.cseq; - if (!auth->onSipReply(reply, old_dlg_status)) { - AmB2BCalleeSession::onSipReply(reply,old_dlg_status); + if (!auth->onSipReply(reply, old_dlg_status,trans_method)) { + AmB2BCalleeSession::onSipReply(reply,old_dlg_status,trans_method); } else { if (cseq_before != dlg.cseq) { DBG("uac_auth consumed reply with cseq %d and resent with cseq %d; " diff --git a/apps/auth_b2b/AuthB2B.h b/apps/auth_b2b/AuthB2B.h index 5619a881..7bca232b 100644 --- a/apps/auth_b2b/AuthB2B.h +++ b/apps/auth_b2b/AuthB2B.h @@ -95,7 +95,7 @@ class AuthB2BCalleeSession AmSessionEventHandler* auth; protected: - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method); void onSendRequest(const string& method, const string& content_type, const string& body, string& hdrs, int flags, unsigned int cseq); diff --git a/apps/conference/Conference.cpp b/apps/conference/Conference.cpp index b1b39928..f2ccce0f 100644 --- a/apps/conference/Conference.cpp +++ b/apps/conference/Conference.cpp @@ -862,10 +862,10 @@ void ConferenceDialog::onSipRequest(const AmSipRequest& req) return; } -void ConferenceDialog::onSipReply(const AmSipReply& reply, int old_dlg_status) +void ConferenceDialog::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { int status = dlg.getStatus(); - AmSession::onSipReply(reply,old_dlg_status); + AmSession::onSipReply(reply, old_dlg_status, trans_method); DBG("ConferenceDialog::onSipReply: code = %i, reason = %s\n, status = %i\n", reply.code,reply.reason.c_str(),dlg.getStatus()); diff --git a/apps/conference/Conference.h b/apps/conference/Conference.h index ce284b04..ab00af83 100644 --- a/apps/conference/Conference.h +++ b/apps/conference/Conference.h @@ -153,7 +153,8 @@ public: void onBye(const AmSipRequest& req); void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method); #ifdef WITH_SAS_TTS void onZRTPEvent(zrtp_event_t event, zrtp_stream_ctx_t *stream_ctx); diff --git a/apps/dsm/DSMCall.cpp b/apps/dsm/DSMCall.cpp index 49b3e7d3..9d0fcf7c 100644 --- a/apps/dsm/DSMCall.cpp +++ b/apps/dsm/DSMCall.cpp @@ -287,7 +287,7 @@ void DSMCall::onSipRequest(const AmSipRequest& req) { AmB2BCallerSession::onSipRequest(req); } -void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status) { +void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { if (checkVar(DSM_ENABLE_REPLY_EVENTS, DSM_TRUE)) { map params; @@ -318,7 +318,7 @@ void DSMCall::onSipReply(const AmSipReply& reply, int old_dlg_status) { } } - AmB2BCallerSession::onSipReply(reply,old_dlg_status); + AmB2BCallerSession::onSipReply(reply,old_dlg_status,trans_method); if ((old_dlg_status < AmSipDialog::Connected) && (dlg.getStatus() == AmSipDialog::Disconnected)) { diff --git a/apps/dsm/DSMCall.h b/apps/dsm/DSMCall.h index a7794d7b..c3208588 100644 --- a/apps/dsm/DSMCall.h +++ b/apps/dsm/DSMCall.h @@ -83,7 +83,7 @@ public: void onDtmf(int event, int duration_msec); void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method); void process(AmEvent* event); diff --git a/apps/examples/b2b_connect/b2b_connect.cpp b/apps/examples/b2b_connect/b2b_connect.cpp index bde20ab0..62ee1f27 100644 --- a/apps/examples/b2b_connect/b2b_connect.cpp +++ b/apps/examples/b2b_connect/b2b_connect.cpp @@ -286,8 +286,10 @@ inline UACAuthCred* b2b_connectCalleeSession::getCredentials() { return &credentials; } -void b2b_connectCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status) { - AmB2ABCalleeSession::onSipReply(reply, old_dlg_status); +void b2b_connectCalleeSession::onSipReply(const AmSipReply& reply, + int old_dlg_status, + const string& trans_method) { + AmB2ABCalleeSession::onSipReply(reply, old_dlg_status, trans_method); if ((old_dlg_status == AmSipDialog::Pending)&& (dlg.getStatus() == AmSipDialog::Disconnected)) { diff --git a/apps/examples/b2b_connect/b2b_connect.h b/apps/examples/b2b_connect/b2b_connect.h index 83d39bc2..b7722743 100644 --- a/apps/examples/b2b_connect/b2b_connect.h +++ b/apps/examples/b2b_connect/b2b_connect.h @@ -88,7 +88,8 @@ class b2b_connectCalleeSession AmSipRequest invite_req; protected: - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method); public: b2b_connectCalleeSession(const string& other_tag, diff --git a/apps/gateway/GWSession.cpp b/apps/gateway/GWSession.cpp index 38e2482e..5720d33a 100644 --- a/apps/gateway/GWSession.cpp +++ b/apps/gateway/GWSession.cpp @@ -90,7 +90,7 @@ void GWSession::onSipRequest(const AmSipRequest& req) } } -void GWSession::onSipReply(const AmSipReply& reply, int old_dlg_status) { +void GWSession::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { int status = dlg.getStatus(); DBG("GWSession::onSipReply: code = %i, reason = %s\n, status = %i\n", reply.code,reply.reason.c_str(),dlg.getStatus()); @@ -99,7 +99,7 @@ void GWSession::onSipReply(const AmSipReply& reply, int old_dlg_status) { int ret=((mISDNChannel*)m_OtherLeg)->hangup(); } DBG("GWSession::onSipReply calling parent\n"); - AmSession::onSipReply(reply, old_dlg_status); + AmSession::onSipReply(reply, old_dlg_status, trans_method); } void GWSession::on_stop() { diff --git a/apps/gateway/GWSession.h b/apps/gateway/GWSession.h index 535a6cfa..8126f782 100644 --- a/apps/gateway/GWSession.h +++ b/apps/gateway/GWSession.h @@ -33,7 +33,7 @@ static GWSession* CallFromOutside(std::string &fromnumber, std::string &tonum void onBye(const AmSipRequest& req); //virtual void onSipEvent(AmSipEvent* sip_ev); void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method); //virtual void onRtpTimeout(); //virtual void onSendRequest(const string& method, const string& content_type, const string& body, string& hdrs, int flags, unsigned int cseq); //virtual void onSendReply(const AmSipRequest& req, unsigned int code,const string& reason,const string& content_type, const string& body,string& hdrs,int flags) diff --git a/apps/ivr/Ivr.cpp b/apps/ivr/Ivr.cpp index 89f31b33..37a66b32 100644 --- a/apps/ivr/Ivr.cpp +++ b/apps/ivr/Ivr.cpp @@ -749,11 +749,11 @@ void safe_Py_DECREF(PyObject* pyo) { Py_DECREF(pyo); } -void IvrDialog::onSipReply(const AmSipReply& r, int old_dlg_status) { +void IvrDialog::onSipReply(const AmSipReply& r, int old_dlg_status, const string& trans_method) { PyObject* pyo = getPySipReply(r); callPyEventHandler("onSipReply","(O)", pyo); safe_Py_DECREF(pyo); - AmB2BSession::onSipReply(r,old_dlg_status); + AmB2BSession::onSipReply(r,old_dlg_status,trans_method); } void IvrDialog::onSipRequest(const AmSipRequest& r){ diff --git a/apps/ivr/Ivr.h b/apps/ivr/Ivr.h index b2ba8f6d..bd87c720 100644 --- a/apps/ivr/Ivr.h +++ b/apps/ivr/Ivr.h @@ -149,7 +149,7 @@ class IvrDialog : public AmB2BCallerSession void onOtherBye(const AmSipRequest& req); bool onOtherReply(const AmSipReply& r); - void onSipReply(const AmSipReply& r,int old_dlg_status); + void onSipReply(const AmSipReply& r,int old_dlg_status, const string& trans_method); void onSipRequest(const AmSipRequest& r); void onRtpTimeout(); diff --git a/apps/registrar_client/SIPRegistrarClient.cpp b/apps/registrar_client/SIPRegistrarClient.cpp index 914bb930..770a4f44 100644 --- a/apps/registrar_client/SIPRegistrarClient.cpp +++ b/apps/registrar_client/SIPRegistrarClient.cpp @@ -369,9 +369,9 @@ bool SIPRegistration::registerExpired(time_t now_sec) { return ((reg_begin+reg_expires) < (unsigned int)now_sec); } -void SIPRegistration::onSipReply(const AmSipReply& reply, int old_dlg_status) +void SIPRegistration::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { - if ((seh!=NULL) && seh->onSipReply(reply, old_dlg_status)) + if ((seh!=NULL) && seh->onSipReply(reply, old_dlg_status, trans_method)) return; waiting_result = false; @@ -498,7 +498,7 @@ void SIPRegistrarClient::onRemoveRegistration(SIPRemoveRegistrationEvent* new_re void SIPRegistrarClient::on_stop() { } -bool SIPRegistrarClient::onSipReply(const AmSipReply& rep) { +bool SIPRegistrarClient::onSipReply(const AmSipReply& rep, int old_dlg_status, const string& trans_method) { DBG("got reply with tag '%s'\n", rep.local_tag.c_str()); if (instance()->hasRegistration(rep.local_tag)) { diff --git a/apps/registrar_client/SIPRegistrarClient.h b/apps/registrar_client/SIPRegistrarClient.h index e79af3bf..5bcfef00 100644 --- a/apps/registrar_client/SIPRegistrarClient.h +++ b/apps/registrar_client/SIPRegistrarClient.h @@ -124,7 +124,7 @@ class SIPRegistration : public AmSipDialogEventHandler, // CredentialHolder UACAuthCred* getCredentials() { return &cred; } - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method); void onSipRequest(const AmSipRequest& req) {} void onInvite2xx(const AmSipReply&) {} void onNoAck(unsigned int) {} @@ -192,7 +192,7 @@ class SIPRegistrarClient : public AmThread, void invoke(const string& method, const AmArg& args, AmArg& ret); - bool onSipReply(const AmSipReply& rep); + bool onSipReply(const AmSipReply& rep, int old_dlg_status, const string& trans_method); int onLoad(); void run(); diff --git a/apps/sst_b2b/SSTB2B.cpp b/apps/sst_b2b/SSTB2B.cpp index bd8425c7..05271215 100644 --- a/apps/sst_b2b/SSTB2B.cpp +++ b/apps/sst_b2b/SSTB2B.cpp @@ -132,25 +132,10 @@ void SSTB2BDialog::onInvite(const AmSipRequest& req) recvd_req.insert(std::make_pair(req.cseq,req)); set_sip_relay_only(true); - DBG("##### connecting to <%s>",req.r_uri.c_str()); + DBG("##### connecting to <%s> #####\n",req.r_uri.c_str()); connectCallee("<" + req.r_uri + ">", req.r_uri, true); } -void SSTB2BDialog::sendReinvite(bool updateSDP, const string& headers) { - if (sip_relay_only) { - // we send empty reinvite - DBG("sending empty reinvite in callee session\n"); - dlg.reinvite(headers, "", ""); - } else { - AmB2BCallerSession::sendReinvite(updateSDP, headers); - } - - // // we send empty reinvite - // dlg.reinvite(headers, "", ""); - // we send reinvite with the last body we got from the other side - // last_otherleg_content_type, last_otherleg_body); -} - void SSTB2BDialog::process(AmEvent* ev) { AmB2BCallerSession::process(ev); @@ -171,7 +156,8 @@ void SSTB2BDialog::onSipRequest(const AmSipRequest& req) { AmB2BCallerSession::onSipRequest(req); } -void SSTB2BDialog::onSipReply(const AmSipReply& reply, int old_dlg_status) +void SSTB2BDialog::onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method) { TransMap::iterator t = relayed_req.find(reply.cseq); bool fwd = t != relayed_req.end(); @@ -179,10 +165,10 @@ void SSTB2BDialog::onSipReply(const AmSipReply& reply, int old_dlg_status) DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd); DBG("onSipReply: content-type = %s\n",reply.content_type.c_str()); if (fwd) { - CALL_EVENT_H(onSipReply,reply, old_dlg_status); + CALL_EVENT_H(onSipReply,reply, old_dlg_status, trans_method); } - AmB2BCallerSession::onSipReply(reply,old_dlg_status); + AmB2BCallerSession::onSipReply(reply,old_dlg_status, trans_method); } bool SSTB2BDialog::onOtherReply(const AmSipReply& reply) @@ -344,7 +330,8 @@ void SSTB2BCalleeSession::onSipRequest(const AmSipRequest& req) { AmB2BCalleeSession::onSipRequest(req); } -void SSTB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status) +void SSTB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method) { // call event handlers where it is not done TransMap::iterator t = relayed_req.find(reply.cseq); @@ -352,17 +339,17 @@ void SSTB2BCalleeSession::onSipReply(const AmSipReply& reply, int old_dlg_status DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd); DBG("onSipReply: content-type = %s\n",reply.content_type.c_str()); if(fwd) { - CALL_EVENT_H(onSipReply,reply, old_dlg_status); + CALL_EVENT_H(onSipReply,reply, old_dlg_status, trans_method); } if (NULL == auth) { - AmB2BCalleeSession::onSipReply(reply,old_dlg_status); + AmB2BCalleeSession::onSipReply(reply,old_dlg_status, trans_method); return; } unsigned int cseq_before = dlg.cseq; - if (!auth->onSipReply(reply, old_dlg_status)) { - AmB2BCalleeSession::onSipReply(reply,old_dlg_status); + if (!auth->onSipReply(reply, old_dlg_status, trans_method)) { + AmB2BCalleeSession::onSipReply(reply, old_dlg_status, trans_method); } else { if (cseq_before != dlg.cseq) { DBG("uac_auth consumed reply with cseq %d and resent with cseq %d; " @@ -390,13 +377,3 @@ void SSTB2BCalleeSession::onSendRequest(const string& method, const string& cont body, hdrs, flags, cseq); } -void SSTB2BCalleeSession::sendReinvite(bool updateSDP, const string& headers) { - if (sip_relay_only) { - // we send empty reinvite - DBG("sending empty reinvite in callee session\n"); - dlg.reinvite(headers, "", ""); - } else { - AmB2BCalleeSession::sendReinvite(updateSDP, headers); - } -} - diff --git a/apps/sst_b2b/SSTB2B.h b/apps/sst_b2b/SSTB2B.h index 2d6aa0f0..69a2aaf6 100644 --- a/apps/sst_b2b/SSTB2B.h +++ b/apps/sst_b2b/SSTB2B.h @@ -90,10 +90,9 @@ class SSTB2BDialog : public AmB2BCallerSession void onInvite(const AmSipRequest& req); void onCancel(); - void sendReinvite(bool updateSDP, const string& headers); - protected: - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method); void onSipRequest(const AmSipRequest& req); protected: @@ -115,7 +114,8 @@ class SSTB2BCalleeSession protected: void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method); void onSendRequest(const string& method, const string& content_type, const string& body, string& hdrs, int flags, unsigned int cseq); @@ -128,7 +128,5 @@ class SSTB2BCalleeSession inline UACAuthCred* getCredentials(); void setAuthHandler(AmSessionEventHandler* h) { auth = h; } - - void sendReinvite(bool updateSDP, const string& headers); }; #endif diff --git a/apps/webconference/WebConferenceDialog.cpp b/apps/webconference/WebConferenceDialog.cpp index 229d44cc..0fe4d85c 100644 --- a/apps/webconference/WebConferenceDialog.cpp +++ b/apps/webconference/WebConferenceDialog.cpp @@ -173,11 +173,11 @@ void WebConferenceDialog::onSessionStart(const AmSipReply& rep) { connectConference(dlg.user); } -void WebConferenceDialog::onSipReply(const AmSipReply& reply, int old_dlg_status) +void WebConferenceDialog::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { //int status = dlg.getStatus(); - AmSession::onSipReply(reply,old_dlg_status); + AmSession::onSipReply(reply,old_dlg_status,trans_method); DBG("reply: %u %s, old_dlg_status = %s, status = %s\n", reply.code, reply.reason.c_str(), diff --git a/apps/webconference/WebConferenceDialog.h b/apps/webconference/WebConferenceDialog.h index 203dee43..ea36c26b 100644 --- a/apps/webconference/WebConferenceDialog.h +++ b/apps/webconference/WebConferenceDialog.h @@ -94,7 +94,7 @@ public: ~WebConferenceDialog(); void process(AmEvent* ev); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method); void onSessionStart(const AmSipRequest& req); void onSessionStart(const AmSipReply& rep); void onEarlySessionStart(const AmSipReply& rep); diff --git a/core/AmB2ABSession.cpp b/core/AmB2ABSession.cpp index 89e7d7c5..82c95d76 100644 --- a/core/AmB2ABSession.cpp +++ b/core/AmB2ABSession.cpp @@ -353,13 +353,13 @@ void AmB2ABCalleeSession::onSessionStart(const AmSipReply& rep) { relayEvent(new B2ABConnectAudioEvent()); } -void AmB2ABCalleeSession::onSipReply(const AmSipReply& rep, int old_dlg_status) { - - int status_before = old_dlg_status;//dlg.getStatus(); - AmB2ABSession::onSipReply(rep, old_dlg_status); +void AmB2ABCalleeSession::onSipReply(const AmSipReply& rep, + int old_dlg_status, + const string& trans_method) { + AmB2ABSession::onSipReply(rep, old_dlg_status, trans_method); int status = dlg.getStatus(); - if ((status_before == AmSipDialog::Pending)&& + if ((old_dlg_status == AmSipDialog::Pending)&& (status == AmSipDialog::Disconnected)) { DBG("callee session creation failed. notifying caller session.\n"); diff --git a/core/AmB2ABSession.h b/core/AmB2ABSession.h index ad05edb0..1827e5c6 100644 --- a/core/AmB2ABSession.h +++ b/core/AmB2ABSession.h @@ -247,7 +247,8 @@ class AmB2ABCalleeSession: public AmB2ABSession void onEarlySessionStart(const AmSipReply& rep); void onSessionStart(const AmSipReply& rep); - void onSipReply(const AmSipReply& rep, int old_dlg_status); + void onSipReply(const AmSipReply& rep, int old_dlg_status, + const string& trans_method); protected: void onB2ABEvent(B2ABEvent* ev); diff --git a/core/AmB2BSession.cpp b/core/AmB2BSession.cpp index 27439fdd..671147a9 100644 --- a/core/AmB2BSession.cpp +++ b/core/AmB2BSession.cpp @@ -90,6 +90,16 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev) assert(req_ev); if(req_ev->forward){ + if (req_ev->req.method == SIP_METH_INVITE && + dlg.getUACInvTransPending()) { + // don't relay INVITE if INV trans pending + AmSipReply n_reply; + n_reply.code = 491; + n_reply.reason = "Request Pending"; + n_reply.cseq = req_ev->req.cseq; + relayEvent(new B2BSipReplyEvent(n_reply, true, SIP_METH_INVITE)); + return; + } relaySip(req_ev->req); } @@ -106,19 +116,21 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev) B2BSipReplyEvent* reply_ev = dynamic_cast(ev); assert(reply_ev); - DBG("B2BSipReply: %i %s (fwd=%i)\n",reply_ev->reply.code, - reply_ev->reply.reason.c_str(),reply_ev->forward); + DBG("B2BSipReply: %i %s (fwd=%s)\n",reply_ev->reply.code, + reply_ev->reply.reason.c_str(),reply_ev->forward?"true":"false"); DBG("B2BSipReply: content-type = %s\n",reply_ev->reply.content_type.c_str()); if(reply_ev->forward){ - std::map::iterator t_req = recvd_req.find(reply_ev->reply.cseq); + std::map::iterator t_req = + recvd_req.find(reply_ev->reply.cseq); + if (t_req != recvd_req.end()) { relaySip(t_req->second,reply_ev->reply); if(reply_ev->reply.code >= 200){ - if( (t_req->second.method == "INVITE") && + if( (t_req->second.method == SIP_METH_INVITE) && (reply_ev->reply.code == 487)){ terminateLeg(); @@ -129,6 +141,24 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev) ERROR("Request with CSeq %u not found in recvd_req.\n", reply_ev->reply.cseq); } + } else { + // check whether not-forwarded (locally initiated) + // INV/UPD transaction changed session in other leg + if (SIP_IS_200_CLASS(reply_ev->reply.code) && + (!reply_ev->reply.body.empty()) && + (reply_ev->reply.method == SIP_METH_INVITE || + reply_ev->reply.method == SIP_METH_UPDATE)) { + if (updateSessionDescription(reply_ev->reply.content_type, + reply_ev->reply.body)) { + if (dlg.getUACInvTransPending()) { + DBG("changed session, but UAC INVITE trans pending\n"); + // todo(?): save until trans is finished? + return; + } + DBG("session description changed - refreshing\n"); + sendEstablishedReInvite(); + } + } } } return; @@ -137,44 +167,6 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev) terminateLeg(); break; - case B2BMsgBody: - { - if (!sip_relay_only) { - ERROR("relayed message body received but not in sip_relay_only mode\n"); - return; - } - - B2BMsgBodyEvent* body_ev = dynamic_cast(ev); - assert(body_ev); - - DBG("received B2B Msg body event; is_offer=%s, r_cseq=%d\n", - body_ev->is_offer?"true":"false", body_ev->r_cseq); - - if (body_ev->is_offer) { - // send INVITE with SDP - trans_ticket tt; // empty transaction ticket - relayed_body_req[dlg.cseq] = AmSipTransaction("INVITE", body_ev->r_cseq, tt); - if (dlg.reinvite("", body_ev->content_type, body_ev->body)) { - ERROR("sending reinvite with relayed body\n"); - relayed_body_req.erase(dlg.cseq); - // TODO?: relay error back instead? - // tear down: - DBG("error sending reinvite - terminating this and the other leg\n"); - terminateOtherLeg(); - terminateLeg(); - } - } else { - // is_answer - send 200 ACK - // todo: use that from uas_trans? - trans_ticket tt; // not used for ACK - AmSipTransaction trans("INVITE", body_ev->r_cseq, tt); - if (dlg.send_200_ack(trans, body_ev->content_type, body_ev->body, - "" /* hdrs - todo */, SIP_FLAGS_VERBATIM)) { - ERROR("sending ACK with SDP\n"); - } - } - return; - }; break; } //ERROR("unknown event caught\n"); @@ -189,7 +181,6 @@ void AmB2BSession::onSipRequest(const AmSipRequest& req) if(!fwd) AmSession::onSipRequest(req); else { - //dlg.updateStatus(req); updateRefreshMethod(req.hdrs); recvd_req.insert(std::make_pair(req.cseq,req)); } @@ -197,73 +188,33 @@ void AmB2BSession::onSipRequest(const AmSipRequest& req) relayEvent(new B2BSipRequestEvent(req,fwd)); } -void AmB2BSession::onSipReply(const AmSipReply& reply, int old_dlg_status) +void AmB2BSession::onSipReply(const AmSipReply& reply, + int old_dlg_status, + const string& trans_method) { - updateRefreshMethod(reply.hdrs); - TransMap::iterator t = relayed_req.find(reply.cseq); bool fwd = (t != relayed_req.end()) && (reply.code != 100); - DBG("onSipReply: %i %s (fwd=%i)\n",reply.code,reply.reason.c_str(),fwd); + DBG("onSipReply: %s -> %i %s (fwd=%s)\n", + trans_method.c_str(), reply.code,reply.reason.c_str(),fwd?"true":"false"); DBG("onSipReply: content-type = %s\n",reply.content_type.c_str()); if(fwd) { + updateRefreshMethod(reply.hdrs); + AmSipReply n_reply = reply; n_reply.cseq = t->second.cseq; - //dlg.updateStatus(reply, false); - relayEvent(new B2BSipReplyEvent(n_reply,true)); + relayEvent(new B2BSipReplyEvent(n_reply, true, t->second.method)); if(reply.code >= 200) { - if ((reply.code < 300) && (t->second.method == "INVITE")) { + if ((reply.code < 300) && (t->second.method == SIP_METH_INVITE)) { DBG("not removing relayed INVITE transaction yet...\n"); } else relayed_req.erase(t); } } else { - string trans_method = dlg.get_uac_trans_method(reply.cseq); - - bool relay_body = - // is a reply to request we sent, - // even though we are in sip_relay_only mode - (sip_relay_only && - // positive reply - (200 <= reply.code) && (reply.code < 300) && - // with body - !reply.body.empty() && - trans_method == SIP_METH_INVITE); - - if (relay_body) { - // is it an answer to a relayed body, or an answer to empty re-INVITE? - TransMap::iterator rel_body_it = relayed_body_req.find(reply.cseq); - bool is_offer = (rel_body_it == relayed_body_req.end()); - // answer to empty re-INVITE we have sent - relayEvent(new B2BMsgBodyEvent(reply.content_type, reply.body, - is_offer, is_offer ? reply.cseq : rel_body_it->second.cseq)); - - if (is_offer) { - // onSipReply from AmSession without do_200_ack in dlg.updateStatus(reply) - // todo (?): add do_200_ack flag to AmSession::onSipReply and call AmSession::onSipReply - CALL_EVENT_H(onSipReply,reply,old_dlg_status); - - //int status = dlg.getStatus(); - //dlg.updateStatus(reply, false); - - if (old_dlg_status != dlg.getStatus()) - DBG("Dialog status changed %s -> %s (stopped=%s) \n", - AmSipDialog::status2str[old_dlg_status], - AmSipDialog::status2str[dlg.getStatus()], - getStopped() ? "true" : "false"); - else - DBG("Dialog status stays %s (stopped=%s)\n", AmSipDialog::status2str[old_dlg_status], - getStopped() ? "true" : "false"); - } else { - relayed_body_req.erase(rel_body_it); - AmSession::onSipReply(reply, old_dlg_status); - } - } else { - AmSession::onSipReply(reply, old_dlg_status); - } - relayEvent(new B2BSipReplyEvent(reply,false)); + AmSession::onSipReply(reply, old_dlg_status, trans_method); + relayEvent(new B2BSipReplyEvent(reply, false, trans_method)); } } @@ -325,12 +276,97 @@ void AmB2BSession::onSessionTimeout() { AmSession::onSessionTimeout(); } +void AmB2BSession::saveSessionDescription(const string& content_type, + const string& body) { + DBG("saving session description (%s, %.*s...)\n", + content_type.c_str(), 50, body.c_str()); + established_content_type = content_type; + established_body = body; + + const char* cmp_body_begin = body.c_str(); + size_t cmp_body_length = body.length(); + if (content_type == SIP_APPLICATION_SDP) { + // for SDP, skip v and o line + // (o might change even if SDP unchanged) +#define skip_line \ + while (cmp_body_length-- && *cmp_body_begin != '\n') \ + cmp_body_begin++; \ + cmp_body_begin++; \ + + skip_line; + skip_line; + } + + body_hash = hashlittle(cmp_body_begin, cmp_body_length, 0); +} + +bool AmB2BSession::updateSessionDescription(const string& content_type, + const string& body) { + const char* cmp_body_begin = body.c_str(); + size_t cmp_body_length = body.length(); + if (content_type == SIP_APPLICATION_SDP) { + // for SDP, skip v and o line + // (o might change even if SDP unchanged) + skip_line; + skip_line; + } + +#undef skip_line + + uint32_t new_body_hash = hashlittle(cmp_body_begin, cmp_body_length, 0); + + if (body_hash != new_body_hash) { + DBG("session description changed - saving (%s, %.*s...)\n", + content_type.c_str(), 50, body.c_str()); + body_hash = new_body_hash; + established_content_type = content_type; + established_body = body; + return true; + } + + return false; +} + +int AmB2BSession::sendEstablishedReInvite() { + if (established_content_type.empty() || established_body.empty()) { + ERROR("trying to re-INVITE with saved description, but none saved\n"); + return -1; + } + + DBG("sending re-INVITE with saved session description\n"); + return dlg.reinvite(get_100rel_hdr(reliable_1xx), + established_content_type, established_body); +} + +bool AmB2BSession::refresh() { + // not in B2B mode + if (other_id.empty() || + // UPDATE as refresh handled like normal session + refresh_method == REFRESH_UPDATE) { + return AmSession::refresh(); + } + + // refresh with re-INVITE + if (dlg.getUACInvTransPending()) { + DBG("INVITE transaction pending - not refreshing now\n"); + return false; + } + return sendEstablishedReInvite() == 0; +} + void AmB2BSession::relaySip(const AmSipRequest& req) { if (req.method != "ACK") { relayed_req[dlg.cseq] = AmSipTransaction(req.method,req.cseq,req.tt); dlg.sendRequest(req.method,req.content_type, req.body, req.hdrs, SIP_FLAGS_VERBATIM); // todo: relay error event back if sending fails + + if ((req.method == SIP_METH_INVITE || + req.method == SIP_METH_UPDATE) && + !req.body.empty()) { + saveSessionDescription(req.content_type, req.body); + } + } else { //its a (200) ACK TransMap::iterator t = relayed_req.begin(); @@ -344,9 +380,16 @@ void AmB2BSession::relaySip(const AmSipRequest& req) ERROR("transaction for ACK not found in relayed requests\n"); return; } + DBG("sending relayed ACK\n"); dlg.send_200_ack(AmSipTransaction(t->second.method, t->first,t->second.tt), req.content_type, req.body, req.hdrs, SIP_FLAGS_VERBATIM); + + if (!req.body.empty() && t->second.method == SIP_METH_INVITE) { + // delayed SDP negotiation - save SDP + saveSessionDescription(req.content_type, req.body); + } + relayed_req.erase(t); } } @@ -356,6 +399,13 @@ void AmB2BSession::relaySip(const AmSipRequest& orig, const AmSipReply& reply) dlg.reply(orig,reply.code,reply.reason, reply.content_type, reply.body,reply.hdrs,SIP_FLAGS_VERBATIM); + + if ((orig.method == SIP_METH_INVITE || + orig.method == SIP_METH_UPDATE) && + !reply.body.empty()) { + saveSessionDescription(reply.content_type, reply.body); + } + } // @@ -411,7 +461,8 @@ void AmB2BCallerSession::onB2BEvent(B2BEvent* ev) if ((!sip_relay_only) && sip_relay_early_media_sdp && reply.code>=180 && reply.code<=183 && (!reply.body.empty())) { if (reinviteCaller(reply)) { - ERROR("re-INVITEing caller for early session - stopping this and other leg\n"); + ERROR("re-INVITEing caller for early session - " + "stopping this and other leg\n"); terminateOtherLeg(); terminateLeg(); } @@ -500,7 +551,9 @@ void AmB2BCallerSession::connectCallee(const string& remote_party, int AmB2BCallerSession::reinviteCaller(const AmSipReply& callee_reply) { - return dlg.sendRequest("INVITE",callee_reply.content_type,callee_reply.body, "", SIP_FLAGS_VERBATIM); + return dlg.sendRequest(SIP_METH_INVITE, + callee_reply.content_type, callee_reply.body, + "" /* hdrs */, SIP_FLAGS_VERBATIM); } void AmB2BCallerSession::createCalleeSession() { @@ -572,12 +625,17 @@ void AmB2BCalleeSession::onB2BEvent(B2BEvent* ev) dlg.remote_uri = co_ev->remote_uri; if (co_ev->relayed_invite) { - relayed_req[dlg.cseq] = AmSipTransaction("INVITE", co_ev->r_cseq, trans_ticket()); + relayed_req[dlg.cseq] = + AmSipTransaction(SIP_METH_INVITE, co_ev->r_cseq, trans_ticket()); } - dlg.sendRequest("INVITE",co_ev->content_type,co_ev->body,co_ev->hdrs,SIP_FLAGS_VERBATIM); + dlg.sendRequest(SIP_METH_INVITE, + co_ev->content_type, co_ev->body, + co_ev->hdrs, SIP_FLAGS_VERBATIM); // todo: relay error event back if sending fails + saveSessionDescription(co_ev->content_type, co_ev->body); + return; } diff --git a/core/AmB2BSession.h b/core/AmB2BSession.h index 9b8d7dcb..1dc4e7a1 100644 --- a/core/AmB2BSession.h +++ b/core/AmB2BSession.h @@ -30,6 +30,7 @@ #include "AmSession.h" #include "AmSipDialog.h" +#include "sip/hash.h" enum { B2BTerminateLeg, B2BConnectLeg, @@ -65,18 +66,20 @@ struct B2BSipRequestEvent: public B2BSipEvent B2BSipRequestEvent(const AmSipRequest& req, bool forward) : B2BSipEvent(B2BSipRequest,forward), req(req) - {} + { } }; /** \brief SIP reply in B2B session */ struct B2BSipReplyEvent: public B2BSipEvent { AmSipReply reply; + string trans_method; - B2BSipReplyEvent(const AmSipReply& reply, bool forward) - : B2BSipEvent(B2BSipReply,forward), - reply(reply) - {} + B2BSipReplyEvent(const AmSipReply& reply, bool forward, + string trans_method) + : B2BSipEvent(B2BSipReply,forward), + reply(reply), trans_method(trans_method) + { } }; /** \brief relay a message body to other leg in B2B session */ @@ -84,17 +87,10 @@ struct B2BMsgBodyEvent : public B2BEvent { string content_type; string body; - bool is_offer; - unsigned int r_cseq; - - B2BMsgBodyEvent(const string& content_type, - const string& body, - bool is_offer, - unsigned int r_cseq) + B2BMsgBodyEvent(const string& content_type, + const string& body) : B2BEvent(B2BMsgBody), - content_type(content_type), body(body), - is_offer(is_offer), r_cseq(r_cseq) { - } + content_type(content_type), body(body) { } ~B2BMsgBodyEvent() { } }; @@ -124,7 +120,8 @@ struct B2BConnectEvent: public B2BEvent /** * \brief Base class for Sessions in B2BUA mode. * - * It has two legs: Callee- and caller-leg. + * It has two legs as independent sessions: + * Callee- and caller-leg. */ class AmB2BSession: public AmSession { @@ -134,32 +131,40 @@ class AmB2BSession: public AmSession /** Tell if the session should * process SIP request itself - * or only relay them. + * or only relay them (B2B mode). */ bool sip_relay_only; /** - * Requests which - * have been relayed (sent) + * Requests which have been relayed + * from the other leg and sent as SIP */ TransMap relayed_req; - /** - * Requests which have been originated - * from local dialog but with - * relayed body - */ - TransMap relayed_body_req; - /** Requests received for relaying */ std::map recvd_req; + /** content-type of established session */ + string established_content_type; + /** body of established session */ + string established_body; + /** hash of body (from o-line) */ + uint32_t body_hash; + /** save current session description (SDP) */ + void saveSessionDescription(const string& content_type, const string& body); + /** @return whether session has changed */ + bool updateSessionDescription(const string& content_type, const string& body); + + /** reset relation with other leg */ void clear_other(); /** Relay one event to the other side. */ virtual void relayEvent(AmEvent* ev); + /** send a relayed SIP Request */ void relaySip(const AmSipRequest& req); + + /** send a relayed SIP Reply */ void relaySip(const AmSipRequest& orig, const AmSipReply& reply); /** Terminate our leg and forget the other. */ @@ -170,18 +175,27 @@ class AmB2BSession: public AmSession /** @see AmSession */ void onSipRequest(const AmSipRequest& req); - void onSipReply(const AmSipReply& reply, int old_dlg_status); + void onSipReply(const AmSipReply& reply, + int old_dlg_status, const string& trans_method); void onInvite2xx(const AmSipReply& reply); void onSessionTimeout(); + /** send re-INVITE with established session description + * @return 0 on success + */ + int sendEstablishedReInvite(); + + /** do session refresh */ + bool refresh(); + /** @see AmEventQueue */ void process(AmEvent* event); /** B2BEvent handler */ virtual void onB2BEvent(B2BEvent* ev); - // Other leg received a BYE + /** handle BYE on other leg */ virtual void onOtherBye(const AmSipRequest& req); /** diff --git a/core/AmSession.cpp b/core/AmSession.cpp index 5e340e58..060276e9 100644 --- a/core/AmSession.cpp +++ b/core/AmSession.cpp @@ -36,7 +36,6 @@ #include "AmMediaProcessor.h" #include "AmDtmfDetector.h" #include "AmPlayoutBuffer.h" -#include "AmSipHeaders.h" #ifdef WITH_ZRTP #include "AmZRTP.h" @@ -774,9 +773,10 @@ void AmSession::onSipRequest(const AmSipRequest& req) } } -void AmSession::onSipReply(const AmSipReply& reply, int old_dlg_status) +void AmSession::onSipReply(const AmSipReply& reply, + int old_dlg_status, const string& trans_method) { - CALL_EVENT_H(onSipReply,reply,old_dlg_status); + CALL_EVENT_H(onSipReply, reply, old_dlg_status, trans_method); updateRefreshMethod(reply.hdrs); @@ -786,7 +786,8 @@ void AmSession::onSipReply(const AmSipReply& reply, int old_dlg_status) AmSipDialog::status2str[dlg.getStatus()], sess_stopped.get() ? "true" : "false"); else - DBG("Dialog status stays %s (stopped=%s)\n", AmSipDialog::status2str[old_dlg_status], + DBG("Dialog status stays %s (stopped=%s)\n", + AmSipDialog::status2str[old_dlg_status], sess_stopped.get() ? "true" : "false"); @@ -953,7 +954,7 @@ void AmSession::onInvite(const AmSipRequest& req) acceptAudio(req.body,req.hdrs,&sdp_reply); if(dlg.reply(req,200,"OK", - "application/sdp",sdp_reply) != 0) + SIP_APPLICATION_SDP, sdp_reply) != 0) throw AmSession::Exception(500,"could not send response"); }catch(const AmSession::Exception& e){ @@ -1103,20 +1104,26 @@ void AmSession::updateRefreshMethod(const string& headers) { } } -void AmSession::refresh() { +bool AmSession::refresh() { if (refresh_method == REFRESH_UPDATE) { DBG("Refreshing session with UPDATE\n"); - sendUpdate("", "", ""); + return sendUpdate("", "", "") == 0; } else { + + if (dlg.getUACInvTransPending()) { + DBG("INVITE transaction pending - not refreshing now\n"); + return false; + } + DBG("Refreshing session with re-INVITE\n"); - sendReinvite(true); + return sendReinvite(true) == 0; } } -void AmSession::sendUpdate(const string &cont_type, const string &body, +int AmSession::sendUpdate(const string &cont_type, const string &body, const string &hdrs) { - dlg.update(cont_type, body, hdrs); + return dlg.update(cont_type, body, hdrs); } void AmSession::sendPrack(const string &sdp_offer, @@ -1141,32 +1148,16 @@ string AmSession::sid4dbg() return dbg; } -static inline string get_100rel_hdr(unsigned char reliable_1xx) -{ - switch(reliable_1xx) { - case REL100_SUPPORTED: - return SIP_HDR_COLSP(SIP_HDR_SUPPORTED) SIP_EXT_100REL CRLF; - case REL100_REQUIRE: - return SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF; - default: - ERROR("BUG: unexpected reliability switch value of '%d'.\n", - reliable_1xx); - case 0: - break; - } - return ""; -} - -void AmSession::sendReinvite(bool updateSDP, const string& headers) +int AmSession::sendReinvite(bool updateSDP, const string& headers) { if (updateSDP) { RTPStream()->setLocalIP(AmConfig::LocalIP); string sdp_body; sdp.genResponse(advertisedIP(), RTPStream()->getLocalPort(), sdp_body); - dlg.reinvite(headers + get_100rel_hdr(reliable_1xx), "application/sdp", + return dlg.reinvite(headers + get_100rel_hdr(reliable_1xx), SIP_APPLICATION_SDP, sdp_body); } else { - dlg.reinvite(headers + get_100rel_hdr(reliable_1xx), "", ""); + return dlg.reinvite(headers + get_100rel_hdr(reliable_1xx), "", ""); } } @@ -1181,7 +1172,7 @@ int AmSession::sendInvite(const string& headers) // Generate SDP. string sdp_body; sdp.genRequest(advertisedIP(), RTPStream()->getLocalPort(), sdp_body); - return dlg.invite(headers + get_100rel_hdr(reliable_1xx), "application/sdp", + return dlg.invite(headers + get_100rel_hdr(reliable_1xx), SIP_APPLICATION_SDP, sdp_body); } diff --git a/core/AmSession.h b/core/AmSession.h index c3c174f5..fcd61ad2 100644 --- a/core/AmSession.h +++ b/core/AmSession.h @@ -34,6 +34,7 @@ #include "AmRtpAudio.h" #include "AmDtmfDetector.h" #include "AmSipMsg.h" +#include "AmSipHeaders.h" #include "AmSipDialog.h" #include "AmSipEvent.h" #include "AmApi.h" @@ -360,13 +361,13 @@ public: string* sdp_reply); /** refresh the session - re-INVITE or UPDATE*/ - virtual void refresh(); + virtual bool refresh(); /** send an UPDATE in the session */ - virtual void sendUpdate(const string &cont_type, const string &body, const string &hdrs); + virtual int sendUpdate(const string &cont_type, const string &body, const string &hdrs); /** send a Re-INVITE (if connected) */ - virtual void sendReinvite(bool updateSDP = true, const string& headers = ""); + virtual int sendReinvite(bool updateSDP = true, const string& headers = ""); /** send an INVITE */ virtual int sendInvite(const string& headers = ""); @@ -521,7 +522,8 @@ public: virtual void onSipRequest(const AmSipRequest& req); /** Entry point for SIP Replies */ - virtual void onSipReply(const AmSipReply& reply, int old_dlg_status); + virtual void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method); /** 2xx reply has been received for an INVITE transaction */ virtual void onInvite2xx(const AmSipReply& reply); @@ -586,6 +588,7 @@ public: // The IP address to put as c= in SDP bodies and to use for Contact:. string advertisedIP(); + /** format session id for debugging */ string sid4dbg(); }; @@ -598,6 +601,22 @@ inline AmRtpAudio* AmSession::RTPStream() { return _rtp_str.get(); } +static inline string get_100rel_hdr(unsigned char reliable_1xx) +{ + switch(reliable_1xx) { + case REL100_SUPPORTED: + return SIP_HDR_COLSP(SIP_HDR_SUPPORTED) SIP_EXT_100REL CRLF; + case REL100_REQUIRE: + return SIP_HDR_COLSP(SIP_HDR_REQUIRE) SIP_EXT_100REL CRLF; + default: + ERROR("BUG: unexpected reliability switch value of '%d'.\n", + reliable_1xx); + case 0: + break; + } + return ""; +} + #endif /** EMACS ** diff --git a/core/AmSessionEventHandler.cpp b/core/AmSessionEventHandler.cpp index ed4cb0b6..3d8b88d6 100644 --- a/core/AmSessionEventHandler.cpp +++ b/core/AmSessionEventHandler.cpp @@ -43,7 +43,8 @@ bool AmSessionEventHandler::onSipRequest(const AmSipRequest&) return false; } -bool AmSessionEventHandler::onSipReply(const AmSipReply& reply, int old_dlg_status) +bool AmSessionEventHandler::onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method) { return false; } diff --git a/core/AmSessionEventHandler.h b/core/AmSessionEventHandler.h index 14e71338..ce3e381b 100644 --- a/core/AmSessionEventHandler.h +++ b/core/AmSessionEventHandler.h @@ -66,7 +66,8 @@ public: virtual bool process(AmEvent*); virtual bool onSipRequest(const AmSipRequest&); - virtual bool onSipReply(const AmSipReply&, int old_dlg_status); + virtual bool onSipReply(const AmSipReply&, int old_dlg_status, + const string& trans_method); virtual bool onSipReqTimeout(const AmSipRequest &); virtual bool onSipRplTimeout(const AmSipRequest &, const AmSipReply &); diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 2b6d3d22..96fb10f4 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -226,6 +226,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) AmSipTransaction& t = t_it->second; int old_dlg_status = status; + string trans_method = t.method; // rfc3261 12.1 // Dialog established only by 101-199 or 2xx @@ -240,7 +241,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) remote_tag = reply.remote_tag; } - // allow route overwritting + // allow route overwriting if ((status < Connected) && !reply.route.empty()) { route = reply.route; } @@ -250,7 +251,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) switch(status){ case Disconnecting: - if( t.method == "INVITE" ){ + if (trans_method == SIP_METH_INVITE) { if(reply.code == 487){ // CANCEL accepted @@ -270,7 +271,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) case Disconnected: // only change status of dialog if reply // to INVITE received - if(t.method == "INVITE"){ + if (trans_method == SIP_METH_INVITE) { if(reply.code < 200) status = Pending; else if(reply.code >= 300) @@ -289,7 +290,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) // TODO: // - place this somewhere else. // (probably in AmSession...) - if((reply.code < 300) && (t.method == "INVITE")) { + if((reply.code < 300) && (trans_method == SIP_METH_INVITE)) { if(hdl) { hdl->onInvite2xx(reply); @@ -304,7 +305,7 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) } if(hdl) - hdl->onSipReply(reply, old_dlg_status); + hdl->onSipReply(reply, old_dlg_status, trans_method); } void AmSipDialog::uasTimeout(AmSipTimeoutEvent* to_ev) @@ -330,6 +331,19 @@ void AmSipDialog::uasTimeout(AmSipTimeoutEvent* to_ev) to_ev->processed = true; } +bool AmSipDialog::getUACTransPending() { + return !uac_trans.empty(); +} + +bool AmSipDialog::getUACInvTransPending() { + for (TransMap::iterator it=uac_trans.begin(); + it != uac_trans.end(); it++) { + if (it->second.method == "INVITE") + return true; + } + return false; +} + string AmSipDialog::getContactHdr() { if(contact_uri.empty()) { diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index e25104b1..aad81ca7 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -74,7 +74,8 @@ class AmSipDialogEventHandler virtual void onSipRequest(const AmSipRequest& req)=0; /** Hook called when a reply has been received */ - virtual void onSipReply(const AmSipReply& reply, int old_dlg_status)=0; + virtual void onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method)=0; /** Hook called before a request is sent */ virtual void onSendRequest(const string& method, @@ -160,7 +161,11 @@ class AmSipDialog AmSipDialog(AmSipDialogEventHandler* h=0); ~AmSipDialog(); - bool getUACTransPending() { return !uac_trans.empty(); } + /** @return whether UAC transaction is pending */ + bool getUACTransPending(); + + /** @return whether INVITE transaction is pending */ + bool getUACInvTransPending(); int getStatus() { return status; } void setStatus(int new_status); @@ -174,6 +179,7 @@ class AmSipDialog void uasTimeout(AmSipTimeoutEvent* to_ev); + /** @return 0 on success */ int reply(const AmSipRequest& req, unsigned int code, const string& reason, @@ -182,34 +188,51 @@ class AmSipDialog const string& hdrs = "", int flags = 0); + /** @return 0 on success */ int sendRequest(const string& method, const string& content_type = "", const string& body = "", const string& hdrs = "", int flags = 0); + /** @return 0 on success */ int send_200_ack(const AmSipTransaction& t, const string& content_type = "", const string& body = "", const string& hdrs = "", int flags = 0); + /** @return 0 on success */ int bye(const string& hdrs = ""); + + /** @return 0 on success */ int cancel(); + + /** @return 0 on success */ int prack(const string &cont_type, const string &body, const string &hdrs); + + /** @return 0 on success */ int update(const string &cont_type, const string &body, const string &hdrs); + + /** @return 0 on success */ int reinvite(const string& hdrs, const string& content_type, const string& body); + + /** @return 0 on success */ int invite(const string& hdrs, const string& content_type, const string& body); + + /** @return 0 on success */ int refer(const string& refer_to, int expires = -1); + + /** @return 0 on success */ int transfer(const string& target); int drop(); diff --git a/core/AmSipHeaders.h b/core/AmSipHeaders.h index cdc3d313..dc22b9c1 100644 --- a/core/AmSipHeaders.h +++ b/core/AmSipHeaders.h @@ -41,4 +41,8 @@ #define SIP_EXT_100REL "100rel" #define SIP_HDR_SESSION_EXPIRES_COMPACT "x" + +#define SIP_IS_200_CLASS(code) ((code >= 200) && (code < 300)) + +#define SIP_APPLICATION_SDP "application/sdp" #endif /* __AMSIPHEADERS_H__ */ diff --git a/core/plug-in/session_timer/SessionTimer.cpp b/core/plug-in/session_timer/SessionTimer.cpp index c6cd47ce..0e49b97d 100644 --- a/core/plug-in/session_timer/SessionTimer.cpp +++ b/core/plug-in/session_timer/SessionTimer.cpp @@ -77,7 +77,8 @@ bool SessionTimer::onSipRequest(const AmSipRequest& req) return false; } -bool SessionTimer::onSipReply(const AmSipReply& reply, int old_dlg_status) +bool SessionTimer::onSipReply(const AmSipReply& reply, int old_dlg_status, + const string& trans_method) { updateTimer(s,reply); return false; @@ -327,6 +328,15 @@ void SessionTimer::setTimers(AmSession* s) } } +void SessionTimer::retryRefreshTimer(AmSession* s) { + DBG("Retrying session refresh timer: T-2s, tag '%s' \n", + s->getLocalTag().c_str()); + + UserTimer::instance()-> + setTimer(ID_SESSION_REFRESH_TIMER, 2, s->getLocalTag()); +} + + void SessionTimer::removeTimers(AmSession* s) { UserTimer::instance()-> @@ -342,7 +352,9 @@ void SessionTimer::onTimeoutEvent(AmTimeoutEvent* timeout_ev) if (timer_id == ID_SESSION_REFRESH_TIMER) { if (session_refresher == refresh_local) { DBG("Session Timer: initiating session refresh\n"); - s->refresh(); + if (!s->refresh()) { + retryRefreshTimer(s); + } } else { DBG("need session refresh but remote session is refresher\n"); } diff --git a/core/plug-in/session_timer/SessionTimer.h b/core/plug-in/session_timer/SessionTimer.h index 0b179e81..92a0afa4 100644 --- a/core/plug-in/session_timer/SessionTimer.h +++ b/core/plug-in/session_timer/SessionTimer.h @@ -120,6 +120,7 @@ class SessionTimer: public AmSessionEventHandler void updateTimer(AmSession* s,const AmSipReply& reply); void setTimers(AmSession* s); + void retryRefreshTimer(AmSession* s); void removeTimers(AmSession* s); string getReplyHeaders(const AmSipRequest& req); @@ -140,7 +141,8 @@ class SessionTimer: public AmSessionEventHandler virtual bool process(AmEvent*); virtual bool onSipRequest(const AmSipRequest&); - virtual bool onSipReply(const AmSipReply&, int old_dlg_status); + virtual bool onSipReply(const AmSipReply&, int old_dlg_status, + const string& trans_method); virtual bool onSendRequest(const string& method, const string& content_type, diff --git a/core/plug-in/uac_auth/UACAuth.cpp b/core/plug-in/uac_auth/UACAuth.cpp index d81d3721..af04b1f8 100644 --- a/core/plug-in/uac_auth/UACAuth.cpp +++ b/core/plug-in/uac_auth/UACAuth.cpp @@ -124,7 +124,7 @@ bool UACAuth::onSipRequest(const AmSipRequest& req) return false; } -bool UACAuth::onSipReply(const AmSipReply& reply, int old_dlg_status) +bool UACAuth::onSipReply(const AmSipReply& reply, int old_dlg_status, const string& trans_method) { bool processed = false; if (reply.code==407 || reply.code==401) { diff --git a/core/plug-in/uac_auth/UACAuth.h b/core/plug-in/uac_auth/UACAuth.h index 93af41d5..4c6eacf5 100644 --- a/core/plug-in/uac_auth/UACAuth.h +++ b/core/plug-in/uac_auth/UACAuth.h @@ -138,7 +138,7 @@ class UACAuth : public AmSessionEventHandler virtual bool process(AmEvent*); virtual bool onSipEvent(AmSipEvent*); virtual bool onSipRequest(const AmSipRequest&); - virtual bool onSipReply(const AmSipReply&, int old_dlg_status); + virtual bool onSipReply(const AmSipReply&, int old_dlg_status, const string& trans_method); virtual bool onSendRequest(const string& method, const string& content_type,