diff options
-rw-r--r-- | configs/basic-pbx/asterisk.conf | 13 | ||||
-rwxr-xr-x | configure | 14 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py | 32 | ||||
-rw-r--r-- | main/strings.c | 6 | ||||
-rw-r--r-- | res/res_fax.c | 46 | ||||
-rw-r--r-- | res/res_pjsip.c | 7 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 1 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_options.c | 64 | ||||
-rw-r--r-- | res/res_pjsip_outbound_publish.c | 187 | ||||
-rw-r--r-- | res/res_pjsip_outbound_registration.c | 2 | ||||
-rw-r--r-- | res/res_pjsip_publish_asterisk.c | 2 | ||||
-rw-r--r-- | res/res_sorcery_astdb.c | 3 |
13 files changed, 267 insertions, 114 deletions
diff --git a/configs/basic-pbx/asterisk.conf b/configs/basic-pbx/asterisk.conf index 576cc976b..06c632e79 100644 --- a/configs/basic-pbx/asterisk.conf +++ b/configs/basic-pbx/asterisk.conf @@ -1,16 +1,3 @@ -[directories] -astetcdir => /etc/asterisk -astmoddir => /usr/lib/asterisk/modules -astvarlibdir => /var/lib/asterisk -astdbdir => /var/lib/asterisk -astkeydir => /var/lib/asterisk -astdatadir => /var/lib/asterisk -astagidir => /var/lib/asterisk/agi-bin -astspooldir => /var/spool/asterisk -astrundir => /var/run/asterisk -astlogdir => /var/log/asterisk -astsbindir => /usr/sbin - [options] ; If we want to start Asterisk with a default verbosity for the verbose ; or debug logger channel types, then we use these settings. @@ -13772,7 +13772,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13818,7 +13818,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13842,7 +13842,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13887,7 +13887,7 @@ else We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -13911,7 +13911,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ -#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) +#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; @@ -17774,7 +17774,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_LEAK_SANITIZER=1 else - AST_LEAK_SANITIZER= + AST_LEAK_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } @@ -17806,7 +17806,7 @@ if ac_fn_c_try_compile "$LINENO"; then : $as_echo "yes" >&6; } AST_UNDEFINED_SANITIZER=1 else - AST_UNDEFINED_SANITIZER= + AST_UNDEFINED_SANITIZER=0 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } diff --git a/configure.ac b/configure.ac index 9c11054e9..5852d3fa2 100644 --- a/configure.ac +++ b/configure.ac @@ -1117,7 +1117,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_LEAK_SANITIZER=1], - [AST_LEAK_SANITIZER=] + [AST_LEAK_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" @@ -1133,7 +1133,7 @@ AC_COMPILE_IFELSE( [AC_LANG_PROGRAM([], [int x = 1;])], AC_MSG_RESULT(yes) [AST_UNDEFINED_SANITIZER=1], - [AST_UNDEFINED_SANITIZER=] + [AST_UNDEFINED_SANITIZER=0] AC_MSG_RESULT(no) ) CFLAGS="${saved_sanitize_CFLAGS}" diff --git a/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py new file mode 100644 index 000000000..76faf394c --- /dev/null +++ b/contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py @@ -0,0 +1,32 @@ +"""ps_contacts add authenticate_qualify + +Revision ID: 6be31516058d +Revises: 81b01a191a46 +Create Date: 2016-05-03 14:57:12.538179 + +""" + +# revision identifiers, used by Alembic. +revision = '6be31516058d' +down_revision = '81b01a191a46' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + +def upgrade(): + ############################# Enums ############################## + + # yesno_values have already been created, so use postgres enum object + # type to get around "already created" issue - works okay with mysql + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_contacts', sa.Column('authenticate_qualify', yesno_values)) + + +def downgrade(): + op.drop_column('ps_contacts', 'authenticate_qualify') + diff --git a/main/strings.c b/main/strings.c index f828727ad..b9c88dea5 100644 --- a/main/strings.c +++ b/main/strings.c @@ -234,8 +234,8 @@ int ast_strings_match(const char *left, const char *op, const char *right) { char *internal_op = (char *)op; char *internal_right = (char *)right; - float left_num; - float right_num; + double left_num; + double right_num; int scan_numeric = 0; if (!(left && right)) { @@ -297,7 +297,7 @@ regex: } equals: - scan_numeric = (sscanf(left, "%f", &left_num) && sscanf(internal_right, "%f", &right_num)); + scan_numeric = (sscanf(left, "%lf", &left_num) && sscanf(internal_right, "%lf", &right_num)); if (internal_op[0] == '=') { if (ast_strlen_zero(left) && ast_strlen_zero(internal_right)) { diff --git a/res/res_fax.c b/res/res_fax.c index 33c3f116b..c8ff1e988 100644 --- a/res/res_fax.c +++ b/res/res_fax.c @@ -626,6 +626,8 @@ static const struct ast_datastore_info fax_datastore = { static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_details *details); static int fax_detect_attach(struct ast_channel *chan, int timeout, int flags); static struct ast_fax_session_details *find_or_create_details(struct ast_channel *chan); +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan); + /*! \brief Copies fax detection and gateway framehooks during masquerades * @@ -2835,6 +2837,23 @@ static void destroy_gateway(void *data) ao2_cleanup(gateway->peer_write_format); } +static struct ast_fax_session *fax_v21_session_new (struct ast_channel *chan) { + struct ast_fax_session_details *v21_details; + struct ast_fax_session *v21_session; + + if (!chan || !(v21_details = session_details_new())) { + return NULL; + } + + v21_details->caps = AST_FAX_TECH_V21_DETECT; + if (!(v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { + ao2_ref(v21_details, -1); + return NULL; + } + + return v21_session; +} + /*! \brief Create a new fax gateway object. * \param chan the channel the gateway object will be attached to * \param details the fax session details @@ -2843,30 +2862,16 @@ static void destroy_gateway(void *data) static struct fax_gateway *fax_gateway_new(struct ast_channel *chan, struct ast_fax_session_details *details) { struct fax_gateway *gateway = ao2_alloc(sizeof(*gateway), destroy_gateway); - struct ast_fax_session_details *v21_details; if (!gateway) { return NULL; } - if (!(v21_details = session_details_new())) { + if (!(gateway->chan_v21_session = fax_v21_session_new(chan))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(chan)); ao2_ref(gateway, -1); return NULL; } - v21_details->caps = AST_FAX_TECH_V21_DETECT; - if (!(gateway->chan_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - - if (!(gateway->peer_v21_session = fax_session_new(v21_details, chan, NULL, NULL))) { - ao2_ref(v21_details, -1); - ao2_ref(gateway, -1); - return NULL; - } - ao2_ref(v21_details, -1); - gateway->framehook = -1; details->caps = AST_FAX_TECH_GATEWAY; @@ -3360,6 +3365,11 @@ static struct ast_frame *fax_gateway_framehook(struct ast_channel *chan, struct ast_channel_unlock(peer); gateway->bridged = 1; + if (!(gateway->peer_v21_session = fax_v21_session_new(peer))) { + ast_log(LOG_ERROR, "Can't create V21 session on chan %s for T.38 gateway session\n", ast_channel_name(peer)); + ast_framehook_detach(chan, gateway->framehook); + return f; + } } if (gateway->bridged && !ast_tvzero(gateway->timeout_start)) { @@ -3486,6 +3496,10 @@ static int fax_gateway_attach(struct ast_channel *chan, struct ast_fax_session_d .disable_inheritance = 1, /* Masquerade inheritance is handled through the datastore fixup */ }; + if (global_fax_debug) { + details->option.debug = AST_FAX_OPTFLAG_TRUE; + } + ast_string_field_set(details, result, "SUCCESS"); ast_string_field_set(details, resultstr, "gateway operation started successfully"); ast_string_field_set(details, error, "NO_ERROR"); diff --git a/res/res_pjsip.c b/res/res_pjsip.c index db3395fa7..a3b2d081d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1095,6 +1095,13 @@ If <literal>0</literal> no timeout. Time in fractional seconds. </para></description> </configOption> + <configOption name="authenticate_qualify" default="no"> + <synopsis>Authenticates a qualify request if needed</synopsis> + <description><para> + If true and a qualify request receives a challenge or authenticate response + authentication is attempted before declaring the contact available. + </para></description> + </configOption> <configOption name="outbound_proxy"> <synopsis>Outbound proxy used when sending OPTIONS request</synopsis> <description><para> diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 2779fe396..fd6db6edc 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -1116,6 +1116,7 @@ int ast_sip_initialize_sorcery_location(void) ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400); ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout)); + ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent)); ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server)); diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index c0d41c3d1..62640fe4e 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -1025,17 +1025,11 @@ int ast_sip_initialize_sorcery_qualify(void) return 0; } -static int qualify_and_schedule_cb(void *obj, void *arg, int flags) +static void qualify_and_schedule_contact(struct ast_sip_contact *contact) { - struct ast_sip_contact *contact = obj; - struct ast_sip_aor *aor = arg; int initial_interval; int max_time = ast_sip_get_max_initial_qualify_time(); - contact->qualify_frequency = aor->qualify_frequency; - contact->qualify_timeout = aor->qualify_timeout; - contact->authenticate_qualify = aor->authenticate_qualify; - /* Delay initial qualification by a random fraction of the specified interval */ if (max_time && max_time < contact->qualify_frequency) { initial_interval = max_time; @@ -1051,26 +1045,47 @@ static int qualify_and_schedule_cb(void *obj, void *arg, int flags) } else { update_contact_status(contact, UNKNOWN); } +} + +static int qualify_and_schedule_cb_with_aor(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_aor *aor = arg; + + contact->qualify_frequency = aor->qualify_frequency; + contact->qualify_timeout = aor->qualify_timeout; + contact->authenticate_qualify = aor->authenticate_qualify; + + qualify_and_schedule_contact(contact); + + return 0; +} + +static int qualify_and_schedule_cb_without_aor(void *obj, void *arg, int flags) +{ + qualify_and_schedule_contact((struct ast_sip_contact *) obj); return 0; } /*! * \internal - * \brief Qualify and schedule an endpoint's contacts + * \brief Qualify and schedule an aor's contacts * - * \details For the given endpoint retrieve its list of aors, qualify all - * contacts, and schedule for checks if configured. + * \details For the given aor check if it has permanent contacts, + * qualify all contacts and schedule for checks if configured. */ static int qualify_and_schedule_all_cb(void *obj, void *arg, int flags) { struct ast_sip_aor *aor = obj; struct ao2_container *contacts; - contacts = ast_sip_location_retrieve_aor_contacts(aor); - if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); - ao2_ref(contacts, -1); + if (aor->permanent_contacts) { + contacts = ast_sip_location_retrieve_aor_contacts(aor); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); + ao2_ref(contacts, -1); + } } return 0; @@ -1093,6 +1108,7 @@ static void qualify_and_schedule_all(void) { struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", ""); struct ao2_container *aors; + struct ao2_container *contacts; if (!var) { return; @@ -1100,16 +1116,22 @@ static void qualify_and_schedule_all(void) aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor", AST_RETRIEVE_FLAG_MULTIPLE, var); - ast_variables_destroy(var); - ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL); - if (!aors) { - return; + if (aors) { + ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); + ao2_ref(aors, -1); } - ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL); - ao2_ref(aors, -1); + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), + "contact", AST_RETRIEVE_FLAG_MULTIPLE, var); + if (contacts) { + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL); + ao2_ref(contacts, -1); + } + + ast_variables_destroy(var); + } static int format_contact_status(void *obj, void *arg, int flags) @@ -1175,7 +1197,7 @@ static void aor_observer_modified(const void *obj) contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { - ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb, aor); + ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_with_aor, aor); ao2_ref(contacts, -1); } } diff --git a/res/res_pjsip_outbound_publish.c b/res/res_pjsip_outbound_publish.c index 0265c424e..51e8a06be 100644 --- a/res/res_pjsip_outbound_publish.c +++ b/res/res_pjsip_outbound_publish.c @@ -406,22 +406,30 @@ static void sip_outbound_publish_synchronize(struct ast_sip_event_publisher_hand ao2_ref(states, -1); } -struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name) +static struct ast_sip_outbound_publish_state *sip_publish_state_get(const char *id) { - RAII_VAR(struct ao2_container *, states, - ao2_global_obj_ref(current_states), ao2_cleanup); - RAII_VAR(struct ast_sip_outbound_publish_state *, state, NULL, ao2_cleanup); + struct ao2_container *states = ao2_global_obj_ref(current_states); + struct ast_sip_outbound_publish_state *res; if (!states) { return NULL; } - state = ao2_find(states, name, OBJ_SEARCH_KEY); + res = ao2_find(states, id, OBJ_SEARCH_KEY); + ao2_ref(states, -1); + return res; +} + +struct ast_sip_outbound_publish_client *ast_sip_publish_client_get(const char *name) +{ + struct ast_sip_outbound_publish_state *state = sip_publish_state_get(name); + if (!state) { return NULL; } ao2_ref(state->client, +1); + ao2_ref(state, -1); return state->client; } @@ -701,8 +709,15 @@ static int explicit_publish_destroy(void *data) { struct ast_sip_outbound_publish_client *client = data; - pjsip_publishc_destroy(client->client); - ao2_ref(client, -1); + /* + * If there is no pjsip publishing client then we obviously don't need + * to destroy it. Also, the ref for the Asterisk publishing client that + * pjsip had would not exist or should already be gone as well. + */ + if (client->client) { + pjsip_publishc_destroy(client->client); + ao2_ref(client, -1); + } return 0; } @@ -882,6 +897,11 @@ static int sip_outbound_publish_client_alloc(void *data) /*! \brief Callback function for publish client responses */ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) { +#define DESTROY_CLIENT() do { \ + pjsip_publishc_destroy(client->client); \ + client->client = NULL; \ + ao2_ref(client, -1); } while (0) + RAII_VAR(struct ast_sip_outbound_publish_client *, client, ao2_bump(param->token), ao2_cleanup); RAII_VAR(struct ast_sip_outbound_publish *, publish, ao2_bump(client->publish), ao2_cleanup); SCOPED_AO2LOCK(lock, client); @@ -899,8 +919,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) ao2_ref(client, -1); } /* Once the destroy is called this callback will not get called any longer, so drop the client ref */ - pjsip_publishc_destroy(client->client); - ao2_ref(client, -1); + DESTROY_CLIENT(); return; } @@ -919,9 +938,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) client->auth_attempts++; if (client->auth_attempts == publish->max_auth_attempts) { - pjsip_publishc_destroy(client->client); - client->client = NULL; - + DESTROY_CLIENT(); ast_log(LOG_ERROR, "Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n", ast_sorcery_object_get_id(publish)); @@ -933,9 +950,7 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) client->auth_attempts = 0; if (param->code == 412) { - pjsip_publishc_destroy(client->client); - client->client = NULL; - + DESTROY_CLIENT(); if (sip_outbound_publish_client_alloc(client)) { ast_log(LOG_ERROR, "Failed to create a new outbound publish client for '%s' on 412 response\n", ast_sorcery_object_get_id(publish)); @@ -950,10 +965,9 @@ static void sip_outbound_publish_callback(struct pjsip_publishc_cbparam *param) expires = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_MIN_EXPIRES, NULL); if (!expires || !expires->ivalue) { + DESTROY_CLIENT(); ast_log(LOG_ERROR, "Received 423 response on outbound publish '%s' without a Min-Expires header\n", ast_sorcery_object_get_id(publish)); - pjsip_publishc_destroy(client->client); - client->client = NULL; goto end; } @@ -1080,25 +1094,89 @@ static struct ast_sip_outbound_publish_state *sip_outbound_publish_state_alloc( return state; } -/*! \brief Apply function which finds or allocates a state structure */ -static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *obj) +static int initialize_publish_client(struct ast_sip_outbound_publish *publish, + struct ast_sip_outbound_publish_state *state) { - RAII_VAR(struct ao2_container *, states, ao2_global_obj_ref(current_states), ao2_cleanup); - RAII_VAR(struct ast_sip_outbound_publish_state *, state, NULL, ao2_cleanup); - struct ast_sip_outbound_publish *applied = obj; + if (ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, state->client)) { + ast_log(LOG_ERROR, "Unable to create client for outbound publish '%s'\n", + ast_sorcery_object_get_id(publish)); + return -1; + } - if (ast_strlen_zero(applied->server_uri)) { + return 0; +} + +static int validate_publish_config(struct ast_sip_outbound_publish *publish) +{ + if (ast_strlen_zero(publish->server_uri)) { ast_log(LOG_ERROR, "No server URI specified on outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); + ast_sorcery_object_get_id(publish)); return -1; - } else if (ast_strlen_zero(applied->event)) { + } else if (ast_strlen_zero(publish->event)) { ast_log(LOG_ERROR, "No event type specified for outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); + ast_sorcery_object_get_id(publish)); return -1; } + return 0; +} + +static int current_state_reusable(struct ast_sip_outbound_publish *publish, + struct ast_sip_outbound_publish_state *current_state) +{ + struct ast_sip_outbound_publish *old_publish; + if (!can_reuse_publish(current_state->client->publish, publish)) { + /* + * Something significant has changed in the configuration, so we are + * unable to use the old state object. The current state needs to go + * away and a new one needs to be created. + */ + return 0; + } + + /* + * We can reuse the current state object so keep it, but swap out the + * underlying publish object with the new one. + */ + old_publish = current_state->client->publish; + current_state->client->publish = publish; + if (initialize_publish_client(publish, current_state)) { + /* + * If the state object fails to re-initialize then swap + * the old publish info back in. + */ + current_state->client->publish = publish; + return -1; + } + + /* + * Since we swapped out the publish object the new one needs a ref + * while the old one needs to go away. + */ + ao2_ref(current_state->client->publish, +1); + ao2_cleanup(old_publish); + + /* Tell the caller that the current state object should be used */ + return 1; +} + +/*! \brief Apply function which finds or allocates a state structure */ +static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *obj) +{ +#define ADD_TO_NEW_STATES(__obj) \ + do { if (__obj) { \ + ao2_link(new_states, __obj); \ + ao2_ref(__obj, -1); } } while (0) + + struct ast_sip_outbound_publish *applied = obj; + struct ast_sip_outbound_publish_state *current_state, *new_state; + int res; + + /* + * New states are being loaded or reloaded. We'll need to add the new + * object if created/updated, or keep the old object if an error occurs. + */ if (!new_states) { - /* make sure new_states has been allocated as we will be adding to it */ new_states = ao2_container_alloc_options( AO2_ALLOC_OPT_LOCK_NOLOCK, DEFAULT_STATE_BUCKETS, outbound_publish_state_hash, outbound_publish_state_cmp); @@ -1109,35 +1187,44 @@ static int sip_outbound_publish_apply(const struct ast_sorcery *sorcery, void *o } } - if (states) { - state = ao2_find(states, ast_sorcery_object_get_id(obj), OBJ_SEARCH_KEY); - if (state) { - if (can_reuse_publish(state->client->publish, applied)) { - ao2_replace(state->client->publish, applied); - } else { - ao2_ref(state, -1); - state = NULL; - } - } + /* If there is current state we'll want to maintain it if any errors occur */ + current_state = sip_publish_state_get(ast_sorcery_object_get_id(applied)); + + if ((res = validate_publish_config(applied))) { + ADD_TO_NEW_STATES(current_state); + return res; } - if (!state) { - state = sip_outbound_publish_state_alloc(applied); - if (!state) { - ast_log(LOG_ERROR, "Unable to create state for outbound publish '%s'\n", - ast_sorcery_object_get_id(applied)); - return -1; - }; + if (current_state && (res = current_state_reusable(applied, current_state))) { + /* + * The current state object was able to be reused, or an error + * occurred. Either way we keep the current state and be done. + */ + ADD_TO_NEW_STATES(current_state); + return res == 1 ? 0 : -1; } - if (ast_sip_push_task_synchronous(NULL, sip_outbound_publish_client_alloc, state->client)) { - ast_log(LOG_ERROR, "Unable to create client for outbound publish '%s'\n", + /* + * No current state was found or it was unable to be reused. Either way + * we'll need to create a new state object. + */ + new_state = sip_outbound_publish_state_alloc(applied); + if (!new_state) { + ast_log(LOG_ERROR, "Unable to create state for outbound publish '%s'\n", ast_sorcery_object_get_id(applied)); + ADD_TO_NEW_STATES(current_state); + return -1; + }; + + if (initialize_publish_client(applied, new_state)) { + ADD_TO_NEW_STATES(current_state); + ao2_ref(new_state, -1); return -1; } - ao2_link(new_states, state); - return 0; + ADD_TO_NEW_STATES(new_state); + ao2_cleanup(current_state); + return res; } static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) @@ -1156,6 +1243,7 @@ static int load_module(void) if (ast_sorcery_object_register(ast_sip_get_sorcery(), "outbound-publish", sip_outbound_publish_alloc, NULL, sip_outbound_publish_apply)) { + ast_log(LOG_ERROR, "Unable to register 'outbound-publish' type with sorcery\n"); return AST_MODULE_LOAD_DECLINE; } @@ -1215,7 +1303,7 @@ static int unload_module(void) /* wait for items to unpublish */ ast_verb(5, "Waiting to complete unpublishing task(s)\n"); - while (unloading.count) { + while (unloading.count && !res) { res = ast_cond_timedwait(&unloading.cond, &unloading.lock, &end); } ast_mutex_unlock(&unloading.lock); @@ -1228,6 +1316,7 @@ static int unload_module(void) "in the allowed time\n", unloading.count); } else { ast_verb(5, "All items successfully unpublished\n"); + ast_sorcery_object_unregister(ast_sip_get_sorcery(), "outbound-publish"); } return res; diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c index f85996ed5..815432d10 100644 --- a/res/res_pjsip_outbound_registration.c +++ b/res/res_pjsip_outbound_registration.c @@ -1096,7 +1096,7 @@ static int sip_dialog_create_contact(pj_pool_t *pool, pj_str_t *contact, const c contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE); contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE, "<%s:%s@%s%.*s%s:%d%s%s%s%s>", - (pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) ? "sips" : "sip", + ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ? "sips" : "sip", user, (type & PJSIP_TRANSPORT_IPV6) ? "[" : "", (int)local_addr.slen, diff --git a/res/res_pjsip_publish_asterisk.c b/res/res_pjsip_publish_asterisk.c index 3218b0a0c..002d976d4 100644 --- a/res/res_pjsip_publish_asterisk.c +++ b/res/res_pjsip_publish_asterisk.c @@ -862,6 +862,7 @@ static int load_module(void) ast_sorcery_apply_default(ast_sip_get_sorcery(), "asterisk-publication", "config", "pjsip.conf,criteria=type=asterisk-publication"); if (ast_sorcery_object_register(ast_sip_get_sorcery(), "asterisk-publication", asterisk_publication_config_alloc, NULL, NULL)) { + ast_log(LOG_ERROR, "Unable to register 'asterisk-publication' type with sorcery\n"); return AST_MODULE_LOAD_DECLINE; } @@ -919,6 +920,7 @@ static int unload_module(void) ast_sip_unregister_publish_handler(&asterisk_mwi_publication_handler); ast_sip_unregister_event_publisher_handler(&asterisk_devicestate_publisher_handler); ast_sip_unregister_event_publisher_handler(&asterisk_mwi_publisher_handler); + ast_sorcery_object_unregister(ast_sip_get_sorcery(), "asterisk-publication"); return 0; } diff --git a/res/res_sorcery_astdb.c b/res/res_sorcery_astdb.c index b3642d81e..dcfaba528 100644 --- a/res/res_sorcery_astdb.c +++ b/res/res_sorcery_astdb.c @@ -97,7 +97,6 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; - RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; @@ -113,7 +112,7 @@ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorc } if (!(object = ast_sorcery_alloc(sorcery, type, key)) || - ast_sorcery_objectset_apply(sorcery, object, objset)) { + ast_sorcery_objectset_apply(sorcery, object, existing)) { ao2_cleanup(object); return NULL; } |