From 6e192a0f6f62971bc10311ea7e6f63cfac263c9c Mon Sep 17 00:00:00 2001 From: Joshua Colp Date: Tue, 9 Jul 2013 11:05:48 +0000 Subject: Ensure all pjsip_regc_* access occurs within a pjlib thread. (closes issue ASTERISK-22054) Reported by: Rusty Newton git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393870 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- res/res_sip_outbound_registration.c | 87 ++++++++++++++++++++++--------------- 1 file changed, 52 insertions(+), 35 deletions(-) (limited to 'res') diff --git a/res/res_sip_outbound_registration.c b/res/res_sip_outbound_registration.c index d3c4ad815..b80b85b61 100644 --- a/res/res_sip_outbound_registration.c +++ b/res/res_sip_outbound_registration.c @@ -568,33 +568,15 @@ static int can_reuse_registration(struct sip_outbound_registration *existing, st return 1; } -/*! \brief Apply function which finds or allocates a state structure */ -static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj) +/*! \brief Helper function that allocates a pjsip registration client and configures it */ +static int sip_outbound_registration_regc_alloc(void *data) { - RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup); - struct sip_outbound_registration *applied = obj; + struct sip_outbound_registration *registration = data; pj_str_t server_uri, client_uri, contact_uri; pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, }; - if (!existing) { - /* If no existing registration exists we can just start fresh easily */ - applied->state = sip_outbound_registration_state_alloc(); - } else { - /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */ - if (can_reuse_registration(existing, applied)) { - applied->state = existing->state; - ao2_ref(applied->state, +1); - return 0; - } - applied->state = sip_outbound_registration_state_alloc(); - } - - if (!applied->state) { - return -1; - } - - if (!ast_strlen_zero(applied->transport)) { - RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", applied->transport), ao2_cleanup); + if (!ast_strlen_zero(registration->transport)) { + RAII_VAR(struct ast_sip_transport *, transport, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", registration->transport), ao2_cleanup); if (!transport || !transport->state) { return -1; @@ -611,43 +593,69 @@ static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, vo } } - pjsip_regc_set_transport(applied->state->client_state->client, &selector); + pjsip_regc_set_transport(registration->state->client_state->client, &selector); - if (!ast_strlen_zero(applied->outbound_proxy)) { + if (!ast_strlen_zero(registration->outbound_proxy)) { pjsip_route_hdr route_set, *route; static const pj_str_t ROUTE_HNAME = { "Route", 5 }; pj_str_t tmp; pj_list_init(&route_set); - pj_strdup2_with_null(pjsip_regc_get_pool(applied->state->client_state->client), &tmp, applied->outbound_proxy); - if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(applied->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) { + pj_strdup2_with_null(pjsip_regc_get_pool(registration->state->client_state->client), &tmp, registration->outbound_proxy); + if (!(route = pjsip_parse_hdr(pjsip_regc_get_pool(registration->state->client_state->client), &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL))) { return -1; } pj_list_push_back(&route_set, route); - pjsip_regc_set_route_set(applied->state->client_state->client, &route_set); + pjsip_regc_set_route_set(registration->state->client_state->client, &route_set); } - pj_cstr(&server_uri, applied->server_uri); + pj_cstr(&server_uri, registration->server_uri); - if (sip_dialog_create_contact(pjsip_regc_get_pool(applied->state->client_state->client), &contact_uri, S_OR(applied->contact_user, "s"), &server_uri, &selector)) { + if (sip_dialog_create_contact(pjsip_regc_get_pool(registration->state->client_state->client), &contact_uri, S_OR(registration->contact_user, "s"), &server_uri, &selector)) { return -1; } - pj_cstr(&client_uri, applied->client_uri); + pj_cstr(&client_uri, registration->client_uri); - if (pjsip_regc_init(applied->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, applied->expiration) != PJ_SUCCESS) { + if (pjsip_regc_init(registration->state->client_state->client, &server_uri, &client_uri, &client_uri, 1, &contact_uri, registration->expiration) != PJ_SUCCESS) { return -1; } return 0; } +/*! \brief Apply function which finds or allocates a state structure */ +static int sip_outbound_registration_apply(const struct ast_sorcery *sorcery, void *obj) +{ + RAII_VAR(struct sip_outbound_registration *, existing, ast_sorcery_retrieve_by_id(sorcery, "registration", ast_sorcery_object_get_id(obj)), ao2_cleanup); + struct sip_outbound_registration *applied = obj; + + if (!existing) { + /* If no existing registration exists we can just start fresh easily */ + applied->state = sip_outbound_registration_state_alloc(); + } else { + /* If there is an existing registration things are more complicated, we can immediately reuse this state if most stuff remains unchanged */ + if (can_reuse_registration(existing, applied)) { + applied->state = existing->state; + ao2_ref(applied->state, +1); + return 0; + } + applied->state = sip_outbound_registration_state_alloc(); + } + + if (!applied->state) { + return -1; + } + + return ast_sip_push_task_synchronous(NULL, sip_outbound_registration_regc_alloc, applied); +} + /*! \brief Helper function which performs a single registration */ -static int sip_outbound_registration_perform(void *obj, void *arg, int flags) +static int sip_outbound_registration_perform(void *data) { - struct sip_outbound_registration *registration = obj; + RAII_VAR(struct sip_outbound_registration *, registration, data, ao2_cleanup); size_t i; /* Just in case the client state is being reused for this registration, free the auth information */ @@ -675,12 +683,21 @@ static int sip_outbound_registration_perform(void *obj, void *arg, int flags) static void sip_outbound_registration_perform_all(void) { RAII_VAR(struct ao2_container *, registrations, ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "registration", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL), ao2_cleanup); + struct ao2_iterator i; + struct sip_outbound_registration *registration; if (!registrations) { return; } - ao2_callback(registrations, OBJ_NODATA, sip_outbound_registration_perform, NULL); + i = ao2_iterator_init(registrations, 0); + while ((registration = ao2_iterator_next(&i))) { + if (ast_sip_push_task(registration->state->client_state->serializer, sip_outbound_registration_perform, registration)) { + ast_log(LOG_ERROR, "Failed to perform outbound registration on '%s'\n", ast_sorcery_object_get_id(registration)); + ao2_ref(registration, -1); + } + } + ao2_iterator_destroy(&i); } #define AUTH_INCREMENT 4 -- cgit v1.2.3