diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c index 4c30d335b2..de645b09fb 100644 --- a/channels/chan_pjsip.c +++ b/channels/chan_pjsip.c @@ -670,7 +670,11 @@ static int answer(void *data) pjsip_dlg_dec_lock(session->inv_session->dlg); if (status == PJ_SUCCESS && packet) { - ast_sip_session_send_response(session, packet); + if (ast_sip_session_send_response(session, packet)) { + ast_log(LOG_ERROR,"Cannot answer '%s' because sending the response failed\n", + ast_channel_name(session->channel)); + status = PJSIP_ETSXDESTROYED; + } } #ifdef HAVE_PJSIP_INV_SESSION_REF @@ -1865,7 +1869,13 @@ static void transfer_redirect(struct ast_sip_session *session, const char *targe } pjsip_msg_add_hdr(packet->msg, (pjsip_hdr *) contact); - ast_sip_session_send_response(session, packet); + if (ast_sip_session_send_response(session, packet)) { + message = AST_TRANSFER_FAILED; + ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message)); + + return; + } + ast_queue_control_data(session->channel, AST_CONTROL_TRANSFER, &message, sizeof(message)); } diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h index ddcebd70bc..642a248a4c 100644 --- a/include/asterisk/res_pjsip_session.h +++ b/include/asterisk/res_pjsip_session.h @@ -710,8 +710,12 @@ int ast_sip_session_regenerate_answer(struct ast_sip_session *session, * * \param session The session on which to send the response. * \param tdata The response to send + * \retval 0 Successfully sent response + * \retval -1 Failed to send response + * + * \note Regardless of return status, tdata will have its reference count decremented. */ -void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata); +int ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata); /*! * \brief Send a SIP request diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 7867c52c12..f9b81bfd4a 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -4027,7 +4027,7 @@ int ast_sip_failover_request(pjsip_tx_data *tdata) { pjsip_via_hdr *via; - if (!tdata->dest_info.addr.count || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) { + if (!tdata || !tdata->dest_info.addr.count || (tdata->dest_info.cur_addr == tdata->dest_info.addr.count - 1)) { /* No more addresses to try */ return 0; } diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c index b4828d89fb..604af60943 100644 --- a/res/res_pjsip/pjsip_distributor.c +++ b/res/res_pjsip/pjsip_distributor.c @@ -848,13 +848,19 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) if (!is_ack && ast_sip_requires_authentication(endpoint, rdata)) { pjsip_tx_data *tdata; struct unidentified_request *unid; + pj_status_t status; pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 401, NULL, &tdata); + switch (ast_sip_check_authentication(endpoint, rdata, tdata)) { case AST_SIP_AUTHENTICATION_CHALLENGE: /* Send the 401 we created for them */ ast_sip_report_auth_challenge_sent(endpoint, rdata, tdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + status = pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + /* pjsip_endpt_send_response2 only decrements the tdata ref count on success */ + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_SUCCESS: /* See note in endpoint_lookup about not holding an unnecessary write lock */ @@ -867,7 +873,12 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata) case AST_SIP_AUTHENTICATION_FAILED: log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); - pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + /* pjsip_endpt_send_response2 doesn't decrement the tdata ref count on failure */ + status = pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL); + if (status != PJ_SUCCESS) { + /* pjsip_endpt_send_response2 only decrements the tdata ref count on success */ + pjsip_tx_data_dec_ref(tdata); + } return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: log_failed_request(rdata, "Error to authenticate", 0, 0); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index f0606d67fa..252833465b 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1712,11 +1712,51 @@ int ast_sip_session_regenerate_answer(struct ast_sip_session *session, return 0; } -void ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata) +static int send_inv_msg(struct pjsip_inv_session *inv_session, pjsip_tx_data *tdata) { + pj_status_t status; + + if (inv_session->state == PJSIP_INV_STATE_DISCONNECTED || + inv_session->invite_tsx == NULL) { + ast_log(LOG_ERROR, "Can't send response. %s %s already disconnected [reason=%d (%s)]\n", + inv_session->obj_name, tdata->obj_name, + inv_session->cause, + pjsip_get_status_text(inv_session->cause)->ptr); + pjsip_tx_data_dec_ref(tdata); + return -1; + } + + status = pjsip_inv_send_msg(inv_session, tdata); + if (status != PJ_SUCCESS) { + ast_log(LOG_ERROR, "Can't send response. %s %s [reason=%d (%s)]\n", + inv_session->obj_name, tdata->obj_name, + inv_session->cause, + pjsip_get_status_text(inv_session->cause)->ptr); + return -1; + } + + return 0; +} + +int ast_sip_session_send_response(struct ast_sip_session *session, pjsip_tx_data *tdata) +{ + int rc; + + if (session->inv_session->state == PJSIP_INV_STATE_DISCONNECTED + || session->inv_session->invite_tsx == NULL + || session->inv_session->invite_tsx->state >= PJSIP_TSX_STATE_TERMINATED ) { + ast_log(LOG_ERROR, "Can't send response. Session %p already DISCONNECTED %s %s [reason=%d (%s)]\n", + session, session->inv_session->obj_name, tdata->obj_name, + session->inv_session->cause, + pjsip_get_status_text(session->inv_session->cause)->ptr); + pjsip_tx_data_dec_ref(tdata); + return -1; + } + handle_outgoing_response(session, tdata); - pjsip_inv_send_msg(session->inv_session, tdata); - return; + + rc = send_inv_msg(session->inv_session, tdata); + return rc; } static pj_bool_t session_on_rx_request(pjsip_rx_data *rdata); @@ -1978,7 +2018,7 @@ void ast_sip_session_send_request_with_cb(struct ast_sip_session *session, pjsip MOD_DATA_ON_RESPONSE, on_response); handle_outgoing_request(session, tdata); - pjsip_inv_send_msg(session->inv_session, tdata); + send_inv_msg(session->inv_session, tdata); return; } @@ -2862,16 +2902,36 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a } return NULL; } + dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status); if (!dlg) { if (dlg_status != PJ_EEXISTS) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); } + if (tdata) { + pjsip_tx_data_dec_ref(tdata); + } return NULL; } + + if (rdata->tp_info.transport->is_destroying || rdata->tp_info.transport->is_shutdown) { + ast_log(LOG_WARNING, "Connection from %s:%d terminated unexpectedly %s\n", + rdata->pkt_info.src_name, rdata->pkt_info.src_port, tdata ? tdata->obj_name : "no tdata"); + pjsip_dlg_terminate(dlg); + if (tdata) { + pjsip_tx_data_dec_ref(tdata); + } + return NULL; + } + if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) { + ast_log(LOG_WARNING, "Unable to create inv_session for %s:%d %s\n", + rdata->pkt_info.src_name, rdata->pkt_info.src_port, tdata ? tdata->obj_name : "no tdata"); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); pjsip_dlg_terminate(dlg); + if (tdata) { + pjsip_tx_data_dec_ref(tdata); + } return NULL; } @@ -2879,12 +2939,14 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a inv_session->sdp_neg_flags = PJMEDIA_SDP_NEG_ALLOW_MEDIA_CHANGE; #endif if (pjsip_dlg_add_usage(dlg, &session_module, NULL) != PJ_SUCCESS) { + pjsip_tx_data_dec_ref(tdata); if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) != PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } - pjsip_inv_send_msg(inv_session, tdata); + send_inv_msg(inv_session, tdata); return NULL; } + return inv_session; } @@ -2923,7 +2985,7 @@ static int new_invite(struct new_invite *invite) break; case SIP_GET_DEST_UNSUPPORTED_URI: if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 416, NULL, NULL, &tdata) == PJ_SUCCESS) { - ast_sip_session_send_response(invite->session, tdata); + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); } else { pjsip_inv_terminate(invite->session->inv_session, 416, PJ_TRUE); } @@ -2933,7 +2995,7 @@ static int new_invite(struct new_invite *invite) invite->rdata->tp_info.transport->type_name, invite->rdata->pkt_info.src_name, invite->rdata->pkt_info.src_port, invite->session->exten); if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 484, NULL, NULL, &tdata) == PJ_SUCCESS) { - ast_sip_session_send_response(invite->session, tdata); + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); } else { pjsip_inv_terminate(invite->session->inv_session, 484, PJ_TRUE); } @@ -2945,7 +3007,7 @@ static int new_invite(struct new_invite *invite) invite->rdata->pkt_info.src_port, invite->session->exten, invite->session->endpoint->context); if (pjsip_inv_initial_answer(invite->session->inv_session, invite->rdata, 404, NULL, NULL, &tdata) == PJ_SUCCESS) { - ast_sip_session_send_response(invite->session, tdata); + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); } else { pjsip_inv_terminate(invite->session->inv_session, 404, PJ_TRUE); } @@ -2966,7 +3028,11 @@ static int new_invite(struct new_invite *invite) pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); goto end; } - ast_sip_session_send_response(invite->session, tdata); + + if (ast_sip_session_send_response(invite->session, tdata)) { + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_FALSE); + goto end; + } sdp_info = pjsip_rdata_get_sdp_info(invite->rdata); if (sdp_info && (sdp_info->sdp_err == PJ_SUCCESS) && sdp_info->sdp) { @@ -2974,7 +3040,9 @@ static int new_invite(struct new_invite *invite) tdata = NULL; if (pjsip_inv_end_session(invite->session->inv_session, 488, NULL, &tdata) == PJ_SUCCESS && tdata) { - ast_sip_session_send_response(invite->session, tdata); + if (ast_sip_session_send_response(invite->session, tdata)) { + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_FALSE); + } } goto end; } @@ -2990,7 +3058,9 @@ static int new_invite(struct new_invite *invite) tdata = NULL; if (pjsip_inv_end_session(invite->session->inv_session, 500, NULL, &tdata) == PJ_SUCCESS && tdata) { - ast_sip_session_send_response(invite->session, tdata); + if (ast_sip_session_send_response(invite->session, tdata)) { + pjsip_inv_terminate(invite->session->inv_session, 500, PJ_TRUE); + } } goto end; } @@ -3031,14 +3101,10 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) #ifdef HAVE_PJSIP_INV_SESSION_REF if (pjsip_inv_add_ref(inv_session) != PJ_SUCCESS) { - ast_log(LOG_ERROR, "Can't increase the session reference counter\n"); - if (inv_session->state != PJSIP_INV_STATE_DISCONNECTED) { - if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { - pjsip_inv_terminate(inv_session, 500, PJ_FALSE); - } else { - pjsip_inv_send_msg(inv_session, tdata); - } - } + /* If we can't even increase the ref count on the inv_session, something is seriously + * wrong so don't do anything else with it. + */ + ast_log(LOG_ERROR, "Can't increase the session reference counter %p\n", inv_session); return; } #endif @@ -3048,7 +3114,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata) if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) { pjsip_inv_terminate(inv_session, 500, PJ_FALSE); } else { - pjsip_inv_send_msg(inv_session, tdata); + send_inv_msg(inv_session, tdata); } #ifdef HAVE_PJSIP_INV_SESSION_REF pjsip_inv_dec_ref(inv_session);