summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/app_queue.c2
-rw-r--r--apps/app_voicemail.c16
-rw-r--r--channels/chan_sip.c4
-rw-r--r--channels/chan_skinny.c4
-rwxr-xr-xcontrib/ast-db-manage/config/env.py3
-rwxr-xr-xcontrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py10
-rw-r--r--contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py3
-rw-r--r--contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py3
-rwxr-xr-xcontrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py6
-rw-r--r--contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py3
-rw-r--r--contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py11
-rw-r--r--contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py3
-rwxr-xr-xcontrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py3
-rwxr-xr-xcontrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py3
-rw-r--r--contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py3
-rw-r--r--contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py5
-rw-r--r--contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py3
-rw-r--r--contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py3
-rw-r--r--contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py6
-rwxr-xr-xcontrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py38
-rw-r--r--contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py10
-rw-r--r--contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py3
-rw-r--r--contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py6
-rw-r--r--contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py3
-rw-r--r--contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py12
-rw-r--r--contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py3
-rw-r--r--contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py6
-rw-r--r--contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py3
-rwxr-xr-xcontrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py54
-rwxr-xr-xcontrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py25
-rw-r--r--contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py5
-rw-r--r--contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py3
-rw-r--r--contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py6
-rw-r--r--contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py3
-rw-r--r--contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py3
-rw-r--r--contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py8
-rw-r--r--contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py30
-rw-r--r--include/asterisk/_private.h1
-rw-r--r--include/asterisk/named_locks.h105
-rw-r--r--include/asterisk/pbx.h2
-rw-r--r--include/asterisk/res_pjsip.h43
-rw-r--r--main/asterisk.c5
-rw-r--r--main/core_unreal.c5
-rw-r--r--main/manager.c2
-rw-r--r--main/named_locks.c142
-rw-r--r--main/pbx.c118
-rw-r--r--res/res_pjsip/location.c44
-rw-r--r--res/res_pjsip_exten_state.c9
-rw-r--r--res/res_pjsip_registrar.c55
-rw-r--r--res/res_pjsip_registrar_expire.c18
-rw-r--r--tests/test_named_lock.c151
-rw-r--r--third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch30
52 files changed, 774 insertions, 271 deletions
diff --git a/apps/app_queue.c b/apps/app_queue.c
index 776ada4b8..0123e473a 100644
--- a/apps/app_queue.c
+++ b/apps/app_queue.c
@@ -2461,7 +2461,7 @@ static int extensionstate2devicestate(int state)
return state;
}
-static int extension_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+static int extension_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
{
struct ao2_iterator miter, qiter;
struct member *m;
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index cd552545e..aa8da5f17 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -580,6 +580,8 @@ static AST_LIST_HEAD_STATIC(vmstates, vmstate);
#define INTRO "vm-intro"
+#define MAX_MAIL_BODY_CONTENT_SIZE 134217728L // 128 Mbyte
+
#define MAXMSG 100
#define MAXMSGLIMIT 9999
@@ -3624,8 +3626,8 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
char *body_content;
char *body_decoded;
char *fn = is_intro ? vms->introfn : vms->fn;
- unsigned long len;
- unsigned long newlen;
+ unsigned long len = 0;
+ unsigned long newlen = 0;
char filename[256];
if (!body || body == NIL)
@@ -3634,12 +3636,18 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
ast_mutex_lock(&vms->lock);
body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
ast_mutex_unlock(&vms->lock);
- if (body_content != NIL) {
+ if (len > MAX_MAIL_BODY_CONTENT_SIZE) {
+ ast_log(AST_LOG_ERROR,
+ "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
+ vms->msgArray[vms->curmsg], section, len, MAX_MAIL_BODY_CONTENT_SIZE, vms->imapuser, vms->username);
+ return -1;
+ }
+ if (body_content != NIL && len) {
snprintf(filename, sizeof(filename), "%s.%s", fn, format);
/* ast_debug(1, body_content); */
body_decoded = rfc822_base64((unsigned char *) body_content, len, &newlen);
/* If the body of the file is empty, return an error */
- if (!newlen) {
+ if (!newlen || !body_decoded) {
return -1;
}
write_file(filename, (char *) body_decoded, newlen);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index ffc2084a1..2a6dd77e7 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1269,7 +1269,7 @@ static void check_for_nat(const struct ast_sockaddr *them, struct sip_pvt *p);
/*--- Device monitoring and Device/extension state/event handling */
static int extensionstate_update(const char *context, const char *exten, struct state_notify_data *data, struct sip_pvt *p, int force);
-static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data);
+static int cb_extensionstate(const char *context, const char *exten, struct ast_state_cb_info *info, void *data);
static int sip_poke_noanswer(const void *data);
static int sip_poke_peer(struct sip_peer *peer, int force);
static void sip_poke_all_peers(void);
@@ -17389,7 +17389,7 @@ static int extensionstate_update(const char *context, const char *exten, struct
/*! \brief Callback for the devicestate notification (SUBSCRIBE) support subsystem
\note If you add an "hint" priority to the extension in the dial plan,
you will get notifications on device state changes */
-static int cb_extensionstate(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+static int cb_extensionstate(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
{
struct sip_pvt *p = data;
struct state_notify_data notify_data = {
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index da156fc5e..76990d175 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -1671,7 +1671,7 @@ static struct ast_channel_tech skinny_tech = {
.send_digit_end = skinny_senddigit_end,
};
-static int skinny_extensionstate_cb(char *context, char *id, struct ast_state_cb_info *info, void *data);
+static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data);
static struct skinny_line *skinny_line_alloc(void)
{
@@ -3413,7 +3413,7 @@ static void transmit_serviceurlstat(struct skinny_device *d, int instance)
transmit_response(d, req);
}
-static int skinny_extensionstate_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+static int skinny_extensionstate_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
{
struct skinny_container *container = data;
struct skinny_device *d = NULL;
diff --git a/contrib/ast-db-manage/config/env.py b/contrib/ast-db-manage/config/env.py
index 4118da066..6740d5906 100755
--- a/contrib/ast-db-manage/config/env.py
+++ b/contrib/ast-db-manage/config/env.py
@@ -58,8 +58,7 @@ def run_migrations_online():
connection = engine.connect()
context.configure(
connection=connection,
- target_metadata=target_metadata,
- render_as_batch=True
+ target_metadata=target_metadata
)
try:
diff --git a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
index cc9f0e0cc..b4ea71cbd 100755
--- a/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
+++ b/contrib/ast-db-manage/config/versions/10aedae86a32_add_outgoing_enum_va.py
@@ -45,10 +45,7 @@ def upgrade():
context = op.get_context()
# Upgrading to this revision WILL clear your directmedia values.
- if context.bind.dialect.name == 'sqlite':
- with op.batch_alter_table('sippeers') as batch_op:
- batch_op.alter_column('directmedia', type_=new_type)
- elif context.bind.dialect.name != 'postgresql':
+ if context.bind.dialect.name != 'postgresql':
op.alter_column('sippeers', 'directmedia',
type_=new_type,
existing_type=old_type)
@@ -69,10 +66,7 @@ def downgrade():
op.execute(tcr.update().where(tcr.c.directmedia==u'outgoing')
.values(directmedia=None))
- if context.bind.dialect.name == 'sqlite':
- with op.batch_alter_table('sippeers') as batch_op:
- batch_op.alter_column('directmedia', type_=old_type)
- elif context.bind.dialect.name != 'postgresql':
+ if context.bind.dialect.name != 'postgresql':
op.alter_column('sippeers', 'directmedia',
type_=old_type,
existing_type=new_type)
diff --git a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py
index 22fd6c7b7..724a5e576 100644
--- a/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py
+++ b/contrib/ast-db-manage/config/versions/136885b81223_add_regcontext_to_pj.py
@@ -17,5 +17,4 @@ def upgrade():
op.add_column('ps_globals', sa.Column('regcontext', sa.String(80)))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('regcontext')
+ op.drop_column('ps_globals', 'regcontext')
diff --git a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py
index 6c5f808bb..7e6cf994f 100644
--- a/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py
+++ b/contrib/ast-db-manage/config/versions/154177371065_add_default_from_user.py
@@ -19,5 +19,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('default_from_user')
+ op.drop_column('ps_globals', 'default_from_user')
diff --git a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
index c16cff9f4..215726fa0 100755
--- a/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
+++ b/contrib/ast-db-manage/config/versions/1758e8bbf6b_increase_useragent_column_size.py
@@ -33,11 +33,9 @@ import sqlalchemy as sa
def upgrade():
- with op.batch_alter_table('sippeers') as batch_op:
- batch_op.alter_column('useragent', type_=sa.String(255))
+ op.alter_column('sippeers', 'useragent', type_=sa.String(255))
def downgrade():
- with op.batch_alter_table('sippeers') as batch_op:
- batch_op.alter_column('useragent', type_=sa.String(20))
+ op.alter_column('sippeers', 'useragent', type_=sa.String(20))
diff --git a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py
index dee384d4c..ba972b64e 100644
--- a/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py
+++ b/contrib/ast-db-manage/config/versions/189a235b3fd7_add_keep_alive_interval.py
@@ -19,5 +19,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('keep_alive_interval')
+ op.drop_column('ps_globals', 'keep_alive_interval')
diff --git a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py
index 781dca703..e6f917d87 100644
--- a/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py
+++ b/contrib/ast-db-manage/config/versions/1c688d9a003c_pjsip_voicemail_extension.py
@@ -22,10 +22,7 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('default_voicemail_extension')
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.drop_column('voicemail_extension')
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('voicemail_extension')
- batch_op.drop_column('mwi_subscribe_replaces_unsolicited')
+ op.drop_column('ps_globals', 'default_voicemail_extension')
+ op.drop_column('ps_aors', 'voicemail_extension')
+ op.drop_column('ps_endpoints', 'voicemail_extension')
+ op.drop_column('ps_endpoints', 'mwi_subscribe_replaces_unsolicited')
diff --git a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
index 4d520fcee..eb2000137 100644
--- a/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
+++ b/contrib/ast-db-manage/config/versions/1d50859ed02e_create_accountcode.py
@@ -17,5 +17,4 @@ def upgrade():
op.add_column('ps_endpoints', sa.Column('accountcode', sa.String(20)))
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('accountcode')
+ op.drop_column('ps_endpoints', 'accountcode')
diff --git a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
index 8b77eb7ac..2adca628b 100755
--- a/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
+++ b/contrib/ast-db-manage/config/versions/21e526ad3040_add_pjsip_debug_option.py
@@ -18,5 +18,4 @@ def upgrade():
op.add_column('ps_globals', sa.Column('debug', sa.String(40)))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('debug')
+ op.drop_column('ps_globals', 'debug')
diff --git a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py
index 8ca63f148..dc0c01c24 100755
--- a/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py
+++ b/contrib/ast-db-manage/config/versions/23530d604b96_add_rpid_immediate.py
@@ -45,5 +45,4 @@ def upgrade():
op.add_column('ps_endpoints', sa.Column('rpid_immediate', yesno_values))
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('rpid_immediate')
+ op.drop_column('ps_endpoints', 'rpid_immediate')
diff --git a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py
index 1199d0c83..e7c11da19 100644
--- a/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py
+++ b/contrib/ast-db-manage/config/versions/26d7f3bf0fa5_add_bind_rtp_to_media_address_to_pjsip.py
@@ -28,5 +28,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('bind_rtp_to_media_address')
+ op.drop_column('ps_endpoints', 'bind_rtp_to_media_address')
diff --git a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py
index 2a792d3f1..8972d8030 100644
--- a/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py
+++ b/contrib/ast-db-manage/config/versions/26f10cadc157_add_pjsip_timeout_options.py
@@ -20,6 +20,5 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('rtp_timeout')
- batch_op.drop_column('rtp_timeout_hold')
+ op.drop_column('ps_endpoints', 'rtp_timeout')
+ op.drop_column('ps_endpoints', 'rtp_timeout_hold')
diff --git a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py
index 09056d6c4..ad36bd9b7 100644
--- a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py
+++ b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py
@@ -27,5 +27,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('g726_non_standard')
+ op.drop_column('ps_endpoints', 'g726_non_standard')
diff --git a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py
index 8e05a62a4..8c499aee8 100644
--- a/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py
+++ b/contrib/ast-db-manage/config/versions/28ce1e718f05_add_fatal_response_interval.py
@@ -19,5 +19,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_registrations') as batch_op:
- batch_op.drop_column('fatal_retry_interval')
+ op.drop_column('ps_registrations', 'fatal_retry_interval')
diff --git a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py
index 9f98750f6..2ade86f9f 100644
--- a/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py
+++ b/contrib/ast-db-manage/config/versions/2d078ec071b7_increaes_contact_column_size.py
@@ -15,10 +15,8 @@ import sqlalchemy as sa
def upgrade():
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.alter_column('contact', type_=sa.String(255))
+ op.alter_column('ps_aors', 'contact', type_=sa.String(255))
def downgrade():
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.alter_column('contact', type_=sa.String(40))
+ op.alter_column('ps_aors', 'contact', type_=sa.String(40))
diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
index 102265ea8..d39ddb41a 100755
--- a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
+++ b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
@@ -120,17 +120,15 @@ def upgrade():
op.create_index('ps_registrations_id', 'ps_registrations', ['id'])
########################## add columns ###########################
- with op.batch_alter_table('ps_endpoints') as batch_op:
# new columns for endpoints
- batch_op.add_column(sa.Column('media_address', sa.String(40)))
- batch_op.add_column(sa.Column('redirect_method',
- pjsip_redirect_method_values))
- batch_op.add_column(sa.Column('set_var', sa.Text()))
+ op.add_column('ps_endpoints', sa.Column('media_address', sa.String(40)))
+ op.add_column('ps_endpoints', sa.Column('redirect_method',
+ pjsip_redirect_method_values))
+ op.add_column('ps_endpoints', sa.Column('set_var', sa.Text()))
# rename mwi_fromuser to mwi_from_user
- batch_op.alter_column('mwi_fromuser',
- new_column_name='mwi_from_user',
- existing_type=sa.String(40))
+ op.alter_column('ps_endpoints', 'mwi_fromuser',
+ new_column_name='mwi_from_user', existing_type=sa.String(40))
# new columns for contacts
op.add_column('ps_contacts', sa.Column('outbound_proxy', sa.String(40)))
@@ -144,23 +142,19 @@ def upgrade():
def downgrade():
########################## drop columns ##########################
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.drop_column('support_path')
- batch_op.drop_column('outbound_proxy')
- batch_op.drop_column('maximum_expiration')
+ op.drop_column('ps_aors', 'support_path')
+ op.drop_column('ps_aors', 'outbound_proxy')
+ op.drop_column('ps_aors', 'maximum_expiration')
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.drop_column('path')
- batch_op.drop_column('outbound_proxy')
+ op.drop_column('ps_contacts', 'path')
+ op.drop_column('ps_contacts', 'outbound_proxy')
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.alter_column('mwi_from_user',
- new_column_name='mwi_fromuser',
- existing_type=sa.String(40))
+ op.alter_column('ps_endpoints', 'mwi_from_user',
+ new_column_name='mwi_fromuser', existing_type=sa.String(40))
- batch_op.drop_column('set_var')
- batch_op.drop_column('redirect_method')
- batch_op.drop_column('media_address')
+ op.drop_column('ps_endpoints', 'set_var')
+ op.drop_column('ps_endpoints', 'redirect_method')
+ op.drop_column('ps_endpoints', 'media_address')
########################## drop tables ###########################
diff --git a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
index b1a9f8be8..778de8f37 100644
--- a/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
+++ b/contrib/ast-db-manage/config/versions/31cd4f4891ec_add_auto_dtmf_mode.py
@@ -24,10 +24,7 @@ def upgrade():
context = op.get_context()
# Upgrading to this revision WILL clear your directmedia values.
- if context.bind.dialect.name == 'sqlite':
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.alter_column('dtmf_mode', type_=new_type)
- elif context.bind.dialect.name != 'postgresql':
+ if context.bind.dialect.name != 'postgresql':
op.alter_column('ps_endpoints', 'dtmf_mode',
type_=new_type,
existing_type=old_type)
@@ -45,10 +42,7 @@ def upgrade():
def downgrade():
context = op.get_context()
- if context.bind.dialect.name == 'sqlite':
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.alter_column('dtmf_mode', type_=old_type)
- elif context.bind.dialect.name != 'postgresql':
+ if context.bind.dialect.name != 'postgresql':
op.alter_column('ps_endpoints', 'dtmf_mode',
type_=old_type,
existing_type=new_type)
diff --git a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py
index 5de7aa862..145d6bea6 100644
--- a/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py
+++ b/contrib/ast-db-manage/config/versions/371a3bf4143e_add_user_eq_phone_option_to_pjsip.py
@@ -27,5 +27,4 @@ def upgrade():
op.add_column('ps_endpoints', sa.Column('user_eq_phone', yesno_values))
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('user_eq_phone')
+ op.drop_column('ps_endpoints', 'user_eq_phone')
diff --git a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
index 08457a9d8..afc1beb37 100644
--- a/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
+++ b/contrib/ast-db-manage/config/versions/3855ee4e5f85_add_missing_pjsip_options.py
@@ -20,7 +20,5 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.drop_column('user_agent')
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('message_context')
+ op.drop_column('ps_contacts', 'user_agent')
+ op.drop_column('ps_endpoints', 'message_context')
diff --git a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py
index 7f2c57978..0becc1e26 100644
--- a/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py
+++ b/contrib/ast-db-manage/config/versions/3bcc0b5bc2c9_add_allow_reload_to_ps_transports.py
@@ -22,5 +22,4 @@ def upgrade():
op.add_column('ps_transports', sa.Column('allow_reload', yesno_values))
def downgrade():
- with op.batch_alter_table('ps_transports') as batch_op:
- batch_op.drop_column('allow_reload')
+ op.drop_column('ps_transports', 'allow_reload')
diff --git a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py
index 563b98d08..b8b19b4c9 100644
--- a/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py
+++ b/contrib/ast-db-manage/config/versions/423f34ad36e2_fix_pjsip_qualify_ti.py
@@ -15,13 +15,9 @@ import sqlalchemy as sa
def upgrade():
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.alter_column('qualify_timeout', type_=sa.Float)
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.alter_column('qualify_timeout', type_=sa.Float)
+ op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Float)
+ op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Float)
def downgrade():
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.alter_column('qualify_timeout', type_=sa.Integer)
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.alter_column('qualify_timeout', type_=sa.Integer)
+ op.alter_column('ps_aors', 'qualify_timeout', type_=sa.Integer)
+ op.alter_column('ps_contacts', 'qualify_timeout', type_=sa.Integer)
diff --git a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py
index b09acf7a3..b7d992493 100644
--- a/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py
+++ b/contrib/ast-db-manage/config/versions/45e3f47c6c44_add_pjsip_endpoint_identifier_order.py
@@ -18,5 +18,4 @@ def upgrade():
op.add_column('ps_globals', sa.Column('endpoint_identifier_order', sa.String(40)))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('endpoint_identifier_order')
+ op.drop_column('ps_globals', 'endpoint_identifier_order')
diff --git a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py
index ec8a90449..0512ef936 100644
--- a/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py
+++ b/contrib/ast-db-manage/config/versions/461d7d691209_add_pjsip_qualify_timeout.py
@@ -18,7 +18,5 @@ def upgrade():
op.add_column('ps_contacts', sa.Column('qualify_timeout', sa.Integer))
def downgrade():
- with op.batch_alter_table('ps_aors') as batch_op:
- batch_op.drop_column('qualify_timeout')
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.drop_column('qualify_timeout')
+ op.drop_column('ps_aors', 'qualify_timeout')
+ op.drop_column('ps_contacts', 'qualify_timeout')
diff --git a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
index 3ad26509b..5a4f470aa 100644
--- a/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
+++ b/contrib/ast-db-manage/config/versions/498357a710ae_add_rtp_keepalive.py
@@ -19,5 +19,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('rtp_keepalive')
+ op.drop_column('ps_endpoints', 'rtp_keepalive')
diff --git a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
index d9bbf8977..27b498f30 100755
--- a/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
+++ b/contrib/ast-db-manage/config/versions/4c573e7135bd_fix_tos_field_types.py
@@ -19,43 +19,35 @@ YESNO_NAME = 'yesno_values'
YESNO_VALUES = ['yes', 'no']
def upgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.alter_column('tos_audio',
- type_=sa.String(10))
- batch_op.alter_column('tos_video',
- type_=sa.String(10))
- batch_op.drop_column('cos_audio')
- batch_op.drop_column('cos_video')
- batch_op.add_column(sa.Column('cos_audio', sa.Integer))
- batch_op.add_column(sa.Column('cos_video', sa.Integer))
-
- with op.batch_alter_table('ps_transports') as batch_op:
- batch_op.alter_column('tos',
- type_=sa.String(10))
+ op.alter_column('ps_endpoints', 'tos_audio', type_=sa.String(10))
+ op.alter_column('ps_endpoints', 'tos_video', type_=sa.String(10))
+ op.drop_column('ps_endpoints', 'cos_audio')
+ op.drop_column('ps_endpoints', 'cos_video')
+ op.add_column('ps_endpoints', sa.Column('cos_audio', sa.Integer))
+ op.add_column('ps_endpoints', sa.Column('cos_video', sa.Integer))
- # Can't cast YENO_VALUES to Integers, so dropping and adding is required
- batch_op.drop_column('cos')
+ op.alter_column('ps_transports', 'tos', type_=sa.String(10))
- batch_op.add_column(sa.Column('cos', sa.Integer))
+ # Can't cast YENO_VALUES to Integers, so dropping and adding is required
+ op.drop_column('ps_transports', 'cos')
+ op.add_column('ps_transports', sa.Column('cos', sa.Integer))
def downgrade():
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
# Can't cast string to YESNO_VALUES, so dropping and adding is required
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('tos_audio')
- batch_op.drop_column('tos_video')
- batch_op.add_column(sa.Column('tos_audio', yesno_values))
- batch_op.add_column(sa.Column('tos_video', yesno_values))
- batch_op.drop_column('cos_audio')
- batch_op.drop_column('cos_video')
- batch_op.add_column(sa.Column('cos_audio', yesno_values))
- batch_op.add_column(sa.Column('cos_video', yesno_values))
-
- with op.batch_alter_table('ps_transports') as batch_op:
- batch_op.drop_column('tos')
- batch_op.add_column(sa.Column('tos', yesno_values))
+ op.drop_column('ps_endpoints', 'tos_audio')
+ op.drop_column('ps_endpoints', 'tos_video')
+ op.add_column('ps_endpoints', sa.Column('tos_audio', yesno_values))
+ op.add_column('ps_endpoints', sa.Column('tos_video', yesno_values))
+ op.drop_column('ps_endpoints', 'cos_audio')
+ op.drop_column('ps_endpoints', 'cos_video')
+ op.add_column('ps_endpoints', sa.Column('cos_audio', yesno_values))
+ op.add_column('ps_endpoints', sa.Column('cos_video', yesno_values))
+
+ op.drop_column('ps_transports', 'tos')
+ op.add_column('ps_transports', sa.Column('tos', yesno_values))
# Can't cast integers to YESNO_VALUES, so dropping and adding is required
- batch_op.drop_column('cos')
- batch_op.add_column(sa.Column('cos', yesno_values))
+ op.drop_column('ps_transports', 'cos')
+ op.add_column('ps_transports', sa.Column('cos', yesno_values))
diff --git a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
index 632f4c4eb..01d4985fe 100755
--- a/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
+++ b/contrib/ast-db-manage/config/versions/5139253c0423_make_q_member_uniqueid_autoinc.py
@@ -36,28 +36,19 @@ def upgrade():
context = op.get_context()
# Was unable to find a way to use op.alter_column() to add the unique
# index property.
- if context.bind.dialect.name == 'sqlite':
- with op.batch_alter_table('queue_members') as batch_op:
- batch_op.create_primary_key('queue_members_pj', columns='uniqueid')
- else:
- op.drop_column('queue_members', 'uniqueid')
- op.add_column(
- 'queue_members',
- sa.Column(
- name='uniqueid', type_=sa.Integer, nullable=False,
- unique=True))
+ op.drop_column('queue_members', 'uniqueid')
+ op.add_column('queue_members', sa.Column(name='uniqueid', type_=sa.Integer,
+ nullable=False, unique=True))
# The postgres backend does not like the autoincrement needed for
# mysql here. It is just the backend that is giving a warning and
# not the database itself.
- op.alter_column(
- table_name='queue_members', column_name='uniqueid',
- existing_type=sa.Integer, existing_nullable=False,
- autoincrement=True)
+ op.alter_column(table_name='queue_members', column_name='uniqueid',
+ existing_type=sa.Integer, existing_nullable=False,
+ autoincrement=True)
def downgrade():
# Was unable to find a way to use op.alter_column() to remove the
# unique index property.
- with op.batch_alter_table('queue_members') as batch_op:
- batch_op.drop_column('uniqueid')
- batch_op.add_column(sa.Column(name='uniqueid', type_=sa.String(80), nullable=False))
+ op.drop_column('queue_members', 'uniqueid')
+ op.add_column('queue_members', sa.Column(name='uniqueid', type_=sa.String(80), nullable=False))
diff --git a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
index 8d0f68f03..c2dacda2c 100644
--- a/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
+++ b/contrib/ast-db-manage/config/versions/51f8cb66540e_add_further_dtls_options.py
@@ -28,6 +28,5 @@ def upgrade():
op.add_column('ps_endpoints', sa.Column('media_use_received_transport', yesno_values))
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('force_avp')
- batch_op.drop_column('media_use_received_transport')
+ op.drop_column('ps_endpoints', 'force_avp')
+ op.drop_column('ps_endpoints', 'media_use_received_transport')
diff --git a/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py
index 2c61f2b9d..efa0196ac 100644
--- a/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py
+++ b/contrib/ast-db-manage/config/versions/5813202e92be_add_contact_expiration_check_interval_.py
@@ -17,5 +17,4 @@ def upgrade():
op.add_column('ps_globals', sa.Column('contact_expiration_check_interval', sa.Integer))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('contact_expiration_check_interval')
+ op.drop_column('ps_globals', 'contact_expiration_check_interval')
diff --git a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
index ace544423..28ebc8b17 100644
--- a/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
+++ b/contrib/ast-db-manage/config/versions/5950038a6ead_fix_pjsip_verifiy_typo.py
@@ -19,13 +19,11 @@ YESNO_VALUES = ['yes', 'no']
def upgrade():
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
- with op.batch_alter_table('ps_transports') as batch_op:
- batch_op.alter_column('verifiy_server', type_=yesno_values,
+ op.alter_column('ps_transports', 'verifiy_server', type_=yesno_values,
new_column_name='verify_server')
def downgrade():
yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
- with op.batch_alter_table('ps_transports') as batch_op:
- batch_op.alter_column('verify_server', type_=yesno_values,
+ op.alter_column('ps_transports', 'verify_server', type_=yesno_values,
new_column_name='verifiy_server')
diff --git a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py
index fff250403..7a463f057 100644
--- a/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py
+++ b/contrib/ast-db-manage/config/versions/945b1098bdd_add_media_encryption_optimistic_to_pjsip.py
@@ -28,5 +28,4 @@ def upgrade():
def downgrade():
- with op.batch_alter_table('ps_endpoints') as batch_op:
- batch_op.drop_column('media_encryption_optimistic')
+ op.drop_column('ps_endpoints', 'media_encryption_optimistic')
diff --git a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py
index dc06d84ef..0ffd7848d 100644
--- a/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py
+++ b/contrib/ast-db-manage/config/versions/a541e0b5e89_add_pjsip_max_initial_qualify_time.py
@@ -17,5 +17,4 @@ def upgrade():
op.add_column('ps_globals', sa.Column('max_initial_qualify_time', sa.Integer))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.drop_column('max_initial_qualify_time')
+ op.drop_column('ps_globals', 'max_initial_qualify_time')
diff --git a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py
index b4502eb3d..8aa16f155 100644
--- a/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py
+++ b/contrib/ast-db-manage/config/versions/dbc44d5a908_add_missing_columns_to_sys_and_reg.py
@@ -29,8 +29,6 @@ def upgrade():
op.add_column('ps_registrations', sa.Column('endpoint', sa.String(40)))
def downgrade():
- with op.batch_alter_table('ps_systems') as batch_op:
- batch_op.drop_column('disable_tcp_switch')
- with op.batch_alter_table('ps_registrations') as batch_op:
- batch_op.drop_column('line')
- batch_op.drop_column('endpoint')
+ op.drop_column('ps_systems', 'disable_tcp_switch')
+ op.drop_column('ps_registrations', 'line')
+ op.drop_column('ps_registrations', 'endpoint')
diff --git a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
index f25c2987e..9c00c012e 100644
--- a/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
+++ b/contrib/ast-db-manage/config/versions/e96a0b8071c_increase_pjsip_column_size.py
@@ -15,28 +15,22 @@ import sqlalchemy as sa
def upgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.alter_column('user_agent', type_=sa.String(255))
+ op.alter_column('ps_globals', 'user_agent', type_=sa.String(255))
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.alter_column('id', type_=sa.String(255))
- batch_op.alter_column('uri', type_=sa.String(255))
- batch_op.alter_column('user_agent', type_=sa.String(255))
+ op.alter_column('ps_contacts', 'id', type_=sa.String(255))
+ op.alter_column('ps_contacts', 'uri', type_=sa.String(255))
+ op.alter_column('ps_contacts', 'user_agent', type_=sa.String(255))
- with op.batch_alter_table('ps_registrations') as batch_op:
- batch_op.alter_column('client_uri', type_=sa.String(255))
- batch_op.alter_column('server_uri', type_=sa.String(255))
+ op.alter_column('ps_registrations', 'client_uri', type_=sa.String(255))
+ op.alter_column('ps_registrations', 'server_uri', type_=sa.String(255))
def downgrade():
- with op.batch_alter_table('ps_globals') as batch_op:
- batch_op.alter_column('user_agent', type_=sa.String(40))
+ op.alter_column('ps_globals', 'user_agent', type_=sa.String(40))
- with op.batch_alter_table('ps_contacts') as batch_op:
- batch_op.alter_column('id', type_=sa.String(40))
- batch_op.alter_column('uri', type_=sa.String(40))
- batch_op.alter_column('user_agent', type_=sa.String(40))
+ op.alter_column('ps_contacts', 'id', type_=sa.String(40))
+ op.alter_column('ps_contacts', 'uri', type_=sa.String(40))
+ op.alter_column('ps_contacts', 'user_agent', type_=sa.String(40))
- with op.batch_alter_table('ps_registrations') as batch_op:
- batch_op.alter_column('client_uri', type_=sa.String(40))
- batch_op.alter_column('server_uri', type_=sa.String(40))
+ op.alter_column('ps_registrations', 'client_uri', type_=sa.String(40))
+ op.alter_column('ps_registrations', 'server_uri', type_=sa.String(40))
diff --git a/include/asterisk/_private.h b/include/asterisk/_private.h
index a4a4f1bea..6dbf24f4d 100644
--- a/include/asterisk/_private.h
+++ b/include/asterisk/_private.h
@@ -39,6 +39,7 @@ int ast_dns_system_resolver_init(void); /*!< Provided by dns_system_resolver.c *
void threadstorage_init(void); /*!< Provided by threadstorage.c */
int ast_device_state_engine_init(void); /*!< Provided by devicestate.c */
int astobj2_init(void); /*!< Provided by astobj2.c */
+int ast_named_locks_init(void); /*!< Provided by named_locks.c */
int ast_file_init(void); /*!< Provided by file.c */
int ast_features_init(void); /*!< Provided by features.c */
void ast_autoservice_init(void); /*!< Provided by autoservice.c */
diff --git a/include/asterisk/named_locks.h b/include/asterisk/named_locks.h
new file mode 100644
index 000000000..0fe07d992
--- /dev/null
+++ b/include/asterisk/named_locks.h
@@ -0,0 +1,105 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Named Locks
+ *
+ * \author George Joseph <george.joseph@fairview5.com>
+ */
+
+#ifndef INCLUDE_ASTERISK_NAMED_LOCKS_H_
+#define INCLUDE_ASTERISK_NAMED_LOCKS_H_
+
+#include "asterisk/astobj2.h"
+
+/*!
+ * \defgroup named_locks Named mutex and read-write locks
+ * @{
+ * \page NamedLocks Named mutex and read-write locks
+ * \since 13.9.0
+ *
+ * Locking some objects like sorcery objects can be tricky because the underlying
+ * ao2 object may not be the same for all callers. For instance, two threads that
+ * call ast_sorcery_retrieve_by_id on the same aor name might actually get 2 different
+ * ao2 objects if the underlying wizard had to rehydrate the aor from a database.
+ * Locking one ao2 object doesn't have any effect on the other even if those objects
+ * had locks in the first place
+ *
+ * Named locks allow access control by name. Now an aor named "1000" can be locked and
+ * any other thread attempting to lock the aor named "1000" will wait regardless of whether
+ * the underlying ao2 object is the same or not.
+ *
+ * To use a named lock:
+ * Call ast_named_lock_get with the appropriate keyspace and key.
+ * Use the standard ao2 lock/unlock functions as needed.
+ * Call ast_named_lock_put when you're finished with it.
+ */
+
+/*!
+ * \brief Which type of lock to request.
+ */
+enum ast_named_lock_type {
+ /*! Request a named mutex. */
+ AST_NAMED_LOCK_TYPE_MUTEX = AO2_ALLOC_OPT_LOCK_MUTEX,
+ /*! Request a named read/write lock. */
+ AST_NAMED_LOCK_TYPE_RWLOCK = AO2_ALLOC_OPT_LOCK_RWLOCK,
+};
+
+struct ast_named_lock;
+
+struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func,
+ enum ast_named_lock_type lock_type, const char *keyspace, const char *key);
+
+int __ast_named_lock_put(const char *filename, int lineno, const char *func,
+ struct ast_named_lock *lock);
+
+/*!
+ * \brief Geta named lock handle
+ * \since 13.9.0
+ *
+ * \param lock_type One of ast_named_lock_type
+ * \param keyspace
+ * \param key
+ * \retval A pointer to an ast_named_lock structure
+ * \retval NULL on error
+ *
+ * \note
+ * keyspace and key can be anything. For sorcery objects, keyspace could be the object type
+ * and key could be the object id.
+ */
+#define ast_named_lock_get(lock_type, keyspace, key) \
+ __ast_named_lock_get(__FILE__, __LINE__, __PRETTY_FUNCTION__, lock_type, \
+ keyspace, key)
+
+/*!
+ * \brief Put a named lock handle away
+ * \since 13.9.0
+ *
+ * \param lock The pointer to the ast_named_lock structure returned by ast_named_lock_get
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+#define ast_named_lock_put(lock) \
+ __ast_named_lock_put(__FILE__, __LINE__, __PRETTY_FUNCTION__, lock)
+
+/*!
+ * @}
+ */
+
+#endif /* INCLUDE_ASTERISK_NAMED_LOCKS_H_ */
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index 18b576066..afdcc8da4 100644
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -109,7 +109,7 @@ struct ast_state_cb_info {
};
/*! \brief Typedef for devicestate and hint callbacks */
-typedef int (*ast_state_cb_type)(char *context, char *id, struct ast_state_cb_info *info, void *data);
+typedef int (*ast_state_cb_type)(const char *context, const char *exten, struct ast_state_cb_info *info, void *data);
/*! \brief Typedef for devicestate and hint callback removal indication callback */
typedef void (*ast_state_cb_destroy_type)(int id, void *data);
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 2c26c25da..1bfae66b3 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -996,10 +996,28 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct
*
* \retval NULL if no contacts available
* \retval non-NULL if contacts available
+ *
+ * \warning
+ * Since this function prunes expired contacts before returning, it holds a named write
+ * lock on the aor. If you already hold the lock, call ast_sip_location_retrieve_aor_contacts_nolock instead.
*/
struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor);
/*!
+ * \brief Retrieve all contacts currently available for an AOR without locking the AOR
+ * \since 13.9.0
+ *
+ * \param aor Pointer to the AOR
+ *
+ * \retval NULL if no contacts available
+ * \retval non-NULL if contacts available
+ *
+ * \warning
+ * This function should only be called if you already hold a named write lock on the aor.
+ */
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor);
+
+/*!
* \brief Retrieve the first bound contact from a list of AORs
*
* \param aor_list A comma-separated list of AOR names
@@ -1049,12 +1067,37 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
*
* \retval -1 failure
* \retval 0 success
+ *
+ * \warning
+ * This function holds a named write lock on the aor. If you already hold the lock
+ * you should call ast_sip_location_add_contact_nolock instead.
*/
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent,
struct ast_sip_endpoint *endpoint);
/*!
+ * \brief Add a new contact to an AOR without locking the AOR
+ * \since 13.9.0
+ *
+ * \param aor Pointer to the AOR
+ * \param uri Full contact URI
+ * \param expiration_time Optional expiration time of the contact
+ * \param path_info Path information
+ * \param user_agent User-Agent header from REGISTER request
+ * \param endpoint The endpoint that resulted in the contact being added
+ *
+ * \retval -1 failure
+ * \retval 0 success
+ *
+ * \warning
+ * This function should only be called if you already hold a named write lock on the aor.
+ */
+int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
+ struct timeval expiration_time, const char *path_info, const char *user_agent,
+ struct ast_sip_endpoint *endpoint);
+
+/*!
* \brief Update a contact
*
* \param contact New contact object with details
diff --git a/main/asterisk.c b/main/asterisk.c
index 7636ec7b4..bf2206cd7 100644
--- a/main/asterisk.c
+++ b/main/asterisk.c
@@ -4339,6 +4339,11 @@ static void asterisk_daemon(int isroot, const char *runuser, const char *rungrou
exit(1);
}
+ if (ast_named_locks_init()) {
+ printf("Failed: ast_named_locks_init\n%s", term_quit());
+ exit(1);
+ }
+
if (ast_opt_console) {
if (el_hist == NULL || el == NULL)
ast_el_initialize();
diff --git a/main/core_unreal.c b/main/core_unreal.c
index 1f5c202ba..377abd1ff 100644
--- a/main/core_unreal.c
+++ b/main/core_unreal.c
@@ -566,6 +566,11 @@ int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data
res = -1;
}
break;
+ case AST_CONTROL_PVT_CAUSE_CODE:
+ /* Return -1 so that asterisk core will correctly set up hangupcauses. */
+ unreal_queue_indicate(p, ast, condition, data, datalen);
+ res = -1;
+ break;
default:
res = unreal_queue_indicate(p, ast, condition, data, datalen);
break;
diff --git a/main/manager.c b/main/manager.c
index e74b253ff..74e953333 100644
--- a/main/manager.c
+++ b/main/manager.c
@@ -6765,7 +6765,7 @@ int ast_manager_unregister(const char *action)
return 0;
}
-static int manager_state_cb(char *context, char *exten, struct ast_state_cb_info *info, void *data)
+static int manager_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
{
/* Notify managers of change */
char hint[512];
diff --git a/main/named_locks.c b/main/named_locks.c
new file mode 100644
index 000000000..b977b553c
--- /dev/null
+++ b/main/named_locks.c
@@ -0,0 +1,142 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Named Locks
+ *
+ * \author George Joseph <george.joseph@fairview5.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_REGISTER_FILE()
+
+#include "asterisk/_private.h"
+#include "asterisk/astobj2.h"
+#include "asterisk/named_locks.h"
+#include "asterisk/utils.h"
+
+struct ao2_container *named_locks;
+#define NAMED_LOCKS_BUCKETS 101
+
+struct ast_named_lock {
+ char key[0];
+};
+
+static int named_locks_hash(const void *obj, const int flags)
+{
+ const struct ast_named_lock *lock = obj;
+
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_KEY:
+ return ast_str_hash(obj);
+ case OBJ_SEARCH_OBJECT:
+ return ast_str_hash(lock->key);
+ default:
+ /* Hash can only work on something with a full key. */
+ ast_assert(0);
+ return 0;
+ }
+}
+
+static int named_locks_cmp(void *obj_left, void *obj_right, int flags)
+{
+ const struct ast_named_lock *object_left = obj_left;
+ const struct ast_named_lock *object_right = obj_right;
+ const char *right_key = obj_right;
+ int cmp;
+
+ switch (flags & OBJ_SEARCH_MASK) {
+ case OBJ_SEARCH_OBJECT:
+ right_key = object_right->key;
+ /* Fall through */
+ case OBJ_SEARCH_KEY:
+ cmp = strcmp(object_left->key, right_key);
+ break;
+ case OBJ_SEARCH_PARTIAL_KEY:
+ cmp = strncmp(object_left->key, right_key, strlen(right_key));
+ break;
+ default:
+ cmp = 0;
+ break;
+ }
+
+ return cmp ? 0 : CMP_MATCH;
+}
+
+static void named_locks_shutdown(void)
+{
+ ao2_cleanup(named_locks);
+}
+
+int ast_named_locks_init(void)
+{
+ named_locks = ao2_container_alloc_hash(0, 0, NAMED_LOCKS_BUCKETS, named_locks_hash, NULL,
+ named_locks_cmp);
+ if (!named_locks) {
+ return -1;
+ }
+
+ ast_register_cleanup(named_locks_shutdown);
+
+ return 0;
+}
+
+struct ast_named_lock *__ast_named_lock_get(const char *filename, int lineno, const char *func,
+ enum ast_named_lock_type lock_type, const char *keyspace, const char *key)
+{
+ struct ast_named_lock *lock = NULL;
+ int concat_key_buff_len = strlen(keyspace) + strlen(key) + 2;
+ char *concat_key = ast_alloca(concat_key_buff_len);
+
+ sprintf(concat_key, "%s-%s", keyspace, key); /* Safe */
+
+ ao2_lock(named_locks);
+ lock = ao2_find(named_locks, concat_key, OBJ_SEARCH_KEY | OBJ_NOLOCK);
+ if (lock) {
+ ao2_unlock(named_locks);
+ ast_assert((ao2_options_get(lock) & AO2_ALLOC_OPT_LOCK_MASK) == lock_type);
+ return lock;
+ }
+
+ lock = ao2_alloc_options(sizeof(*lock) + concat_key_buff_len, NULL, lock_type);
+ if (lock) {
+ strcpy(lock->key, concat_key); /* Safe */
+ ao2_link_flags(named_locks, lock, OBJ_NOLOCK);
+ }
+ ao2_unlock(named_locks);
+
+ return lock;
+}
+
+int __ast_named_lock_put(const char *filename, int lineno, const char *func,
+ struct ast_named_lock *lock)
+{
+ if (!lock) {
+ return -1;
+ }
+
+ ao2_lock(named_locks);
+ if (ao2_ref(lock, -1) == 2) {
+ ao2_unlink_flags(named_locks, lock, OBJ_NOLOCK);
+ }
+ ao2_unlock(named_locks);
+
+ return 0;
+}
diff --git a/main/pbx.c b/main/pbx.c
index 1b78bbb32..df9cad326 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -3231,8 +3231,7 @@ static int execute_state_callback(ast_state_cb_type cb,
info.exten_state = AST_EXTENSION_REMOVED;
}
- /* NOTE: The casts will not be needed for v10 and later */
- res = cb((char *) context, (char *) exten, &info, data);
+ res = cb(context, exten, &info, data);
return res;
}
@@ -3322,7 +3321,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
{
struct ao2_iterator cb_iter;
struct ast_state_cb *state_cb;
- int state, same_state;
+ int state;
+ int same_state;
struct ao2_container *device_state_info;
int first_extended_cb_call = 1;
char context_name[AST_MAX_CONTEXT];
@@ -3361,7 +3361,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
device_state_info = alloc_device_state_info();
state = ast_extension_state3(*hint_app, device_state_info);
- if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) {
+ same_state = state == hint->laststate;
+ if (same_state && (~state & AST_EXTENSION_RINGING)) {
ao2_cleanup(device_state_info);
return;
}
@@ -3370,17 +3371,19 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
hint->laststate = state; /* record we saw the change */
/* For general callbacks */
- cb_iter = ao2_iterator_init(statecbs, 0);
- for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
- execute_state_callback(state_cb->change_cb,
- context_name,
- exten_name,
- state_cb->data,
- AST_HINT_UPDATE_DEVICE,
- hint,
- NULL);
+ if (!same_state) {
+ cb_iter = ao2_iterator_init(statecbs, 0);
+ for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+ execute_state_callback(state_cb->change_cb,
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint,
+ NULL);
+ }
+ ao2_iterator_destroy(&cb_iter);
}
- ao2_iterator_destroy(&cb_iter);
/* For extension callbacks */
/* extended callbacks are called when the state changed or when AST_STATE_RINGING is
@@ -3395,12 +3398,12 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
}
if (state_cb->extended || !same_state) {
execute_state_callback(state_cb->change_cb,
- context_name,
- exten_name,
- state_cb->data,
- AST_HINT_UPDATE_DEVICE,
- hint,
- state_cb->extended ? device_state_info : NULL);
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint,
+ state_cb->extended ? device_state_info : NULL);
}
}
ao2_iterator_destroy(&cb_iter);
@@ -3458,12 +3461,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st
cb_iter = ao2_iterator_init(statecbs, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
execute_state_callback(state_cb->change_cb,
- context_name,
- exten_name,
- state_cb->data,
- AST_HINT_UPDATE_PRESENCE,
- hint,
- NULL);
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_PRESENCE,
+ hint,
+ NULL);
}
ao2_iterator_destroy(&cb_iter);
@@ -3471,12 +3474,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st
cb_iter = ao2_iterator_init(hint->callbacks, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
execute_state_callback(state_cb->change_cb,
- context_name,
- exten_name,
- state_cb->data,
- AST_HINT_UPDATE_PRESENCE,
- hint,
- NULL);
+ context_name,
+ exten_name,
+ state_cb->data,
+ AST_HINT_UPDATE_PRESENCE,
+ hint,
+ NULL);
}
ao2_iterator_destroy(&cb_iter);
}
@@ -3496,27 +3499,32 @@ static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_
hint = stasis_message_data(msg);
- if (reason == AST_HINT_UPDATE_DEVICE) {
+ switch (reason) {
+ case AST_HINT_UPDATE_DEVICE:
device_state_notify_callbacks(hint, &hint_app);
- } else if (reason == AST_HINT_UPDATE_PRESENCE) {
- char *presence_subtype = NULL;
- char *presence_message = NULL;
- int state;
+ break;
+ case AST_HINT_UPDATE_PRESENCE:
+ {
+ char *presence_subtype = NULL;
+ char *presence_message = NULL;
+ int state;
- state = extension_presence_state_helper(
- hint->exten, &presence_subtype, &presence_message);
+ state = extension_presence_state_helper(
+ hint->exten, &presence_subtype, &presence_message);
+ {
+ struct ast_presence_state_message presence_state = {
+ .state = state > 0 ? state : AST_PRESENCE_INVALID,
+ .subtype = presence_subtype,
+ .message = presence_message
+ };
- {
- struct ast_presence_state_message presence_state = {
- .state = state > 0 ? state : AST_PRESENCE_INVALID,
- .subtype = presence_subtype,
- .message = presence_message
- };
- presence_state_notify_callbacks(hint, &hint_app, &presence_state);
- }
+ presence_state_notify_callbacks(hint, &hint_app, &presence_state);
+ }
- ast_free(presence_subtype);
- ast_free(presence_message);
+ ast_free(presence_subtype);
+ ast_free(presence_message);
+ }
+ break;
}
ast_free(hint_app);
@@ -3976,12 +3984,12 @@ static int ast_add_hint(struct ast_exten *e)
cb_iter = ao2_iterator_init(statecbs, 0);
for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
execute_state_callback(state_cb->change_cb,
- ast_get_context_name(ast_get_extension_context(e)),
- ast_get_extension_name(e),
- state_cb->data,
- AST_HINT_UPDATE_DEVICE,
- hint_new,
- NULL);
+ ast_get_context_name(ast_get_extension_context(e)),
+ ast_get_extension_name(e),
+ state_cb->data,
+ AST_HINT_UPDATE_DEVICE,
+ hint_new,
+ NULL);
}
ao2_iterator_destroy(&cb_iter);
}
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 3145daca0..bc14f184b 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -27,6 +27,7 @@
#include "include/res_pjsip_private.h"
#include "asterisk/res_pjsip_cli.h"
#include "asterisk/statsd.h"
+#include "asterisk/named_locks.h"
/*! \brief Destructor for AOR */
static void aor_destroy(void *obj)
@@ -168,7 +169,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct
return contact;
}
-struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
+struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
{
/* Give enough space for ^ at the beginning and ;@ at the end, since that is our object naming scheme */
char regex[strlen(ast_sorcery_object_get_id(aor)) + 4];
@@ -191,6 +192,24 @@ struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_si
return contacts;
}
+struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
+{
+ struct ao2_container *contacts;
+ struct ast_named_lock *lock;
+
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor));
+ if (!lock) {
+ return NULL;
+ }
+
+ ao2_wrlock(lock);
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+
+ return contacts;
+}
+
void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
struct ast_sip_contact **contact)
{
@@ -274,7 +293,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
}
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
+int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent,
struct ast_sip_endpoint *endpoint)
{
@@ -311,6 +330,27 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
return ast_sorcery_create(ast_sip_get_sorcery(), contact);
}
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
+ struct timeval expiration_time, const char *path_info, const char *user_agent,
+ struct ast_sip_endpoint *endpoint)
+{
+ int res;
+ struct ast_named_lock *lock;
+
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", ast_sorcery_object_get_id(aor));
+ if (!lock) {
+ return -1;
+ }
+
+ ao2_wrlock(lock);
+ res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent,
+ endpoint);
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+
+ return res;
+}
+
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
{
return ast_sorcery_update(ast_sip_get_sorcery(), contact);
diff --git a/res/res_pjsip_exten_state.c b/res/res_pjsip_exten_state.c
index 27d16bd67..a4ad1cd78 100644
--- a/res/res_pjsip_exten_state.c
+++ b/res/res_pjsip_exten_state.c
@@ -191,8 +191,9 @@ static void notify_task_data_destructor(void *obj)
ast_free(task_data->exten_state_data.user_agent);
}
-static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
- struct ast_state_cb_info *info)
+static struct notify_task_data *alloc_notify_task_data(const char *exten,
+ struct exten_state_subscription *exten_state_sub,
+ struct ast_state_cb_info *info)
{
struct notify_task_data *task_data =
ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
@@ -270,8 +271,8 @@ static int notify_task(void *obj)
*
* Upon state change, send the appropriate notification to the subscriber.
*/
-static int state_changed(char *context, char *exten,
- struct ast_state_cb_info *info, void *data)
+static int state_changed(const char *context, const char *exten,
+ struct ast_state_cb_info *info, void *data)
{
struct notify_task_data *task_data;
struct exten_state_subscription *exten_state_sub = data;
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 46d24324a..97cf34ae6 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -32,6 +32,7 @@
#include "asterisk/test.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/manager.h"
+#include "asterisk/named_locks.h"
#include "res_pjsip/include/res_pjsip_private.h"
/*** DOCUMENTATION
@@ -412,27 +413,21 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st
return -1;
}
-static int rx_task(void *data)
+static int rx_task_core(struct rx_task_data *task_data, struct ao2_container *contacts,
+ const char *aor_name)
{
static const pj_str_t USER_AGENT = { "User-Agent", 10 };
- RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
- RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
int added = 0, updated = 0, deleted = 0;
pjsip_contact_hdr *contact_hdr = NULL;
struct registrar_contact_details details = { 0, };
pjsip_tx_data *tdata;
- const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
struct ast_sip_contact *response_contact;
char *user_agent = NULL;
pjsip_user_agent_hdr *user_agent_hdr;
pjsip_expires_hdr *expires_hdr;
- /* Retrieve the current contacts, we'll need to know whether to update or not */
- contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
-
/* So we don't count static contacts against max_contacts we prune them out from the container */
ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL);
@@ -503,7 +498,7 @@ static int rx_task(void *data)
continue;
}
- if (ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
+ if (ast_sip_location_add_contact_nolock(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
user_agent, task_data->endpoint)) {
ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
@@ -545,7 +540,7 @@ static int rx_task(void *data)
if (ast_sip_location_update_contact(contact_update)) {
ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
contact->uri, expiration);
- ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+ ast_sip_location_delete_contact(contact);
continue;
}
ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
@@ -584,15 +579,14 @@ static int rx_task(void *data)
ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL);
}
- /* Update the contacts as things will probably have changed */
- ao2_cleanup(contacts);
-
- contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
+ /* Re-retrieve contacts. Caller will clean up the original container. */
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor);
response_contact = ao2_callback(contacts, 0, NULL, NULL);
/* Send a response containing all of the contacts (including static) that are present on this AOR */
if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
ao2_cleanup(response_contact);
+ ao2_cleanup(contacts);
return PJ_TRUE;
}
ao2_cleanup(response_contact);
@@ -601,6 +595,7 @@ static int rx_task(void *data)
registrar_add_date_header(tdata);
ao2_callback(contacts, 0, registrar_add_contact, tdata);
+ ao2_cleanup(contacts);
if ((expires_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(task_data->aor, NULL, task_data->rdata));
@@ -612,6 +607,38 @@ static int rx_task(void *data)
return PJ_TRUE;
}
+static int rx_task(void *data)
+{
+ int res;
+ struct rx_task_data *task_data = data;
+ struct ao2_container *contacts = NULL;
+ struct ast_named_lock *lock;
+ const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
+
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", aor_name);
+ if (!lock) {
+ ao2_cleanup(task_data);
+ return PJ_TRUE;
+ }
+
+ ao2_wrlock(lock);
+ contacts = ast_sip_location_retrieve_aor_contacts_nolock(task_data->aor);
+ if (!contacts) {
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+ ao2_cleanup(task_data);
+ return PJ_TRUE;
+ }
+
+ res = rx_task_core(task_data, contacts, aor_name);
+ ao2_cleanup(contacts);
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
+ ao2_cleanup(task_data);
+
+ return res;
+}
+
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
{
RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup);
diff --git a/res/res_pjsip_registrar_expire.c b/res/res_pjsip_registrar_expire.c
index e52363e13..0d979a13f 100644
--- a/res/res_pjsip_registrar_expire.c
+++ b/res/res_pjsip_registrar_expire.c
@@ -30,6 +30,7 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
+#include "asterisk/named_locks.h"
/*! \brief Thread keeping things alive */
static pthread_t check_thread = AST_PTHREADT_NULL;
@@ -41,8 +42,23 @@ static unsigned int check_interval;
static int expire_contact(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
+ struct ast_named_lock *lock;
- ast_sorcery_delete(ast_sip_get_sorcery(), contact);
+ lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_RWLOCK, "aor", contact->aor);
+ if (!lock) {
+ return 0;
+ }
+
+ /*
+ * We need to check the expiration again with the aor lock held
+ * in case another thread is attempting to renew the contact.
+ */
+ ao2_wrlock(lock);
+ if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
+ ast_sip_location_delete_contact(contact);
+ }
+ ao2_unlock(lock);
+ ast_named_lock_put(lock);
return 0;
}
diff --git a/tests/test_named_lock.c b/tests/test_named_lock.c
new file mode 100644
index 000000000..9e383088e
--- /dev/null
+++ b/tests/test_named_lock.c
@@ -0,0 +1,151 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2016, Fairview 5 Engineering, LLC
+ *
+ * George Joseph <george.joseph@fairview5.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \brief Named Lock unit tests
+ *
+ * \author George Joseph <george.joseph@fairview5.com>
+ *
+ */
+
+/*** MODULEINFO
+ <depend>TEST_FRAMEWORK</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+#include <signal.h>
+
+#include "asterisk/test.h"
+#include "asterisk/utils.h"
+#include "asterisk/module.h"
+#include "asterisk/lock.h"
+#include "asterisk/named_locks.h"
+
+static void *lock_thread(void *data)
+{
+ struct ast_named_lock *lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", data);
+
+ if (!lock) {
+ return NULL;
+ }
+
+ ao2_lock(lock);
+ usleep(3000000);
+ ao2_unlock(lock);
+
+ ast_named_lock_put(lock);
+
+ return NULL;
+}
+
+AST_TEST_DEFINE(named_lock_test)
+{
+ enum ast_test_result_state res = AST_TEST_FAIL;
+ struct ast_named_lock *lock1 = NULL;
+ struct ast_named_lock *lock2 = NULL;
+ pthread_t thread1;
+ pthread_t thread2;
+ struct timeval start_time;
+ int64_t duration;
+
+ switch(cmd) {
+ case TEST_INIT:
+ info->name = "named_lock_test";
+ info->category = "/main/lock/";
+ info->summary = "Named Lock test";
+ info->description =
+ "Tests that named locks operate as expected";
+ return AST_TEST_NOT_RUN;
+ case TEST_EXECUTE:
+ break;
+ }
+
+ ast_test_status_update(test, "This test should take about 3 seconds\n");
+
+ /* 2 locks/threads to make sure they're independent */
+ ast_pthread_create(&thread1, NULL, lock_thread, "lock_1");
+ ast_pthread_create(&thread2, NULL, lock_thread, "lock_2");
+
+ lock1 = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", "lock_1");
+ ast_test_validate_cleanup(test, lock1 != NULL, res, fail);
+
+ lock2 = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "lock_test", "lock_2");
+ ast_test_validate_cleanup(test, lock2 != NULL, res, fail);
+
+ usleep(1000000);
+
+ /* These should both fail */
+ if (!ao2_trylock(lock1)) {
+ ast_test_status_update(test, "ao2_trylock on lock1 succeeded when it should have failed\n");
+ ao2_unlock(lock1);
+ goto fail;
+ }
+
+ if (!ao2_trylock(lock2)) {
+ ast_test_status_update(test, "ao2_trylock on lock2 succeeded when it should have failed\n");
+ ao2_unlock(lock2);
+ goto fail;
+ }
+
+ start_time = ast_tvnow();
+
+ /* These should both succeed eventually */
+ if (ao2_lock(lock1)) {
+ ast_test_status_update(test, "ao2_lock on lock1 failed\n");
+ goto fail;
+ }
+ ao2_unlock(lock1);
+
+ if (ao2_lock(lock2)) {
+ ast_test_status_update(test, "ao2_lock on lock2 failed\n");
+ goto fail;
+ }
+ ao2_unlock(lock2);
+
+ duration = ast_tvdiff_ms(ast_tvnow(), start_time);
+ ast_test_validate_cleanup(test, duration > 1500 && duration < 3500, res, fail);
+
+ res = AST_TEST_PASS;
+
+fail:
+
+ ast_named_lock_put(lock1);
+ ast_named_lock_put(lock2);
+
+ pthread_join(thread1, NULL);
+ pthread_join(thread2, NULL);
+
+ return res;
+}
+
+
+static int unload_module(void)
+{
+ AST_TEST_UNREGISTER(named_lock_test);
+ return 0;
+}
+
+static int load_module(void)
+{
+ AST_TEST_REGISTER(named_lock_test);
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Named Lock test module");
diff --git a/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch b/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch
new file mode 100644
index 000000000..60c27cb1a
--- /dev/null
+++ b/third-party/pjproject/patches/0001-sip_parser.c-Fix-pjsip_VIA_PARAM_SPEC_ESC.patch
@@ -0,0 +1,30 @@
+From 0fc7ef5f01be9cc74d184c3ca3a973ff1ef44c93 Mon Sep 17 00:00:00 2001
+From: George Joseph <george.joseph@fairview5.com>
+Date: Sun, 10 Apr 2016 12:54:06 -0600
+Subject: [PATCH] sip_parser.c: Fix pjsip_VIA_PARAM_SPEC_ESC
+
+pjsip_VIA_PARAM_SPEC_ESC should have been pjsip_TOKEN_SPEC_ESC + ":" but
+instead of appending ":" to pjsip_VIA_PARAM_SPEC_ESC it was being appended
+to pjsip_VIA_PARAM_SPEC again. This was causing parsing of Via headers
+to fail when an ipv6 address was in a "received" param and
+PJSIP_UNESCAPE_IN_PLACE was used. Probably just a copy/paste error.
+---
+ pjsip/src/pjsip/sip_parser.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/pjsip/src/pjsip/sip_parser.c b/pjsip/src/pjsip/sip_parser.c
+index 378c22f..c18faa3 100644
+--- a/pjsip/src/pjsip/sip_parser.c
++++ b/pjsip/src/pjsip/sip_parser.c
+@@ -327,7 +327,7 @@ static pj_status_t init_parser()
+
+ status = pj_cis_dup(&pconst.pjsip_VIA_PARAM_SPEC_ESC, &pconst.pjsip_TOKEN_SPEC_ESC);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+- pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC, ":");
++ pj_cis_add_str(&pconst.pjsip_VIA_PARAM_SPEC_ESC, ":");
+
+ status = pj_cis_dup(&pconst.pjsip_HOST_SPEC, &pconst.pjsip_ALNUM_SPEC);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
+--
+2.5.5
+