diff --git a/core/AmEvent.h b/core/AmEvent.h index dac08d61..f8ca9652 100644 --- a/core/AmEvent.h +++ b/core/AmEvent.h @@ -95,10 +95,4 @@ class AmEventHandler virtual ~AmEventHandler() { }; }; -/* class AmEventFactory */ -/* { */ -/* virtual AmEvent* generateEvent(const string& receiver_id) = 0; */ -/* virtual ~AmEventFactory() { } */ -/* }; */ - #endif diff --git a/core/AmMediaProcessor.cpp b/core/AmMediaProcessor.cpp index 312d5c81..8a25223d 100644 --- a/core/AmMediaProcessor.cpp +++ b/core/AmMediaProcessor.cpp @@ -178,7 +178,7 @@ void AmMediaProcessor::stop() { } bool threads_stopped = true; do { - usleep(10000); + usleep(10000); // 10ms threads_stopped = true; for (unsigned int i=0;iis_stopped())) { diff --git a/core/AmSession.cpp b/core/AmSession.cpp index 8827f0ae..540d438a 100644 --- a/core/AmSession.cpp +++ b/core/AmSession.cpp @@ -671,19 +671,22 @@ void AmSession::onSipEvent(AmSipEvent* sip_ev) AmSipRequestEvent* req_ev = dynamic_cast(sip_ev); if(req_ev) { - //onSipRequest(req_ev->req); dlg.updateStatus(req_ev->req); return; } - AmSipReplyEvent* reply_ev = dynamic_cast(sip_ev); if(reply_ev) { - //onSipReply(reply_ev->reply); dlg.updateStatus(reply_ev->reply); return; } + AmSipTimeoutEvent* to_ev = dynamic_cast(sip_ev); + if(to_ev) { + dlg.uasTimeout(to_ev); + return; + } + ERROR("Unknown SIP Event"); } @@ -691,8 +694,6 @@ void AmSession::onSipRequest(const AmSipRequest& req) { CALL_EVENT_H(onSipRequest,req); - //dlg.updateStatus(req); - DBG("onSipRequest: method = %s\n",req.method.c_str()); if(req.method == "INVITE"){ diff --git a/core/AmSessionContainer.cpp b/core/AmSessionContainer.cpp index dc0e4e47..0da7022b 100644 --- a/core/AmSessionContainer.cpp +++ b/core/AmSessionContainer.cpp @@ -195,7 +195,7 @@ AmSession* AmSessionContainer::startSessionUAC(AmSipRequest& req, AmArg* session AmSession* session = NULL; try { if((session = createSession(req, session_params)) != 0) { - session->dlg.updateStatusFromLocalRequest(req); // sets local tag as well + session->dlg.updateStatusFromLocalRequest(req); session->setCallgroup(req.from_tag); session->setNegotiateOnReply(true); diff --git a/core/AmSipDialog.cpp b/core/AmSipDialog.cpp index 351e1d32..205725ce 100644 --- a/core/AmSipDialog.cpp +++ b/core/AmSipDialog.cpp @@ -97,15 +97,7 @@ void AmSipDialog::updateStatus(const AmSipRequest& req) r_cseq = req.cseq; r_cseq_i = true; - - if(uas_trans.find(req.cseq) == uas_trans.end()){ - DBG("req.tt = {%p,%p}\n",req.tt._bucket, req.tt._t); - uas_trans[req.cseq] = AmSipTransaction(req.method,req.cseq,req.tt); - } - // else { - // // shouldn't we drop those requests? - // // (CANCEL requests should have been handled before) - // } + uas_trans[req.cseq] = AmSipTransaction(req.method,req.cseq,req.tt); // target refresh requests if (req.from_uri.length() && @@ -151,8 +143,6 @@ void AmSipDialog::updateStatusFromLocalRequest(const AmSipRequest& req) local_uri = req.from_uri; remote_party = req.to; local_party = req.from; - - //next_hop = req.next_hop; } } @@ -304,6 +294,34 @@ void AmSipDialog::updateStatus(const AmSipReply& reply) hdl->onSipReply(reply, old_dlg_status); } +void AmSipDialog::uasTimeout(AmSipTimeoutEvent* to_ev) +{ + assert(to_ev); + + switch(to_ev->type){ + case AmSipTimeoutEvent::no2xxACK: + //TODO + DBG("Timeout: missing 2xx-ACK received\n"); + break; + + case AmSipTimeoutEvent::noErrorACK: + //TODO + DBG("Timeout: missing non-2xx-ACK\n"); + break; + + case AmSipTimeoutEvent::noPRACK: + //TODO + DBG("Timeout: missing PRACK\n"); + break; + + case AmSipTimeoutEvent::_noEv: + default: + break; + }; + + to_ev->processed = true; +} + string AmSipDialog::getContactHdr() { if(contact_uri.empty()) { diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index 60c729ec..16ef5f75 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -42,6 +42,8 @@ using std::string; #define SIP_FLAGS_VERBATIM 1 // send request verbatim, // i.e. modify as little as possible +class AmSipTimeoutEvent; + /** \brief SIP transaction representation */ struct AmSipTransaction { @@ -49,12 +51,8 @@ struct AmSipTransaction unsigned int cseq; trans_ticket tt; - // last reply code - // (sent or received) - //int reply_code; - -AmSipTransaction(const string& method, unsigned int cseq, const trans_ticket& tt) -: method(method), + AmSipTransaction(const string& method, unsigned int cseq, const trans_ticket& tt) + : method(method), cseq(cseq), tt(tt) {} @@ -164,6 +162,8 @@ class AmSipDialog void updateStatus(const AmSipRequest& req); void updateStatus(const AmSipReply& reply); + + void uasTimeout(AmSipTimeoutEvent* to_ev); int reply(const AmSipRequest& req, unsigned int code, diff --git a/core/AmSipEvent.h b/core/AmSipEvent.h index ec1c5a16..9ea2af7a 100644 --- a/core/AmSipEvent.h +++ b/core/AmSipEvent.h @@ -38,6 +38,31 @@ class AmSipEvent: public AmEvent AmSipEvent(int id = -1) : AmEvent(id) {} + + AmSipEvent(const AmSipEvent& ev) + : AmEvent(ev) + {} +}; + +class AmSipTimeoutEvent: public AmSipEvent +{ + public: + + enum EvType { + _noEv=0, + no2xxACK, + noErrorACK, + noPRACK + }; + + EvType type; + + unsigned int cseq_num; + string cseq_method; + + AmSipTimeoutEvent(EvType t, unsigned int cseq_num, const string& cseq_method) + : AmSipEvent(-1), type(t) + {} }; /** \brief SIP request event */ diff --git a/core/SipCtrlInterface.cpp b/core/SipCtrlInterface.cpp index 095b0128..f7f3e27a 100644 --- a/core/SipCtrlInterface.cpp +++ b/core/SipCtrlInterface.cpp @@ -47,8 +47,9 @@ #include "AmApi.h" #include "AmConfigReader.h" #include "AmSipDispatcher.h" +#include "AmEventDispatcher.h" +#include "AmSipEvent.h" -bool SipCtrlInterface::accept_fr_without_totag = false; int SipCtrlInterface::log_raw_messages = 3; bool SipCtrlInterface::log_parsed_messages = true; int SipCtrlInterface::udp_rcvbuf = -1; @@ -71,11 +72,11 @@ int SipCtrlInterface::load() string cfgfile = AmConfig::ConfigurationFile.c_str(); if (file_exists(cfgfile) && !cfg.loadFile(cfgfile)) { if (cfg.hasParameter("accept_fr_without_totag")) { - accept_fr_without_totag = + trans_layer::accept_fr_without_totag = cfg.getParameter("accept_fr_without_totag") == "yes"; } DBG("accept_fr_without_totag = %s\n", - accept_fr_without_totag?"yes":"no"); + trans_layer::accept_fr_without_totag?"yes":"no"); if (cfg.hasParameter("log_raw_messages")) { string msglog = cfg.getParameter("log_raw_messages"); @@ -324,12 +325,11 @@ int SipCtrlInterface::send(const AmSipReply &rep) #define DBG_PARAM(p)\ DBG("%s = <%s>\n",#p,p.c_str()); -void SipCtrlInterface::handle_sip_request(trans_ticket* tt, sip_msg* msg) +void SipCtrlInterface::handle_sip_request(const trans_ticket& tt, sip_msg* msg) { assert(msg); assert(msg->from && msg->from->p); assert(msg->to && msg->to->p); - assert(tt); AmSipRequest req; @@ -384,7 +384,7 @@ void SipCtrlInterface::handle_sip_request(trans_ticket* tt, sip_msg* msg) req.cseq = get_cseq(msg)->num; req.body = c2stlstr(msg->body); - req.tt = *tt; + req.tt = tt; if (msg->content_type) req.content_type = c2stlstr(msg->content_type->value); @@ -486,6 +486,50 @@ void SipCtrlInterface::handle_sip_reply(sip_msg* msg) #undef DBG_PARAM +void SipCtrlInterface::timer_expired(sip_trans* trans, sip_timer_type tt) +{ + assert(trans); + assert(trans->type == TT_UAS); + + AmSipTimeoutEvent::EvType ev = AmSipTimeoutEvent::_noEv; + + //TODO: send an event to the SIP Dialog + switch(tt){ + + case STIMER_H: + switch(trans->state){ + case TS_TERMINATED_200: // missing 200-ACK + ev = AmSipTimeoutEvent::no2xxACK; + break; + case TS_COMPLETED: // missing error-ACK + ev = AmSipTimeoutEvent::noErrorACK; + break; + + // TODO: missing PRACK + //case TS_???: + default: + ERROR("timer H expired / transaction in undefined state\n"); + return; + } + default: + return; + } + + assert(trans->msg); + assert(trans->to_tag.len); + assert(trans->msg->cseq && trans->msg->cseq->p); + + sip_cseq* cseq = dynamic_cast(trans->msg->cseq->p); + + if(!cseq){ + ERROR("missing CSeq\n"); + return; + } + + AmEventDispatcher::instance()->post(c2stlstr(trans->to_tag), + new AmSipTimeoutEvent(ev, cseq->num, c2stlstr(cseq->method_str))); +} + void SipCtrlInterface::prepare_routes_uac(const list& routes, string& route_field) { if(!routes.empty()){ diff --git a/core/SipCtrlInterface.h b/core/SipCtrlInterface.h index 45fc95bd..5d27e819 100644 --- a/core/SipCtrlInterface.h +++ b/core/SipCtrlInterface.h @@ -59,7 +59,6 @@ public: static unsigned int outbound_port; static bool log_parsed_messages; static int log_raw_messages; - static bool accept_fr_without_totag; static int udp_rcvbuf; SipCtrlInterface(); @@ -96,8 +95,9 @@ public: /** * From sip_ua */ - void handle_sip_request(trans_ticket* tt, sip_msg* msg); + void handle_sip_request(const trans_ticket& tt, sip_msg* msg); void handle_sip_reply(sip_msg* msg); + void timer_expired(sip_trans* trans, sip_timer_type tt); }; diff --git a/core/sip/sip_trans.h b/core/sip/sip_trans.h index 62d335f7..3fe6464e 100644 --- a/core/sip/sip_trans.h +++ b/core/sip/sip_trans.h @@ -132,8 +132,8 @@ class sip_trans /** * Retransmission buffer - * - UAS transaction: ACK - * - UAC transaction: final reply + * - UAC transaction: ACK + * - UAS transaction: last reply */ char* retr_buf; diff --git a/core/sip/sip_ua.h b/core/sip/sip_ua.h index ea8c18af..5ea319b4 100644 --- a/core/sip/sip_ua.h +++ b/core/sip/sip_ua.h @@ -27,6 +27,8 @@ #ifndef _sip_ua_h_ #define _sip_ua_h_ +#include "sip_trans.h" + class trans_ticket; struct sip_msg; @@ -34,8 +36,12 @@ class sip_ua { public: virtual ~sip_ua() {} - virtual void handle_sip_request(trans_ticket* tt, sip_msg* msg)=0; + + virtual void handle_sip_request(const trans_ticket& tt, sip_msg* msg)=0; virtual void handle_sip_reply(sip_msg* msg)=0; + + // UAS timer expired (UAC timers generate a local 408) + virtual void timer_expired(sip_trans* trans, sip_timer_type tt)=0; }; #endif diff --git a/core/sip/trans_layer.cpp b/core/sip/trans_layer.cpp index 00293d28..bdce0e2c 100644 --- a/core/sip/trans_layer.cpp +++ b/core/sip/trans_layer.cpp @@ -59,6 +59,7 @@ */ trans_layer* trans_layer::_instance = NULL; +bool trans_layer::accept_fr_without_totag = false; trans_layer* trans_layer::instance() { @@ -879,6 +880,10 @@ int trans_layer::cancel(trans_ticket* tt) case TS_COMPLETED: // final reply has been sent, but still no ACK: // do nothing!!! + + // TODO: switch to TS_CANCELLING?? + // this would allow for sending the BYE as soon + // we get an ACK or a timeout (STIMER_H)... bucket->unlock(); return 0; @@ -1043,8 +1048,7 @@ void trans_layer::received_msg(sip_msg* msg) // the UA. assert(ua); DBG("Passing ACK to the UA.\n"); - trans_ticket tt(t,bucket); - ua->handle_sip_request(&tt,msg); + ua->handle_sip_request(trans_ticket(t,bucket),msg); DROP_MSG; } @@ -1072,8 +1076,7 @@ void trans_layer::received_msg(sip_msg* msg) // the UA. assert(ua); - trans_ticket tt(t,bucket); - ua->handle_sip_request(&tt,msg); + ua->handle_sip_request(trans_ticket(t,bucket),msg); // forget the msg: it will be // owned by the new transaction @@ -1159,7 +1162,7 @@ int trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg* m to_tag = ((sip_from_to*)msg->to->p)->tag; if((t->msg->u.request->method != sip_request::CANCEL) && !to_tag.len){ DBG("To-tag missing in final reply (see sipctrl.conf?)\n"); - if (!SipCtrlInterface::accept_fr_without_totag) + if (!trans_layer::accept_fr_without_totag) return -1; } @@ -1220,7 +1223,7 @@ int trans_layer::update_uac_reply(trans_bucket* bucket, sip_trans* t, sip_msg* m t->to_tag.s = new char[to_tag.len]; t->to_tag.len = to_tag.len; memcpy((void*)t->to_tag.s,to_tag.s,to_tag.len); - } + } goto pass_reply; @@ -1542,7 +1545,6 @@ void trans_layer::timer_expired(timer* t, trans_bucket* bucket, sip_trans* tr) case STIMER_D: // Completed: -> Terminated case STIMER_K: // Completed: terminate transaction case STIMER_J: // Completed: -> Terminated - case STIMER_H: // Completed: -> Terminated case STIMER_I: // Confirmed: -> Terminated case STIMER_L: // Terminated_200 -> Terminated @@ -1551,10 +1553,15 @@ void trans_layer::timer_expired(timer* t, trans_bucket* bucket, sip_trans* tr) // else, send ACK & BYE. tr->clear_timer(type); - tr->state = TS_TERMINATED; bucket->remove_trans(tr); break; + case STIMER_H: // Completed: -> Terminated + + tr->clear_timer(type); + ua->timer_expired(tr,STIMER_H); + bucket->remove_trans(tr); + break; case STIMER_E: // Trying/Proceeding: (re-)send request case STIMER_G: // Completed: (re-)send response diff --git a/core/sip/trans_layer.h b/core/sip/trans_layer.h index 740e27b3..1b159f36 100644 --- a/core/sip/trans_layer.h +++ b/core/sip/trans_layer.h @@ -27,8 +27,6 @@ #ifndef _trans_layer_h_ #define _trans_layer_h_ -//#include "AmApi.h" - #include "cstring.h" #include @@ -134,6 +132,13 @@ class trans_layer public: + /** + * Config option: if true, final replies without + * a to-tag will be accepted for requests which do not + * create a dialog. + */ + static bool accept_fr_without_totag; + /** * Retrieve the singleton instance. */