summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/basic-pbx/asterisk.conf13
-rwxr-xr-xconfigure14
-rw-r--r--configure.ac4
-rw-r--r--contrib/ast-db-manage/config/versions/837aa67461fb_ps_contacts_add_authenticate_qualify.py32
-rw-r--r--main/strings.c6
-rw-r--r--res/res_fax.c46
-rw-r--r--res/res_pjsip.c7
-rw-r--r--res/res_pjsip/location.c1
-rw-r--r--res/res_pjsip/pjsip_options.c64
-rw-r--r--res/res_pjsip_outbound_publish.c187
-rw-r--r--res/res_pjsip_outbound_registration.c2
-rw-r--r--res/res_pjsip_publish_asterisk.c2
-rw-r--r--res/res_sorcery_astdb.c3
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.
diff --git a/configure b/configure
index 751fbea5d..9e3772748 100755
--- a/configure
+++ b/configure
@@ -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;
}