diff --git a/include/asterisk/res_pjsip_presence_xml.h b/include/asterisk/res_pjsip_presence_xml.h index add5f89..deed090 100644 --- a/include/asterisk/res_pjsip_presence_xml.h +++ b/include/asterisk/res_pjsip_presence_xml.h @@ -17,14 +17,15 @@ */ /*! - * \brief The length of the XML prolog when printing - * presence or other XML in PJSIP. + * \brief Length of the XML prolog when printing presence or other XML in PJSIP. * * When calling any variant of pj_xml_print(), the documentation * claims that it will return -1 if the provided buffer is not * large enough. However, if the XML prolog is requested to be - * printed, then the length of the XML prolog is returned upon - * failure instead of -1. + * printed and the buffer is not large enough, then it will + * return -1 only if the buffer is not large enough to hold the + * XML prolog or return the length of the XML prolog on failure + * instead of -1. * * This constant is useful to check against when trying to determine * if printing XML succeeded or failed. diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c index d9725f4..48ac60f 100644 --- a/res/res_pjsip_dialog_info_body_generator.c +++ b/res/res_pjsip_dialog_info_body_generator.c @@ -163,14 +163,13 @@ static void dialog_info_to_string(void *body, struct ast_str **str) int size; do { - size = pj_xml_print(dialog_info, ast_str_buffer(*str), ast_str_size(*str), PJ_TRUE); - if (size == AST_PJSIP_XML_PROLOG_LEN) { + size = pj_xml_print(dialog_info, ast_str_buffer(*str), ast_str_size(*str) - 1, PJ_TRUE); + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_str_make_space(str, ast_str_size(*str) * 2); ++growths; } - } while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); - - if (size == AST_PJSIP_XML_PROLOG_LEN) { + } while (size <= AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_log(LOG_WARNING, "dialog-info+xml body text too large\n"); return; } diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c index 2ab7dfe..212ec1c 100644 --- a/res/res_pjsip_mwi.c +++ b/res/res_pjsip_mwi.c @@ -138,9 +138,17 @@ static struct mwi_stasis_subscription *mwi_stasis_subscription_alloc(const char /* Safe strcpy */ strcpy(mwi_stasis_sub->mailbox, mailbox); + + ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n", + mailbox, mwi_sub->id); ao2_ref(mwi_sub, +1); - ast_debug(3, "Creating stasis MWI subscription to mailbox %s for endpoint %s\n", mailbox, mwi_sub->id); mwi_stasis_sub->stasis_sub = stasis_subscribe_pool(topic, mwi_stasis_cb, mwi_sub); + if (!mwi_stasis_sub->stasis_sub) { + /* Failed to subscribe. */ + ao2_ref(mwi_stasis_sub, -1); + ao2_ref(mwi_sub, -1); + mwi_stasis_sub = NULL; + } return mwi_stasis_sub; } @@ -488,22 +496,38 @@ static void mwi_subscription_shutdown(struct ast_sip_subscription *sub) mwi_sub = mwi_datastore->data; ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL); + ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE); +} + +static void mwi_ds_destroy(void *data) +{ + struct mwi_subscription *sub = data; + + ao2_ref(sub, -1); } -static struct ast_datastore_info mwi_ds_info = { }; +static struct ast_datastore_info mwi_ds_info = { + .destroy = mwi_ds_destroy, +}; static int add_mwi_datastore(struct mwi_subscription *sub) { RAII_VAR(struct ast_datastore *, mwi_datastore, NULL, ao2_cleanup); + int res; mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE); if (!mwi_datastore) { return -1; } + ao2_ref(sub, +1); mwi_datastore->data = sub; - ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore); - return 0; + /* + * NOTE: Adding the datastore to the subscription creates a ref loop + * that must be manually broken. + */ + res = ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore); + return res; } /*! @@ -617,8 +641,8 @@ static struct mwi_subscription *mwi_create_subscription( } if (add_mwi_datastore(sub)) { - ast_log(LOG_WARNING, "Unable to allocate datastore on MWI " - "subscription from %s\n", sub->id); + ast_log(LOG_WARNING, "Unable to add datastore for MWI subscription to %s\n", + sub->id); ao2_ref(sub, -1); return NULL; } @@ -711,12 +735,19 @@ static int mwi_subscription_established(struct ast_sip_subscription *sip_sub) } else { sub = mwi_subscribe_single(endpoint, sip_sub, resource); } - if (!sub) { ao2_cleanup(endpoint); return -1; } + if (!ao2_container_count(sub->stasis_subs)) { + /* + * We setup no MWI subscriptions so remove the MWI datastore + * to break the ref loop. + */ + ast_sip_subscription_remove_datastore(sip_sub, MWI_DATASTORE); + } + ao2_cleanup(sub); ao2_cleanup(endpoint); return 0; diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c index ef0cce5..d3be8c1 100644 --- a/res/res_pjsip_pidf_body_generator.c +++ b/res/res_pjsip_pidf_body_generator.c @@ -84,19 +84,18 @@ static int pidf_generate_body_content(void *body, void *data) static void pidf_to_string(void *body, struct ast_str **str) { - int size; - int growths = 0; pjpidf_pres *pres = body; + int growths = 0; + int size; do { size = pjpidf_print(pres, ast_str_buffer(*str), ast_str_size(*str) - 1); - if (size == AST_PJSIP_XML_PROLOG_LEN) { + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_str_make_space(str, ast_str_size(*str) * 2); ++growths; } - } while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); - - if (size == AST_PJSIP_XML_PROLOG_LEN) { + } while (size <= AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_log(LOG_WARNING, "PIDF body text too large\n"); return; } diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index 74a3f19..8eda30c 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -1766,7 +1766,7 @@ static int rlmi_print_body(struct pjsip_msg_body *msg_body, char *buf, pj_size_t pj_xml_node *rlmi = msg_body->data; num_printed = pj_xml_print(rlmi, buf, size, PJ_TRUE); - if (num_printed == AST_PJSIP_XML_PROLOG_LEN) { + if (num_printed <= AST_PJSIP_XML_PROLOG_LEN) { return -1; } diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 87ce2b0..8ec367a 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1039,7 +1039,10 @@ void ast_sip_session_resume_reinvite(struct ast_sip_session *session) return; } - pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), session->deferred_reinvite, NULL, NULL); + if (session->channel) { + pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), + session->deferred_reinvite, NULL, NULL); + } pjsip_rx_data_free_cloned(session->deferred_reinvite); session->deferred_reinvite = NULL; } diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c index 06a73cc..e7a0da3 100644 --- a/res/res_pjsip_t38.c +++ b/res/res_pjsip_t38.c @@ -135,10 +135,13 @@ static void t38_change_state(struct ast_sip_session *session, struct ast_sip_ses } session->t38state = new_state; - ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n", new_state, old_state, ast_channel_name(session->channel)); + ast_debug(2, "T.38 state changed to '%u' from '%u' on channel '%s'\n", + new_state, old_state, + session->channel ? ast_channel_name(session->channel) : ""); if (pj_timer_heap_cancel(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()), &state->timer)) { - ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n", ast_channel_name(session->channel)); + ast_debug(2, "Automatic T.38 rejection on channel '%s' terminated\n", + session->channel ? ast_channel_name(session->channel) : ""); ao2_ref(session, -1); } @@ -198,7 +201,12 @@ static int t38_automatic_reject(void *obj) return 0; } - ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", ast_channel_name(session->channel)); + if (!session->channel) { + /* If you see this message and it doesn't crash then the bug is fixed. */ + ast_log(LOG_NOTICE, "BUGBUG T.38 auto reject timer expired without a session channel.\n"); + } + ast_debug(2, "Automatically rejecting T.38 request on channel '%s'\n", + session->channel ? ast_channel_name(session->channel) : ""); t38_change_state(session, session_media, datastore->data, T38_REJECTED); ast_sip_session_resume_reinvite(session); @@ -227,9 +235,9 @@ static struct t38_state *t38_state_get_or_alloc(struct ast_sip_session *session) return datastore->data; } - if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38")) || - !(datastore->data = ast_calloc(1, sizeof(struct t38_state))) || - ast_sip_session_add_datastore(session, datastore)) { + if (!(datastore = ast_sip_session_alloc_datastore(&t38_datastore, "t38")) + || !(datastore->data = ast_calloc(1, sizeof(struct t38_state))) + || ast_sip_session_add_datastore(session, datastore)) { return NULL; } @@ -324,9 +332,14 @@ static int t38_interpret_parameters(void *obj) case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */ /* Negotiation can not take place without a valid max_ifp value. */ if (!parameters->max_ifp) { - t38_change_state(data->session, session_media, state, T38_REJECTED); + ast_log(LOG_NOTICE, "BUGBUG No max_ifp value. Rejecting or dropping T.38\n"); if (data->session->t38state == T38_PEER_REINVITE) { + t38_change_state(data->session, session_media, state, T38_REJECTED); ast_sip_session_resume_reinvite(data->session); + } else if (data->session->t38state == T38_ENABLED) { + t38_change_state(data->session, session_media, state, T38_DISABLED); + ast_sip_session_refresh(data->session, NULL, NULL, NULL, + AST_SIP_SESSION_REFRESH_METHOD_INVITE, 1); } break; } else if (data->session->t38state == T38_PEER_REINVITE) { diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c index 43cb1e7..298235c 100644 --- a/res/res_pjsip_xpidf_body_generator.c +++ b/res/res_pjsip_xpidf_body_generator.c @@ -106,14 +106,13 @@ static void xpidf_to_string(void *body, struct ast_str **str) int size; do { - size = pjxpidf_print(pres, ast_str_buffer(*str), ast_str_size(*str)); - if (size == AST_PJSIP_XML_PROLOG_LEN) { + size = pjxpidf_print(pres, ast_str_buffer(*str), ast_str_size(*str) - 1); + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_str_make_space(str, ast_str_size(*str) * 2); ++growths; } - } while (size == AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); - - if (size == AST_PJSIP_XML_PROLOG_LEN) { + } while (size <= AST_PJSIP_XML_PROLOG_LEN && growths < MAX_STRING_GROWTHS); + if (size <= AST_PJSIP_XML_PROLOG_LEN) { ast_log(LOG_WARNING, "XPIDF body text too large\n"); return; }