diff --git a/include/bgcfsproutlet.h b/include/bgcfsproutlet.h index 29d9e4dd9..bc402aa87 100644 --- a/include/bgcfsproutlet.h +++ b/include/bgcfsproutlet.h @@ -134,9 +134,9 @@ class BGCFSproutletTsx : public SproutletTsx ~BGCFSproutletTsx(); virtual void on_rx_initial_request(pjsip_msg* req) override; - virtual void on_tx_request(pjsip_msg* req, int fork_id) override; + virtual void obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) override; virtual void on_rx_response(pjsip_msg* rsp, int fork_id) override; - virtual void on_tx_response(pjsip_msg* rsp) override; + virtual void obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) override; virtual void on_rx_cancel(int status_code, pjsip_msg* req) override; private: diff --git a/include/icscfsproutlet.h b/include/icscfsproutlet.h index 0787d65f6..19f81e649 100644 --- a/include/icscfsproutlet.h +++ b/include/icscfsproutlet.h @@ -154,9 +154,9 @@ class ICSCFSproutletTsx : public SproutletTsx virtual void on_rx_initial_request(pjsip_msg* req) override; virtual void on_rx_in_dialog_request(pjsip_msg* req) override; - virtual void on_tx_request(pjsip_msg* req, int fork_id) override; + virtual void obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) override; virtual void on_rx_response(pjsip_msg* rsp, int fork_id) override; - virtual void on_tx_response(pjsip_msg* rsp) override; + virtual void obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) override; virtual void on_rx_cancel(int status_code, pjsip_msg* req) override; private: @@ -200,9 +200,9 @@ class ICSCFSproutletRegTsx : public SproutletTsx virtual void on_rx_initial_request(pjsip_msg* req) override; virtual void on_rx_in_dialog_request(pjsip_msg* req) override; - virtual void on_tx_request(pjsip_msg* req, int fork_id) override; + virtual void obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) override; virtual void on_rx_response(pjsip_msg* rsp, int fork_id) override; - virtual void on_tx_response(pjsip_msg* rsp) override; + virtual void obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) override; virtual void on_rx_cancel(int status_code, pjsip_msg* req) override; private: diff --git a/include/pjutils.h b/include/pjutils.h index cb47d68b4..77e7a53ce 100644 --- a/include/pjutils.h +++ b/include/pjutils.h @@ -179,6 +179,18 @@ pjsip_tx_data* create_cancel(pjsip_endpoint* endpt, pjsip_tx_data* tdata, int reason_code); +/// Creates an ACK to a negative response. This method cannot be used to +/// generate ACKs for ACK transactions. +/// +/// @return - The negative ACK created +/// +/// @param endpt - The PJSIP endpoint. +/// @param req - The original request that the response was sent to. +/// @param rsp - The response to the original request. +pjsip_tx_data* create_ack(pjsip_endpoint* endpt, + pjsip_msg* req, + pjsip_msg* rsp); + void resolve(const std::string& name, int port, int transport, diff --git a/include/scscfsproutlet.h b/include/scscfsproutlet.h index 400d3f5b3..7ea080374 100644 --- a/include/scscfsproutlet.h +++ b/include/scscfsproutlet.h @@ -246,9 +246,10 @@ class SCSCFSproutletTsx : public SproutletTsx virtual void on_rx_initial_request(pjsip_msg* req) override; virtual void on_rx_in_dialog_request(pjsip_msg* req) override; - virtual void on_tx_request(pjsip_msg* req, int fork_id) override; + virtual void obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) override; virtual void on_rx_response(pjsip_msg* rsp, int fork_id) override; - virtual void on_tx_response(pjsip_msg* rsp) override; + virtual void on_rx_trying(pjsip_msg* rsp, int fork_id) override; + virtual void obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) override; virtual void on_rx_cancel(int status_code, pjsip_msg* req) override; virtual void on_timer_expiry(void* context) override; @@ -367,6 +368,10 @@ class SCSCFSproutletTsx : public SproutletTsx /// @param sip_code - The reported SIP return code std::string fork_failure_reason_as_string(int fork_id, int sip_code); + void acr_handle_response(pjsip_msg* rsp); + + void cancel_liveness_timer(); + /// Pointer to the parent SCSCFSproutlet object - used for various operations /// that require access to global configuration or services. SCSCFSproutlet* _scscf; diff --git a/include/sproutlet.h b/include/sproutlet.h index 1cc750eb5..a746420b7 100644 --- a/include/sproutlet.h +++ b/include/sproutlet.h @@ -91,7 +91,7 @@ class SproutletTsxHelper /// /// @returns - A clone of the original request message. /// - virtual pjsip_msg* original_request() = 0; + virtual pjsip_msg* get_request_for_sproutlet_tsx() = 0; /// Returns the top Route header from the original incoming request. This /// can be inpsected by the Sproutlet, but should not be modified. Note that @@ -321,28 +321,23 @@ class SproutletTsx /// @param req - The received in-dialog request. virtual void on_rx_in_dialog_request(pjsip_msg* req) { send_request(req); } - /// Called when a request has been transmitted on the transaction (usually - /// because the service has previously called forward_request() with the - /// request message. + /// Called with all responses, except 100 Trying, received on the transaction. + /// If a transport error or transaction timeout occurs on a downstream leg, + /// this method is called with a 408 response. /// - /// @param req - The transmitted request - /// @param fork_id - The identity of the downstream fork on which the - /// request was sent. - virtual void on_tx_request(pjsip_msg* req, int fork_id) { } - - /// Called with all responses received on the transaction. If a transport - /// error or transaction timeout occurs on a downstream leg, this method is - /// called with a 408 response. + /// Note: 100 Trying responses are handled by the on_rx_trying method. /// - /// @param rsp - The received request. + /// @param rsp - The received response. /// @param fork_id - The identity of the downstream fork on which /// the response was received. virtual void on_rx_response(pjsip_msg* rsp, int fork_id) { send_response(rsp); } - /// Called when a response has been transmitted on the transaction. + /// This is a notification that a 100 Trying has been received. The sproutlet + /// proxy handles these automatically. The Sproutlet Tsx should not forward + /// the response on (i.e. should not call send_request). /// - /// @param rsp - The transmitted response. - virtual void on_tx_response(pjsip_msg* rsp) { } + /// @param rsp - The received response. + virtual void on_rx_trying(pjsip_msg* rsp, int fork_id) {} /// Called if the original request is cancelled (either by a received /// CANCEL request, an error on the inbound transport or a transaction @@ -357,6 +352,47 @@ class SproutletTsx /// was triggered by an error or timeout. virtual void on_rx_cancel(int status_code, pjsip_msg* cancel_req) {} + /// The next four methods make up the observation API. The purpose of this API + /// is to view transaction management messages that are not seen by + /// on_rx_request and on_rx_response. This includes CANCEL, 200 OK to CANCEL, + /// 100 Trying and ACK to negative response. This API also sees all the + /// messages that are passed to on_rx_request and on_rx_response. + + /// Called when a request is received by this sproutlet Tsx. + /// + /// @param req - The received request. + /// @param tsx_mgmt - True when the received request will not be passed + /// to on_rx_request. + virtual void obs_rx_request(pjsip_msg* req, bool tsx_mgmt) {}; + + /// Called when a response is received by this sproutlet Tsx. + /// + /// @param rsp - The received response. + /// @param fork_id - The identity of the downstream fork on which the + /// response was received. + /// @param tsx_mgmt - True when the received respone will not be passed + /// to on_rx_response. + virtual void obs_rx_response(pjsip_msg* rsp, int fork_id, bool tsx_mgmt) {}; + + /// Called when a request has been transmitted on the transaction by this + /// sproutlet Tsx. This is usually because the service has previously called + /// forward_request() with the request message. + /// + /// @param req - The transmitted request + /// @param fork_id - The identity of the downstream fork on which the + /// request was sent. + /// @param tsx_mgmt - True when the transmitted request was not generated + /// by the sproutlet Tsx calling send_request(). + virtual void obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) {} + + /// Called when a response has been transmitted on the transaction by the + /// sproutlet Tsx. + /// + /// @param rsp - The transmitted response. + /// @param tsx_mgmt - True when the transmitted response was not generated + /// by the sproutlet Tsx calling send_response(). + virtual void obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) {} + /// Called when a timer programmed by the SproutletTsx expires. /// /// @param context - The context parameter specified when the timer @@ -371,7 +407,7 @@ class SproutletTsx /// @returns - A clone of the original request message. /// pjsip_msg* original_request() - {return _helper->original_request();} + {return _helper->get_request_for_sproutlet_tsx();} /// Returns a URI that could be used to route back to the current Sproutlet. /// This URI may contain pre-loaded parameters that should not be modified diff --git a/include/sproutletproxy.h b/include/sproutletproxy.h index 35c46dc96..aa83fd518 100644 --- a/include/sproutletproxy.h +++ b/include/sproutletproxy.h @@ -191,6 +191,10 @@ class SproutletProxy : public BasicProxy int fork_id, pjsip_tx_data* cancel); + void tx_negative_ack(SproutletWrapper* sproutlet, + int fork_id, + pjsip_tx_data* ack); + /// Gets the next target Sproutlet for the message by analysing the top /// Route header. Sproutlet* target_sproutlet(pjsip_msg* msg, @@ -289,7 +293,7 @@ class SproutletWrapper : public SproutletTsxHelper /// functions from SproutletTsxHelper. See there for function comments for /// the following. void add_to_dialog(const std::string& dialog_id=""); - pjsip_msg* original_request(); + pjsip_msg* get_request_for_sproutlet_tsx(); const char* msg_info(pjsip_msg*); const pjsip_route_hdr* route_hdr() const; const std::string& dialog_id() const; @@ -320,6 +324,7 @@ class SproutletWrapper : public SproutletTsxHelper void rx_request(pjsip_tx_data* req); void rx_response(pjsip_tx_data* rsp, int fork_id); void rx_cancel(pjsip_tx_data* cancel); + void rx_negative_ack(pjsip_tx_data* ack); void rx_error(int status_code); void rx_fork_error(pjsip_event_id_e event, int fork_id); void on_timer_pop(TimerID id, void* context); @@ -331,6 +336,7 @@ class SproutletWrapper : public SproutletTsxHelper void tx_request(pjsip_tx_data* req, int fork_id); void tx_response(pjsip_tx_data* rsp); void tx_cancel(int fork_id); + void tx_negative_ack(pjsip_tx_data* rsp, int fork_id); int compare_sip_sc(int sc1, int sc2); bool is_uri_local(const pjsip_uri*) const; void log_inter_sproutlet(pjsip_tx_data* tdata, bool downstream); diff --git a/src/bgcfsproutlet.cpp b/src/bgcfsproutlet.cpp index b4aedaf51..53b6047a3 100644 --- a/src/bgcfsproutlet.cpp +++ b/src/bgcfsproutlet.cpp @@ -253,9 +253,10 @@ void BGCFSproutletTsx::on_rx_initial_request(pjsip_msg* req) } -void BGCFSproutletTsx::on_tx_request(pjsip_msg* req, int fork_id) +void BGCFSproutletTsx::obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) { - if (_acr != NULL) + // We don't send ACRs for transaction management messages. + if ((!tsx_mgmt) && (_acr != NULL)) { // Pass the transmitted request to the ACR to update the accounting // information. @@ -279,9 +280,10 @@ void BGCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) } -void BGCFSproutletTsx::on_tx_response(pjsip_msg* rsp) +void BGCFSproutletTsx::obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) { - if (_acr != NULL) + // We don't send ACRs for transaction management messages. + if ((!tsx_mgmt) && (_acr != NULL)) { // Pass the transmitted response to the ACR to update the accounting // information. diff --git a/src/icscfsproutlet.cpp b/src/icscfsproutlet.cpp index 8edc0c0e9..4dc379854 100644 --- a/src/icscfsproutlet.cpp +++ b/src/icscfsproutlet.cpp @@ -297,9 +297,10 @@ void ICSCFSproutletRegTsx::on_rx_in_dialog_request(pjsip_msg* req) } -void ICSCFSproutletRegTsx::on_tx_request(pjsip_msg* req, int fork_id) +void ICSCFSproutletRegTsx::obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) { - if (_acr != NULL) + // We don't send ACRs for transaction management messages. + if ((!tsx_mgmt) && (_acr != NULL)) { // Pass the transmitted request to the ACR to update the accounting // information. @@ -393,9 +394,10 @@ void ICSCFSproutletRegTsx::on_rx_response(pjsip_msg* rsp, int fork_id) } -void ICSCFSproutletRegTsx::on_tx_response(pjsip_msg* rsp) +void ICSCFSproutletRegTsx::obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) { - if (_acr != NULL) + // We don't send ACRs for transaction management messages. + if ((!tsx_mgmt) && (_acr != NULL)) { // Pass the transmitted response to the ACR to update the accounting // information. @@ -710,9 +712,10 @@ void ICSCFSproutletTsx::on_rx_in_dialog_request(pjsip_msg* req) } -void ICSCFSproutletTsx::on_tx_request(pjsip_msg* req, int fork_id) +void ICSCFSproutletTsx::obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) { - if (_acr != NULL) + // We don't send ACRs for transaction management messages. + if ((!tsx_mgmt) && (_acr != NULL)) { // Pass the transmitted request to the ACR to update the accounting // information. @@ -799,60 +802,64 @@ void ICSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) } -void ICSCFSproutletTsx::on_tx_response(pjsip_msg* rsp) +void ICSCFSproutletTsx::obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) { - if (_acr != NULL) - { - // Pass the transmitted response to the ACR to update the accounting - // information. - _acr->tx_response(rsp); - } - - pjsip_status_code rsp_status = (pjsip_status_code)rsp->line.status.code; - - // Check if this is a terminating INVITE. If it is then check whether we need - // to update our session establishment stats. We consider the session to be - // set up as soon as we receive a final response OR a 180 Ringing (per TS - // 32.409). - if (!_originating && - (_req_type == PJSIP_INVITE_METHOD) && - !_session_set_up && - ((rsp_status == PJSIP_SC_RINGING) || - !PJSIP_IS_STATUS_IN_CLASS(rsp_status, 100))) + // We don't send ACRs or update stats for transaction management messages. + if (!tsx_mgmt) { - // Session is now set up. - _session_set_up = true; - _icscf->_session_establishment_tbl->increment_attempts(); - _icscf->_session_establishment_network_tbl->increment_attempts(); - - if ((rsp_status == PJSIP_SC_RINGING) || - PJSIP_IS_STATUS_IN_CLASS(rsp_status, 200)) - { - // Session has been set up successfully. - TRC_DEBUG("Session successful"); - _icscf->_session_establishment_tbl->increment_successes(); - _icscf->_session_establishment_network_tbl->increment_successes(); - } - else if ((rsp_status == PJSIP_SC_BUSY_HERE) || - (rsp_status == PJSIP_SC_BUSY_EVERYWHERE) || - (rsp_status == PJSIP_SC_NOT_FOUND) || - (rsp_status == PJSIP_SC_ADDRESS_INCOMPLETE)) + if (_acr != NULL) { - // Session failed, but should be counted as successful from a network - // perspective. - TRC_DEBUG("Session failed but network successful"); - _icscf->_session_establishment_tbl->increment_failures(); - _icscf->_session_establishment_network_tbl->increment_successes(); + // Pass the transmitted response to the ACR to update the accounting + // information. + _acr->tx_response(rsp); } - else + + pjsip_status_code rsp_status = (pjsip_status_code)rsp->line.status.code; + + // Check if this is a terminating INVITE. If it is then check whether we need + // to update our session establishment stats. We consider the session to be + // set up as soon as we receive a final response OR a 180 Ringing (per TS + // 32.409). We do not consider responses to CANCEL requests as final + // responses. + if (!_originating && + (_req_type == PJSIP_INVITE_METHOD) && + !_session_set_up && + ((rsp_status == PJSIP_SC_RINGING) || + !PJSIP_IS_STATUS_IN_CLASS(rsp_status, 100))) { - // Session establishment failed. - TRC_DEBUG("Session failed"); - _icscf->_session_establishment_tbl->increment_failures(); - _icscf->_session_establishment_network_tbl->increment_failures(); + // Session is now set up. + _session_set_up = true; + _icscf->_session_establishment_tbl->increment_attempts(); + _icscf->_session_establishment_network_tbl->increment_attempts(); + + if ((rsp_status == PJSIP_SC_RINGING) || + PJSIP_IS_STATUS_IN_CLASS(rsp_status, 200)) + { + // Session has been set up successfully. + TRC_DEBUG("Session successful"); + _icscf->_session_establishment_tbl->increment_successes(); + _icscf->_session_establishment_network_tbl->increment_successes(); + } + else if ((rsp_status == PJSIP_SC_BUSY_HERE) || + (rsp_status == PJSIP_SC_BUSY_EVERYWHERE) || + (rsp_status == PJSIP_SC_NOT_FOUND) || + (rsp_status == PJSIP_SC_ADDRESS_INCOMPLETE)) + { + // Session failed, but should be counted as successful from a network + // perspective. + TRC_DEBUG("Session failed but network successful"); + _icscf->_session_establishment_tbl->increment_failures(); + _icscf->_session_establishment_network_tbl->increment_successes(); + } + else + { + // Session establishment failed. + TRC_DEBUG("Session failed"); + _icscf->_session_establishment_tbl->increment_failures(); + _icscf->_session_establishment_network_tbl->increment_failures(); + } } } - } diff --git a/src/mangelwurzel/ut/mangelwurzel_test.cpp b/src/mangelwurzel/ut/mangelwurzel_test.cpp index 064f544d6..2f226b9e9 100644 --- a/src/mangelwurzel/ut/mangelwurzel_test.cpp +++ b/src/mangelwurzel/ut/mangelwurzel_test.cpp @@ -179,7 +179,7 @@ MATCHER_P(ReqUriEquals, req_uri, "") TEST_F(MangelwurzelTest, Rot13) { MangelwurzelTsx::Config config; - EXPECT_CALL(*_helper, original_request()); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()); EXPECT_CALL(*_helper, free_msg(_)); MangelwurzelTsx mangelwurzel_tsx(_helper, config); @@ -200,7 +200,7 @@ TEST_F(MangelwurzelTest, Rot13) TEST_F(MangelwurzelTest, Reverse) { MangelwurzelTsx::Config config; - EXPECT_CALL(*_helper, original_request()); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()); EXPECT_CALL(*_helper, free_msg(_)); MangelwurzelTsx mangelwurzel_tsx(_helper, config); @@ -224,7 +224,7 @@ TEST_F(MangelwurzelTest, CreateDefaults) Mangelwurzel mangelwurzel("mangelwurzel", 5058, "sip:mangelwurzel.homedomain:5058;transport=tcp"); Message msg; pjsip_msg* req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(req)); EXPECT_CALL(*_helper, free_msg(req)); pjsip_route_hdr* hdr = pjsip_rr_hdr_create(stack_data.pool); @@ -255,7 +255,7 @@ TEST_F(MangelwurzelTest, CreateFullConfig) Mangelwurzel mangelwurzel("mangelwurzel", 5058, "sip:mangelwurzel.homedomain:5058;transport=tcp"); Message msg; pjsip_msg* req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(req)); EXPECT_CALL(*_helper, free_msg(req)); pjsip_route_hdr* hdr = pjsip_rr_hdr_create(stack_data.pool); @@ -290,7 +290,7 @@ TEST_F(MangelwurzelTest, CreateRot13) Mangelwurzel mangelwurzel("mangelwurzel", 5058, "sip:mangelwurzel.homedomain:5058;transport=tcp"); Message msg; pjsip_msg* req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(req)); EXPECT_CALL(*_helper, free_msg(req)); pjsip_route_hdr* hdr = pjsip_rr_hdr_create(stack_data.pool); @@ -317,7 +317,7 @@ TEST_F(MangelwurzelTest, CreateInvalidMangalgorithm) Mangelwurzel mangelwurzel("mangelwurzel", 5058, "sip:mangelwurzel.homedomain:5058;transport=tcp"); Message msg; pjsip_msg* req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(req)); EXPECT_CALL(*_helper, free_msg(req)); pjsip_route_hdr* hdr = pjsip_rr_hdr_create(stack_data.pool); @@ -347,7 +347,7 @@ TEST_F(MangelwurzelTest, CreateNoRouteHdr) Message msg; msg._requri = "sip:mangelwurzel.homedomain;mangalgorithm=reverse"; pjsip_msg* req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(req)); EXPECT_CALL(*_helper, free_msg(req)); EXPECT_CALL(*_helper, route_hdr()).WillOnce(ReturnNull()); @@ -372,7 +372,7 @@ TEST_F(MangelwurzelTest, InitialReq) // Save off the original request. We expect mangelwurzel to request it later. pjsip_msg* original_req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(original_req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(original_req)); EXPECT_CALL(*_helper, free_msg(original_req)); // Set up the mangelwurzel transaction's config. Turn everything on. @@ -427,7 +427,7 @@ TEST_F(MangelwurzelTest, Response) // Save off the original request. We expect mangelwurzel to request it later. pjsip_msg* original_req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(original_req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(original_req)); EXPECT_CALL(*_helper, free_msg(original_req)); // Set up the mangelwurzel transaction's config. Turn everything on. @@ -475,7 +475,7 @@ TEST_F(MangelwurzelTest, InDialogReq) // Save off the original request. We expect mangelwurzel to request it later. pjsip_msg* original_req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(original_req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(original_req)); EXPECT_CALL(*_helper, free_msg(original_req)); // Set up the mangelwurzel transaction's config. This is different to the @@ -523,7 +523,7 @@ TEST_F(MangelwurzelTest, REGISTER) // Save off the original request. We expect mangelwurzel to request it later. pjsip_msg* original_req = parse_msg(msg.get_request()); - EXPECT_CALL(*_helper, original_request()).WillOnce(Return(original_req)); + EXPECT_CALL(*_helper, get_request_for_sproutlet_tsx()).WillOnce(Return(original_req)); EXPECT_CALL(*_helper, free_msg(original_req)); // Set up the mangelwurzel transaction's config. This is different to the diff --git a/src/pjutils.cpp b/src/pjutils.cpp index 9ac2dffc4..2d586e3fa 100644 --- a/src/pjutils.cpp +++ b/src/pjutils.cpp @@ -906,6 +906,24 @@ pjsip_tx_data* PJUtils::create_cancel(pjsip_endpoint* endpt, return cancel; } +pjsip_tx_data* PJUtils::create_ack(pjsip_endpoint* endpt, + pjsip_msg* req, + pjsip_msg* rsp) +{ + pjsip_tx_data* ack; + pj_status_t status = pjsip_endpt_create_ack_from_msgs(endpt, + req, + rsp, + &ack); + + if (status != PJ_SUCCESS) + { + return NULL; + } + + return ack; +} + /// Resolves a destination. void PJUtils::resolve(const std::string& name, int port, @@ -1683,7 +1701,7 @@ void PJUtils::mark_sas_call_branch_ids(const SAS::TrailId trail, pjsip_cid_hdr* ((msg->line.req.method.id == PJSIP_REGISTER_METHOD) || (pjsip_method_cmp(&msg->line.req.method, pjsip_get_subscribe_method()) == 0) || (pjsip_method_cmp(&msg->line.req.method, pjsip_get_notify_method()) == 0))); - + if (cid_hdr != NULL) { TRC_DEBUG("Logging SAS Call-ID marker, Call-ID %.*s", cid_hdr->id.slen, cid_hdr->id.ptr); diff --git a/src/scscfsproutlet.cpp b/src/scscfsproutlet.cpp index eac2569d9..dad93e752 100644 --- a/src/scscfsproutlet.cpp +++ b/src/scscfsproutlet.cpp @@ -587,16 +587,20 @@ void SCSCFSproutletTsx::on_rx_in_dialog_request(pjsip_msg* req) } -void SCSCFSproutletTsx::on_tx_request(pjsip_msg* req, int fork_id) +void SCSCFSproutletTsx::obs_tx_request(pjsip_msg* req, int fork_id, bool tsx_mgmt) { - ACR* acr = get_acr(); - if (acr) + // We don't send ACRs for transaction management messages. + if (!tsx_mgmt) { - // Pass the transmitted request to the ACR to update the accounting - // information. - acr->lock(); - acr->tx_request(req); - acr->unlock(); + ACR* acr = get_acr(); + if (acr) + { + // Pass the transmitted request to the ACR to update the accounting + // information. + acr->lock(); + acr->tx_request(req); + acr->unlock(); + } } } @@ -610,22 +614,8 @@ void SCSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) _se_helper.process_response(rsp, get_pool(rsp), trail()); } - // Pass the received response to the ACR. - // @TODO - timestamp from response??? - ACR* acr = get_acr(); - if (acr != NULL) - { - acr->lock(); - acr->rx_response(rsp); - acr->unlock(); - } - - if (_liveness_timer != 0) - { - // The liveness timer is running on this request, so cancel it. - cancel_timer(_liveness_timer); - _liveness_timer = 0; - } + acr_handle_response(rsp); + cancel_liveness_timer(); int st_code = rsp->line.status.code; @@ -710,7 +700,7 @@ void SCSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) // response we've seen from an AS track it as a successful // communication. This means that no matter how many 1xx responses we // receive we only track one success. - if ((st_code > PJSIP_SC_TRYING) && (!_seen_1xx)) + if (!_seen_1xx) { _scscf->track_app_serv_comm_success(_as_chain_link.uri(), _as_chain_link.default_handling()); @@ -719,10 +709,7 @@ void SCSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) } } - if (st_code > PJSIP_SC_TRYING) - { - _seen_1xx = true; - } + _seen_1xx = true; if (rsp != NULL) { @@ -733,28 +720,39 @@ void SCSCFSproutletTsx::on_rx_response(pjsip_msg* rsp, int fork_id) } -void SCSCFSproutletTsx::on_tx_response(pjsip_msg* rsp) +void SCSCFSproutletTsx::on_rx_trying(pjsip_msg* rsp, int fork_id) { - ACR* acr = get_acr(); - if (acr != NULL) - { - // Pass the transmitted response to the ACR to update the accounting - // information. - acr->lock(); - acr->tx_response(rsp); - acr->unlock(); - } + acr_handle_response(rsp); + cancel_liveness_timer(); +} + - // If this is a transaction where we are supposed to be tracking session - // setup stats then check to see if it is now set up. We consider it to be - // setup when we receive either a 180 Ringing or 2xx (per TS 32.409). - pjsip_status_code st_code = (pjsip_status_code)rsp->line.status.code; - if (_record_session_setup_time && - ((st_code == PJSIP_SC_RINGING) || - PJSIP_IS_STATUS_IN_CLASS(st_code, 200))) +void SCSCFSproutletTsx::obs_tx_response(pjsip_msg* rsp, bool tsx_mgmt) +{ + // We don't send ACRs or update stats for transaction management messages. + if (!tsx_mgmt) { - _scscf->track_session_setup_time(_tsx_start_time_usec, _video_call); - _record_session_setup_time = false; + ACR* acr = get_acr(); + if (acr != NULL) + { + // Pass the transmitted response to the ACR to update the accounting + // information. + acr->lock(); + acr->tx_response(rsp); + acr->unlock(); + } + + // If this is a transaction where we are supposed to be tracking session + // setup stats then check to see if it is now set up. We consider it to be + // setup when we receive either a 180 Ringing or 2xx (per TS 32.409). + pjsip_status_code st_code = (pjsip_status_code)rsp->line.status.code; + if (_record_session_setup_time && + ((st_code == PJSIP_SC_RINGING) || + (PJSIP_IS_STATUS_IN_CLASS(st_code, 200)))) + { + _scscf->track_session_setup_time(_tsx_start_time_usec, _video_call); + _record_session_setup_time = false; + } } } @@ -2222,6 +2220,29 @@ std::string SCSCFSproutletTsx::fork_failure_reason_as_string(int fork_id, int si return reason; } +void SCSCFSproutletTsx::acr_handle_response(pjsip_msg* rsp) +{ + // Pass the received response to the ACR. + // @TODO - timestamp from response??? + ACR* acr = get_acr(); + if (acr != NULL) + { + acr->lock(); + acr->rx_response(rsp); + acr->unlock(); + } +} + +void SCSCFSproutletTsx::cancel_liveness_timer() +{ + if (_liveness_timer != 0) + { + // The liveness timer is running on this request, so cancel it. + cancel_timer(_liveness_timer); + _liveness_timer = 0; + } +} + pjsip_msg* SCSCFSproutletTsx::get_base_request() { if (_base_req != nullptr) diff --git a/src/sproutletappserver.cpp b/src/sproutletappserver.cpp index 40321a18d..c7e31f708 100644 --- a/src/sproutletappserver.cpp +++ b/src/sproutletappserver.cpp @@ -107,7 +107,7 @@ void SproutletAppServerTsxHelper::store_dialog_id(pjsip_msg* req) /// pjsip_msg* SproutletAppServerTsxHelper::original_request() { - return _helper->original_request(); + return _helper->get_request_for_sproutlet_tsx(); } /// Returns the top Route header from the original incoming request. This diff --git a/src/sproutletproxy.cpp b/src/sproutletproxy.cpp index b704bf438..37cf2ee1f 100644 --- a/src/sproutletproxy.cpp +++ b/src/sproutletproxy.cpp @@ -858,22 +858,6 @@ void SproutletProxy::UASTsx::schedule_requests() _umap[(void*)downstream] = req.upstream; } - if (req.req->msg->line.req.method.id == PJSIP_INVITE_METHOD) - { - // Send an immediate 100 Trying response to the upstream - // Sproutlet. - pjsip_tx_data* trying; - pj_status_t status = PJUtils::create_response(stack_data.endpt, - req.req, - PJSIP_SC_TRYING, - NULL, - &trying); - if (status == PJ_SUCCESS) - { - req.upstream.first->rx_response(trying, req.upstream.second); - } - } - // Pass the request to the downstream sproutlet. downstream->rx_request(req.req); } @@ -980,6 +964,29 @@ void SproutletProxy::UASTsx::tx_response(SproutletWrapper* downstream, { if (downstream == _root) { + // If this is the root sproutlet in the tree, drop any 100 Trying or 200 OK + // to CANCEL responses that the sproutlets generated. These responses have + // already been sent by the basic proxy. + if ((PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_CANCEL_METHOD) || + (rsp->msg->line.status.code == PJSIP_SC_TRYING)) + { + pjsip_tx_data_dec_ref(rsp); + return; + } + + // If this is a negative response to an INVITE, send an ACK downstream to + // the root sproutlet. + if ((PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_INVITE_METHOD) && + (rsp->msg->line.status.code >= 300)) + { + // Build an ACK request from the original request sent on this fork and the + // negative response received. + pjsip_tx_data* ack = PJUtils::create_ack(stack_data.endpt, + downstream->_req->msg, + rsp->msg); + downstream->rx_negative_ack(ack); + } + // This is the root sproutlet in the tree, so send the response on the // UAS transaction. if (_tsx != NULL) @@ -1017,9 +1024,17 @@ void SproutletProxy::UASTsx::tx_response(SproutletWrapper* downstream, SproutletWrapper* upstream = i->second.first; int fork_id = i->second.second; - if (rsp->msg->line.status.code >= PJSIP_SC_OK) + // We break the linkage between the sproutlets if: + // - We receive a 2xx response for an INVITE. For 3xx-6xx responses + // we will break the linkage after sending an ACK to the negative + // response. + // - We receive a final response for other transaction types (excluding + // CANCEL). + if ((rsp->msg->line.status.code >= PJSIP_SC_OK) && + ((PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id != PJSIP_INVITE_METHOD) || + (rsp->msg->line.status.code < 300)) && + (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id != PJSIP_CANCEL_METHOD)) { - // Final response, so break the linkage between the Sproutlets. _dmap_sproutlet.erase(i->second); _umap.erase(i); } @@ -1058,6 +1073,19 @@ void SproutletProxy::UASTsx::tx_cancel(SproutletWrapper* upstream, } else { + TRC_DEBUG("Send immediate 200 OK to CANCEL"); + pjsip_tx_data* ok; + pj_status_t status = PJUtils::create_response(stack_data.endpt, + cancel, + PJSIP_SC_OK, + NULL, + &ok); + + if (status == PJ_SUCCESS) + { + upstream->rx_response(ok, fork_id); + } + DMap::iterator j = _dmap_uac.find(std::make_pair(upstream, fork_id)); if (j != _dmap_uac.end()) { @@ -1074,6 +1102,34 @@ void SproutletProxy::UASTsx::tx_cancel(SproutletWrapper* upstream, } +void SproutletProxy::UASTsx::tx_negative_ack(SproutletWrapper* upstream, + int fork_id, + pjsip_tx_data* ack) +{ + TRC_DEBUG("Process negative ACK from %s on fork %d", + upstream->service_name().c_str(), fork_id); + DMap::iterator i = + _dmap_sproutlet.find(std::make_pair(upstream, fork_id)); + if (i != _dmap_sproutlet.end()) + { + // Pass the ACK request to the downstream Sproutlet. + SproutletWrapper* downstream = i->second; + TRC_DEBUG("Route negative ACK to %s", downstream->service_name().c_str()); + downstream->rx_negative_ack(ack); + + // This is an ACK to a final response so disconnect the sproutlets. + _dmap_sproutlet.erase(std::make_pair(upstream, fork_id)); + UMap::iterator j = _umap.find((void*)downstream); + _umap.erase(j); + } + else + { + // We don't want to route this externally, so drop our reference to it. + pjsip_tx_data_dec_ref(ack); + } +} + + /// Checks to see if the UASTsx can be destroyed. It is only safe to destroy /// the UASTsx when all the Sproutlet's have completed their processing, which /// only occurs when all the linkages are broken. @@ -1201,7 +1257,7 @@ const std::string& SproutletWrapper::service_name() const /// Returns a mutable clone of the original request suitable for forwarding /// or as the basis for constructing a response. -pjsip_msg* SproutletWrapper::original_request() +pjsip_msg* SproutletWrapper::get_request_for_sproutlet_tsx() { pjsip_tx_data* clone = PJUtils::clone_msg(stack_data.endpt, _req); @@ -1225,6 +1281,14 @@ pjsip_msg* SproutletWrapper::original_request() pj_list_erase(hr); } + // Decrement Max-Forwards if present. + pjsip_max_fwd_hdr* mf_hdr = (pjsip_max_fwd_hdr*) + pjsip_msg_find_hdr(clone->msg, PJSIP_H_MAX_FORWARDS, NULL); + if (mf_hdr != NULL) + { + --mf_hdr->ivalue; + } + register_tdata(clone); return clone->msg; @@ -1424,6 +1488,12 @@ void SproutletWrapper::send_response(pjsip_msg*& rsp) return; } + if (rsp->line.status.code == PJSIP_SC_TRYING) + { + TRC_ERROR("Sproutlet attempted to forward a 100 Trying response"); + return; + } + TRC_VERBOSE("%s sending %s", _id.c_str(), pjsip_tx_data_get_info(it->second)); // We've found the tdata, move it to _send_responses. @@ -1592,16 +1662,28 @@ void SproutletWrapper::rx_request(pjsip_tx_data* req) // Keep an immutable reference to the request. _req = req; - // Decrement Max-Forwards if present. - pjsip_max_fwd_hdr* mf_hdr = (pjsip_max_fwd_hdr*) - pjsip_msg_find_hdr(req->msg, PJSIP_H_MAX_FORWARDS, NULL); - if (mf_hdr != NULL) + // Notify the sproutlet that a request has been received. + _sproutlet_tsx->obs_rx_request(req->msg, false); + + if (req->msg->line.req.method.id == PJSIP_INVITE_METHOD) { - --mf_hdr->ivalue; + // Send an immediate 100 Trying response to the upstream + // Sproutlet. + pjsip_tx_data* trying; + pj_status_t status = PJUtils::create_response(stack_data.endpt, + req, + PJSIP_SC_TRYING, + NULL, + &trying); + if (status == PJ_SUCCESS) + { + log_inter_sproutlet(trying, false); + tx_response(trying); + } } // Clone the request to get a mutable copy to pass to the Sproutlet. - pjsip_msg* clone = original_request(); + pjsip_msg* clone = get_request_for_sproutlet_tsx(); if (clone == NULL) { // @TODO @@ -1643,58 +1725,122 @@ void SproutletWrapper::rx_response(pjsip_tx_data* rsp, int fork_id) log_inter_sproutlet(rsp, false); } - register_tdata(rsp); - if ((PJSIP_IS_STATUS_IN_CLASS(rsp->msg->line.status.code, 100)) && - (_forks[fork_id].state.tsx_state == PJSIP_TSX_STATE_CALLING)) + int status_code = rsp->msg->line.status.code; + if ((status_code == PJSIP_SC_TRYING) || + (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_CANCEL_METHOD)) { - // Provisional response on fork still in calling state, so move to - // proceeding state. - _forks[fork_id].state.tsx_state = PJSIP_TSX_STATE_PROCEEDING; - TRC_VERBOSE("%s received provisional response %s on fork %d, state = %s", - _id.c_str(), pjsip_tx_data_get_info(rsp), - fork_id, pjsip_tsx_state_str(_forks[fork_id].state.tsx_state)); + _sproutlet_tsx->obs_rx_response(rsp->msg, fork_id, true); } - else if (rsp->msg->line.status.code >= PJSIP_SC_OK) + else { - // Final response, so mark the fork as completed and decrement the number - // of pending responses. - _forks[fork_id].state.tsx_state = PJSIP_TSX_STATE_TERMINATED; - pjsip_tx_data_dec_ref(_forks[fork_id].req); - _forks[fork_id].req = NULL; - TRC_VERBOSE("%s received final response %s on fork %d, state = %s", - _id.c_str(), pjsip_tx_data_get_info(rsp), - fork_id, pjsip_tsx_state_str(_forks[fork_id].state.tsx_state)); - --_pending_responses; + _sproutlet_tsx->obs_rx_response(rsp->msg, fork_id, false); + } - if ((_sproutlet != NULL) && - (_sproutlet->_outgoing_sip_transactions_tbl != NULL)) + // If this is a negative response to an INVITE, send an immediate ACK + // to the downstream sproutlet. + if ((status_code >= 300) && + (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_INVITE_METHOD)) + { + TRC_DEBUG("Send immediate ACK to negative response"); + tx_negative_ack(rsp, fork_id); + } + + if (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_CANCEL_METHOD) + { + pjsip_tx_data_dec_ref(rsp); + } + else + { + register_tdata(rsp); + if ((PJSIP_IS_STATUS_IN_CLASS(status_code, 100)) && + (_forks[fork_id].state.tsx_state == PJSIP_TSX_STATE_CALLING)) { - // Update SNMP SIP transactions statistics for the Sproutlet. - if (rsp->msg->line.status.code >= 200 && rsp->msg->line.status.code < 300) - { - _sproutlet->_outgoing_sip_transactions_tbl->increment_successes(_req_type); - } - else + // Provisional response on fork still in calling state, so move to + // proceeding state. + _forks[fork_id].state.tsx_state = PJSIP_TSX_STATE_PROCEEDING; + TRC_VERBOSE("%s received provisional response %s on fork %d, state = %s", + _id.c_str(), pjsip_tx_data_get_info(rsp), + fork_id, pjsip_tsx_state_str(_forks[fork_id].state.tsx_state)); + } + else if (status_code >= PJSIP_SC_OK) + { + // Final response, so mark the fork as completed and decrement the number + // of pending responses. + _forks[fork_id].state.tsx_state = PJSIP_TSX_STATE_TERMINATED; + pjsip_tx_data_dec_ref(_forks[fork_id].req); + _forks[fork_id].req = NULL; + TRC_VERBOSE("%s received final response %s on fork %d, state = %s", + _id.c_str(), pjsip_tx_data_get_info(rsp), + fork_id, pjsip_tsx_state_str(_forks[fork_id].state.tsx_state)); + --_pending_responses; + + if ((_sproutlet != NULL) && + (_sproutlet->_outgoing_sip_transactions_tbl != NULL)) { - _sproutlet->_outgoing_sip_transactions_tbl->increment_failures(_req_type); + // Update SNMP SIP transactions statistics for the Sproutlet. + if (status_code >= 200 && status_code < 300) + { + _sproutlet->_outgoing_sip_transactions_tbl->increment_successes(_req_type); + } + else + { + _sproutlet->_outgoing_sip_transactions_tbl->increment_failures(_req_type); + } } } - } - _sproutlet_tsx->on_rx_response(rsp->msg, fork_id); - process_actions(false); + if (status_code == PJSIP_SC_TRYING) + { + _sproutlet_tsx->on_rx_trying(rsp->msg, fork_id); + deregister_tdata(rsp); + pjsip_tx_data_dec_ref(rsp); + } + else + { + _sproutlet_tsx->on_rx_response(rsp->msg, fork_id); + } + process_actions(false); + } } void SproutletWrapper::rx_cancel(pjsip_tx_data* cancel) { TRC_VERBOSE("%s received CANCEL request", _id.c_str()); + + // Notify the sproutlet that a request has been received. + _sproutlet_tsx->obs_rx_request(cancel->msg, true); + + TRC_DEBUG("Send immediate 200 OK to CANCEL"); + pjsip_tx_data* ok; + pj_status_t status = PJUtils::create_response(stack_data.endpt, + cancel, + PJSIP_SC_OK, + NULL, + &ok); + + if (status == PJ_SUCCESS) + { + tx_response(ok); + } + _sproutlet_tsx->on_rx_cancel(PJSIP_SC_REQUEST_TERMINATED, - cancel->msg); + cancel->msg); pjsip_tx_data_dec_ref(cancel); cancel_pending_forks(); process_actions(false); } +void SproutletWrapper::rx_negative_ack(pjsip_tx_data* ack) +{ + TRC_VERBOSE("%s received negative ACK request", _id.c_str()); + + // Notify the sproutlet that an a negative ACK has been received and then + // drop our reference to this request. + _sproutlet_tsx->obs_rx_request(ack->msg, true); + + pjsip_tx_data_dec_ref(ack); +} + void SproutletWrapper::rx_error(int status_code) { TRC_VERBOSE("%s received error %d", _id.c_str(), status_code); @@ -1879,16 +2025,6 @@ void SproutletWrapper::aggregate_response(pjsip_tx_data* rsp) return; } - if (status_code == 100) - { - // We will already have sent a locally generated 100 Trying response, so - // don't forward this one. - TRC_DEBUG("Discard 100/INVITE response (%s)", rsp->obj_name); - deregister_tdata(rsp); - pjsip_tx_data_dec_ref(rsp); - return; - } - if ((status_code > 100) && (status_code < 199)) { @@ -1969,7 +2105,7 @@ void SproutletWrapper::tx_request(pjsip_tx_data* req, int fork_id) } // Notify the sproutlet that the request is being sent downstream. - _sproutlet_tsx->on_tx_request(req->msg, fork_id); + _sproutlet_tsx->obs_tx_request(req->msg, fork_id, false); // Forward the request downstream. deregister_tdata(req); @@ -1978,10 +2114,10 @@ void SproutletWrapper::tx_request(pjsip_tx_data* req, int fork_id) void SproutletWrapper::tx_response(pjsip_tx_data* rsp) { - // Notify the sproutlet that the response is being sent upstream. - _sproutlet_tsx->on_tx_response(rsp->msg); - - if (rsp->msg->line.status.code >= PJSIP_SC_OK) + // We only treat this as a final response if the status code is >= 200 and + // this is not a 200 OK to a CANCEL. + if ((rsp->msg->line.status.code >= PJSIP_SC_OK) && + (PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id != PJSIP_CANCEL_METHOD)) { _complete = true; cancel_pending_forks(); @@ -2001,6 +2137,17 @@ void SproutletWrapper::tx_response(pjsip_tx_data* rsp) } } + // Notify the sproutlet that the response is being sent upstream. + if ((PJSIP_MSG_CSEQ_HDR(rsp->msg)->method.id == PJSIP_CANCEL_METHOD) || + (rsp->msg->line.status.code == PJSIP_SC_TRYING)) + { + _sproutlet_tsx->obs_tx_response(rsp->msg, true); + } + else + { + _sproutlet_tsx->obs_tx_response(rsp->msg, false); + } + // Forward the response upstream. deregister_tdata(rsp); _proxy_tsx->tx_response(this, rsp); @@ -2013,10 +2160,22 @@ void SproutletWrapper::tx_cancel(int fork_id) pjsip_tx_data* cancel = PJUtils::create_cancel(stack_data.endpt, _forks[fork_id].req, _forks[fork_id].cancel_reason); + _sproutlet_tsx->obs_tx_request(cancel->msg, fork_id, true); _proxy_tsx->tx_cancel(this, fork_id, cancel); _forks[fork_id].pending_cancel = false; } +void SproutletWrapper::tx_negative_ack(pjsip_tx_data* rsp, int fork_id) +{ + // Build an ACK request from the original request sent on this fork and the + // negative response received. + pjsip_tx_data* ack = PJUtils::create_ack(stack_data.endpt, + _forks[fork_id].req->msg, + rsp->msg); + _sproutlet_tsx->obs_tx_request(ack->msg, fork_id, true); + _proxy_tsx->tx_negative_ack(this, fork_id, ack); +} + /// Compare two status codes from the perspective of which is the best to /// return to the originator of a forked transaction. This will only ever /// be called for 3xx/4xx/5xx/6xx response codes. diff --git a/src/ut/mock_sproutlet.h b/src/ut/mock_sproutlet.h index 32aba09c6..56dc51ba9 100644 --- a/src/ut/mock_sproutlet.h +++ b/src/ut/mock_sproutlet.h @@ -72,9 +72,11 @@ class MockSproutletTsx : public SproutletTsx MOCK_METHOD1(on_rx_initial_request, void(pjsip_msg*)); MOCK_METHOD1(on_rx_in_dialog_request, void(pjsip_msg*)); - MOCK_METHOD2(on_tx_request, void(pjsip_msg*, int)); + MOCK_METHOD2(obs_rx_request, void(pjsip_msg*, bool)); + MOCK_METHOD3(obs_tx_request, void(pjsip_msg*, int, bool)); MOCK_METHOD2(on_rx_response, void(pjsip_msg*, int)); - MOCK_METHOD1(on_tx_response, void(pjsip_msg*)); + MOCK_METHOD3(obs_rx_response, void(pjsip_msg*, int, bool)); + MOCK_METHOD2(obs_tx_response, void(pjsip_msg*, bool)); MOCK_METHOD2(on_rx_cancel, void(int, pjsip_msg*)); MOCK_METHOD1(on_timer_expiry, void(void*)); }; diff --git a/src/ut/mocktsxhelper.h b/src/ut/mocktsxhelper.h index 610b3d63a..fe32b7466 100644 --- a/src/ut/mocktsxhelper.h +++ b/src/ut/mocktsxhelper.h @@ -56,7 +56,7 @@ class MockSproutletTsxHelper : public SproutletTsxHelper SAS::TrailId trail() const {return _trail;} SAS::TrailId _trail; - MOCK_METHOD0(original_request, pjsip_msg*()); + MOCK_METHOD0(get_request_for_sproutlet_tsx, pjsip_msg*()); MOCK_CONST_METHOD0(route_hdr, const pjsip_route_hdr*()); MOCK_CONST_METHOD1(get_reflexive_uri, pjsip_sip_uri*(pj_pool_t*)); MOCK_CONST_METHOD1(is_uri_reflexive, bool(const pjsip_uri*)); diff --git a/src/ut/sproutletproxy_test.cpp b/src/ut/sproutletproxy_test.cpp index 70abbbf7b..6dce5aba7 100644 --- a/src/ut/sproutletproxy_test.cpp +++ b/src/ut/sproutletproxy_test.cpp @@ -154,6 +154,13 @@ class FakeSproutletTsxForwarder : public SproutletTsx { send_response(rsp); } + + void on_rx_trying(pjsip_msg* rsp, int fork_id) + { + // Sproutlets shouldn't call send_response for 100 Trying responses, but + // let's check here that the sproutlet proxy handles it if they do. + send_response(rsp); + } }; class FakeSproutletTsxDownstreamRequest : public SproutletTsx