summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES6
-rw-r--r--configs/samples/pjsip.conf.sample2
-rwxr-xr-xconfigure2
-rw-r--r--configure.ac2
-rw-r--r--contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py22
-rwxr-xr-xcontrib/scripts/sip_to_pjsip/sip_to_pjsip.py147
-rw-r--r--include/asterisk/res_pjsip.h2
-rw-r--r--res/res_pjsip.c26
-rw-r--r--res/res_pjsip/pjsip_configuration.c27
-rw-r--r--res/res_pjsip_session.c30
-rw-r--r--rest-api-templates/api.wiki.mustache4
11 files changed, 206 insertions, 64 deletions
diff --git a/CHANGES b/CHANGES
index 95354791b..1dfd445c8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -37,6 +37,12 @@ chan_pjsip
dialplan function PJSIP_MEDIA_OFFER, this allows the formats on a PJSIP
channel to be re-negotiated and updated after session set up.
+res_pjsip
+------------------
+ * A new endpoint configuration parameter 'contact_user' has been added which
+ when set will override the default user set on Contact headers in outgoing
+ requests.
+
------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.10.0 to Asterisk 13.11.0 ----------
------------------------------------------------------------------------------
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 2851945ed..994c8e01c 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -760,6 +760,8 @@
;rtp_timeout_hold= ; Hang up channel if RTP is not received for the specified
; number of seconds when the channel is on hold (default:
; "0" or not enabled)
+;contact_user= ; On outgoing requests, force the user portion of the Contact
+ ; header to this value (default: "")
;==========================AUTH SECTION OPTIONS=========================
;[auth]
diff --git a/configure b/configure
index 1f6c88869..7f6b5dddf 100755
--- a/configure
+++ b/configure
@@ -25329,7 +25329,7 @@ if test "x${PBX_PJ_SSL_CERT_LOAD_FROM_FILES2}" != "x1" -a "${USE_PJ_SSL_CERT_LOA
pbxlibdir="-L${PJ_SSL_CERT_LOAD_FROM_FILES2_DIR}"
fi
fi
- pbxfuncname="pjsip/include/pjsip/sip_util.h"
+ pbxfuncname="pj_ssl_cert_load_from_files2"
if test "x${pbxfuncname}" = "x" ; then # empty lib, assume only headers
AST_PJ_SSL_CERT_LOAD_FROM_FILES2_FOUND=yes
else
diff --git a/configure.ac b/configure.ac
index 637059cd4..588a50075 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2178,7 +2178,7 @@ if test "$USE_PJPROJECT" != "no" ; then
CPPFLAGS="${saved_cppflags}"
AST_EXT_LIB_CHECK([PJSIP_GET_DEST_INFO], [pjsip], [pjsip_get_dest_info], [pjsip.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
- AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pjsip/include/pjsip/sip_util.h], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
+ AST_EXT_LIB_CHECK([PJ_SSL_CERT_LOAD_FROM_FILES2], [pj], [pj_ssl_cert_load_from_files2], [pjlib.h], [$PJPROJECT_LIB], [$PJPROJECT_CFLAGS])
AST_EXT_LIB_CHECK([PJSIP_EXTERNAL_RESOLVER], [pjsip], [pjsip_endpt_set_ext_resolver], [pjsip.h], [$PJPROJECT_LIBS], [$PJPROJECT_CFLAGS])
saved_cppflags="${CPPFLAGS}"
diff --git a/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py b/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py
new file mode 100644
index 000000000..f91cff04e
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/4e2493ef32e6_add_contact_user_to_endpoint.py
@@ -0,0 +1,22 @@
+"""Add contact_user to endpoint
+
+Revision ID: 4e2493ef32e6
+Revises: 3772f8f828da
+Create Date: 2016-08-16 14:19:58.918466
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '4e2493ef32e6'
+down_revision = '3772f8f828da'
+
+from alembic import op
+import sqlalchemy as sa
+
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('contact_user', sa.String(80)))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'contact_user')
diff --git a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
index 890921673..e598caad7 100755
--- a/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
+++ b/contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
@@ -54,10 +54,11 @@ def set_value(key=None, val=None, section=None, pjsip=None,
def merge_value(key=None, val=None, section=None, pjsip=None,
- nmapped=None, type='endpoint', section_to=None):
+ nmapped=None, type='endpoint', section_to=None,
+ key_to=None):
"""Merge values from the given section with those from the default."""
def _merge_value(k, v, s, r, n):
- merge_value(key if key else k, v, s, r, n, type, section_to)
+ merge_value(key if key else k, v, s, r, n, type, section_to, key_to)
# if no value or section return the merge_value
# function with the enclosed key and type
@@ -71,7 +72,8 @@ def merge_value(key=None, val=None, section=None, pjsip=None,
sect = sip.default(section)[0]
# for each merged value add it to pjsip.conf
for i in sect.get_merged(key):
- set_value(key, i, section_to if section_to else section,
+ set_value(key_to if key_to else key, i,
+ section_to if section_to else section,
pjsip, nmapped, type)
@@ -133,11 +135,14 @@ def set_timers(key, val, section, pjsip, nmapped):
found in sip.conf.
"""
# pjsip.conf values can be yes/no, required, always
+ # 'required' is a new feature of chan_pjsip, which rejects
+ # all SIP clients not supporting Session Timers
+ # 'Accept' is the default value of chan_sip and maps to 'yes'
+ # chan_sip ignores the case, for example 'session-timers=Refuse'
+ val = val.lower()
if val == 'originate':
set_value('timers', 'always', section, pjsip, nmapped)
- elif val == 'accept':
- set_value('timers', 'required', section, pjsip, nmapped)
- elif val == 'never':
+ elif val == 'refuse':
set_value('timers', 'no', section, pjsip, nmapped)
else:
set_value('timers', 'yes', section, pjsip, nmapped)
@@ -396,7 +401,7 @@ peer_map = [
['trustpid', set_value('trust_id_inbound')],
['sendrpid', from_sendrpid], # send_pai, send_rpid
['send_diversion', set_value],
- ['encrpytion', set_media_encryption],
+ ['encryption', set_media_encryption],
['avpf', set_value('use_avpf')],
['recordonfeature', set_record_on_feature], # automixon
['recordofffeature', set_record_off_feature], # automixon
@@ -440,6 +445,9 @@ peer_map = [
['host', from_host], # contact, max_contacts
['qualifyfreq', set_value('qualify_frequency', type='aor')],
+ ['maxexpiry', set_value('maximum_expiration', type='aor')],
+ ['minexpiry', set_value('minimum_expiration', type='aor')],
+ ['defaultexpiry', set_value('default_expiration', type='aor')],
############################# maps to auth#####################################
# type = auth
@@ -454,9 +462,9 @@ peer_map = [
['permit', merge_value(type='acl', section_to='acl')],
['deny', merge_value(type='acl', section_to='acl')],
['acl', merge_value(type='acl', section_to='acl')],
- ['contactpermit', merge_value('contact_permit', type='acl', section_to='acl')],
- ['contactdeny', merge_value('contact_deny', type='acl', section_to='acl')],
- ['contactacl', merge_value('contact_acl', type='acl', section_to='acl')],
+ ['contactpermit', merge_value(type='acl', section_to='acl', key_to='contact_permit')],
+ ['contactdeny', merge_value(type='acl', section_to='acl', key_to='contact_deny')],
+ ['contactacl', merge_value(type='acl', section_to='acl', key_to='contact_acl')],
########################### maps to transport #################################
# type = transport
@@ -464,6 +472,7 @@ peer_map = [
# bind
# async_operations
# ca_list_file
+# ca_list_path
# cert_file
# privkey_file
# password
@@ -499,21 +508,6 @@ peer_map = [
]
-def add_localnet(section, pjsip, nmapped):
- """
- Adds localnet values from sip.conf's general section to a transport in
- pjsip.conf. Ideally, we would have just created a template with the
- localnet sections, but because this is a script, it's not hard to add
- the same thing on to every transport.
- """
- try:
- merge_value('local_net', sip.get('general', 'localnet')[0], 'general',
- pjsip, nmapped, 'transport', section)
- except LookupError:
- # No localnet options configured. No biggie!
- pass
-
-
def set_transport_common(section, pjsip, nmapped):
"""
sip.conf has several global settings that in pjsip.conf apply to individual
@@ -527,21 +521,21 @@ def set_transport_common(section, pjsip, nmapped):
"""
try:
- merge_value('local_net', sip.get('general', 'localnet')[0], 'general',
- pjsip, nmapped, 'transport', section)
+ merge_value('localnet', sip.get('general', 'localnet')[0], 'general',
+ pjsip, nmapped, 'transport', section, "local_net")
except LookupError:
# No localnet options configured. Move on.
pass
try:
- set_value('tos', sip.get('general', 'sip_tos')[0], 'general', pjsip,
- nmapped, 'transport', section)
+ set_value('tos', sip.get('general', 'tos_sip')[0], section, pjsip,
+ nmapped, 'transport')
except LookupError:
pass
try:
- set_value('cos', sip.get('general', 'sip_cos')[0], 'general', pjsip,
- nmapped, 'transport', section)
+ set_value('cos', sip.get('general', 'cos_sip')[0], section, pjsip,
+ nmapped, 'transport')
except LookupError:
pass
@@ -697,6 +691,12 @@ def set_tls_bindaddr(val, pjsip, nmapped):
set_value('bind', bind, 'transport-tls', pjsip, nmapped, 'transport')
+def set_tls_cert_file(val, pjsip, section, nmapped):
+ """Sets cert_file based on sip.conf tlscertfile"""
+ set_value('cert_file', val, section, pjsip, nmapped,
+ 'transport')
+
+
def set_tls_private_key(val, pjsip, nmapped):
"""Sets privkey_file based on sip.conf tlsprivatekey or sslprivatekey"""
set_value('priv_key_file', val, 'transport-tls', pjsip, nmapped,
@@ -714,6 +714,12 @@ def set_tls_cafile(val, pjsip, nmapped):
'transport')
+def set_tls_capath(val, pjsip, nmapped):
+ """Sets ca_list_path based on sip.conf tlscapath"""
+ set_value('ca_list_path', val, 'transport-tls', pjsip, nmapped,
+ 'transport')
+
+
def set_tls_verifyclient(val, pjsip, nmapped):
"""Sets verify_client based on sip.conf tlsverifyclient"""
set_value('verify_client', val, 'transport-tls', pjsip, nmapped,
@@ -731,11 +737,6 @@ def set_tls_verifyserver(val, pjsip, nmapped):
'transport')
-def set_tls_method(val, pjsip, nmapped):
- """Sets method based on sip.conf tlsclientmethod or sslclientmethod"""
- set_value('method', val, 'transport-tls', pjsip, nmapped, 'transport')
-
-
def create_tls(sip, pjsip, nmapped):
"""
Creates a 'transport-tls' section in pjsip.conf based on the following
@@ -755,12 +756,13 @@ def create_tls(sip, pjsip, nmapped):
tls_map = [
(['tlsbindaddr', 'sslbindaddr'], set_tls_bindaddr),
+ (['tlscertfile', 'sslcert', 'tlscert'], set_tls_cert_file),
(['tlsprivatekey', 'sslprivatekey'], set_tls_private_key),
(['tlscipher', 'sslcipher'], set_tls_cipher),
(['tlscafile'], set_tls_cafile),
+ (['tlscapath', 'tlscadir'], set_tls_capath),
(['tlsverifyclient'], set_tls_verifyclient),
- (['tlsdontverifyserver'], set_tls_verifyserver),
- (['tlsclientmethod', 'sslclientmethod'], set_tls_method)
+ (['tlsdontverifyserver'], set_tls_verifyserver)
]
try:
@@ -780,6 +782,23 @@ def create_tls(sip, pjsip, nmapped):
except LookupError:
pass
+ try:
+ method = sip.multi_get('general', ['tlsclientmethod', 'sslclientmethod'])[0]
+ print 'In chan_sip, you specified the TLS version. With chan_sip, this was just for outbound client connections. In chan_pjsip, this value is for client and server. Instead, consider not to specify \'tlsclientmethod\' for chan_sip and \'method = sslv23\' for chan_pjsip.'
+ except LookupError:
+ """
+ OpenSSL emerged during the 90s. SSLv2 and SSLv3 were the only
+ existing methods at that time. The OpenSSL project continued. And as
+ of today (OpenSSL 1.0.2) this does not start SSLv2 and SSLv3 anymore
+ but TLSv1.0 and v1.2. Or stated differently: This method should
+ have been called 'method = secure' or 'method = automatic' back in
+ the 90s. The PJProject did not realize this and uses 'tlsv1' as
+ default when unspecified, which disables TLSv1.2. chan_sip used
+ 'sslv23' as default when unspecified, which gives TLSv1.0 and v1.2.
+ """
+ method = 'sslv23'
+ set_value('method', method, 'transport-tls', pjsip, nmapped, 'transport')
+
set_transport_common('transport-tls', pjsip, nmapped)
try:
extern_addr = sip.multi_get('general', ['externaddr', 'externip',
@@ -907,6 +926,17 @@ class Registration:
the right of the user, then finish by using rpartition calls to remove
everything to the left of the user.
"""
+ self.peer = ''
+ self.protocol = 'udp'
+ protocols = ['udp', 'tcp', 'tls']
+ for protocol in protocols:
+ position = user_part.find(protocol + '://')
+ if -1 < position:
+ post_transport = user_part[position + 6:]
+ self.peer, sep, self.protocol = user_part[:position + 3].rpartition('?')
+ user_part = post_transport
+ break
+
colons = user_part.count(':')
if (colons == 3):
# :domainport:secret:authuser
@@ -927,11 +957,7 @@ class Registration:
# Invalid setting
raise
- pre_domain, sep, self.domain = pre_auth.partition('@')
- self.peer, sep, post_peer = pre_domain.rpartition('?')
- transport, sep, self.user = post_peer.rpartition('://')
-
- self.protocol = transport if transport else 'udp'
+ self.user, sep, self.domain = pre_auth.partition('@')
def write(self, pjsip, nmapped):
"""
@@ -981,9 +1007,8 @@ class Registration:
if hasattr(self, 'secret') and self.secret:
set_value('password', self.secret, auth_section, pjsip, nmapped,
'auth')
- if hasattr(self, 'authuser'):
- set_value('username', self.authuser or self.user, auth_section,
- pjsip, nmapped, 'auth')
+ set_value('username', self.authuser if hasattr(self, 'authuser')
+ else self.user, auth_section, pjsip, nmapped, 'auth')
set_value('outbound_auth', auth_section, section, pjsip, nmapped,
'registration')
@@ -1080,6 +1105,35 @@ def find_non_mapped(sections, nmapped):
pass
+def map_system(sip, pjsip, nmapped):
+ section = 'system' # Just a label; you as user can change that
+ type = 'system' # Not a label, therefore not the same as section
+
+ try:
+ user_agent = sip.get('general', 'useragent')[0]
+ set_value('user_agent', user_agent, 'global', pjsip, nmapped, 'global')
+ except LookupError:
+ pass
+
+ try:
+ timer_t1 = sip.get('general', 'timert1')[0]
+ set_value('timer_t1', timer_t1, section, pjsip, nmapped, type)
+ except LookupError:
+ pass
+
+ try:
+ timer_b = sip.get('general', 'timerb')[0]
+ set_value('timer_b', timer_b, section, pjsip, nmapped, type)
+ except LookupError:
+ pass
+
+ try:
+ compact_headers = sip.get('general', 'compactheaders')[0]
+ set_value('compact_headers', compact_headers, section, pjsip, nmapped, type)
+ except LookupError:
+ pass
+
+
def convert(sip, filename, non_mappings, include):
"""
Entry point for configuration file conversion. This
@@ -1092,6 +1146,7 @@ def convert(sip, filename, non_mappings, include):
nmapped = non_mapped(non_mappings[filename])
if not include:
# Don't duplicate transport and registration configs
+ map_system(sip, pjsip, nmapped)
map_transports(sip, pjsip, nmapped)
map_registrations(sip, pjsip, nmapped)
map_auth(sip, pjsip, nmapped)
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 72a2ff351..002182b9a 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -751,6 +751,8 @@ struct ast_sip_endpoint {
struct ast_acl_list *contact_acl;
/*! The number of seconds into call to disable fax detection. (0 = disabled) */
unsigned int faxdetect_timeout;
+ /*! Override the user on the outgoing Contact header with this value. */
+ char *contact_user;
};
/*!
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index aafb3a211..96c07d501 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -913,6 +913,12 @@
then the <replaceable>context</replaceable> setting is used.
</para></description>
</configOption>
+ <configOption name="contact_user" default="">
+ <synopsis>Force the user on the outgoing Contact header to this value.</synopsis>
+ <description><para>
+ On outbound requests, force the user portion of the Contact header to this value.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="auth">
<synopsis>Authentication type</synopsis>
@@ -2869,8 +2875,16 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint,
/* Update the dialog with the new local URI, we do it afterwards so we can use the dialog pool for construction */
pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri);
dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0);
+
dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen, NULL);
+ if (!ast_strlen_zero(endpoint->contact_user)) {
+ pjsip_sip_uri *sip_uri;
+
+ sip_uri = pjsip_uri_get_uri(dlg->local.contact->uri);
+ pj_strdup2(dlg->pool, &sip_uri->user, endpoint->contact_user);
+ }
+
/* If a request user has been specified and we are permitted to change it, do so */
if (!ast_strlen_zero(request_user)) {
pjsip_sip_uri *sip_uri;
@@ -3172,6 +3186,18 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
return -1;
}
+ if (endpoint && !ast_strlen_zero(endpoint->contact_user)){
+ pjsip_contact_hdr *contact_hdr;
+ pjsip_sip_uri *contact_uri;
+ static const pj_str_t HCONTACT = { "Contact", 7 };
+
+ contact_hdr = pjsip_msg_find_hdr_by_name((*tdata)->msg, &HCONTACT, NULL);
+ if (contact_hdr) {
+ contact_uri = pjsip_uri_get_uri(contact_hdr->uri);
+ pj_strdup2(pool, &contact_uri->user, endpoint->contact_user);
+ }
+ }
+
/* Add the user=phone parameter if applicable */
ast_sip_add_usereqphone(endpoint, (*tdata)->pool, (*tdata)->msg->line.req.uri);
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 9e757e230..c3012c4b2 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1211,6 +1211,31 @@ static int voicemail_extension_to_str(const void *obj, const intptr_t *args, cha
return 0;
}
+static int contact_user_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+
+ endpoint->contact_user = ast_strdup(var->value);
+ if (!endpoint->contact_user) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int contact_user_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+
+ *buf = ast_strdup(endpoint->contact_user);
+ if (!(*buf)) {
+ return -1;
+ }
+
+ return 0;
+}
+
static void *sip_nat_hook_alloc(const char *name)
{
return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
@@ -1907,6 +1932,7 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0);
ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context));
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
@@ -2038,6 +2064,7 @@ static void endpoint_destructor(void* obj)
ao2_cleanup(endpoint->persistent);
ast_variables_destroy(endpoint->channel_vars);
AST_VECTOR_FREE(&endpoint->ident_method_order);
+ ast_free(endpoint->contact_user);
}
static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index a41e0aa5d..856626a02 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -2741,22 +2741,21 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
}
break;
case PJSIP_EVENT_TRANSPORT_ERROR:
- /*
- * Clear the module data now to block session_inv_on_state_changed()
- * from calling session_end() if it hasn't already done so.
- */
- inv->mod_data[id] = NULL;
+ if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
+ /*
+ * Clear the module data now to block session_inv_on_state_changed()
+ * from calling session_end() if it hasn't already done so.
+ */
+ inv->mod_data[id] = NULL;
- if (inv->state != PJSIP_INV_STATE_DISCONNECTED) {
- session_end(session);
+ /*
+ * Pass the session ref held by session->inv_session to
+ * session_end_completion().
+ */
+ session_end_completion(session);
+ return;
}
-
- /*
- * Pass the session ref held by session->inv_session to
- * session_end_completion().
- */
- session_end_completion(session);
- return;
+ break;
case PJSIP_EVENT_TIMER:
/*
* The timer event is run by the pjsip monitor thread and not
@@ -2776,7 +2775,8 @@ static void session_inv_on_tsx_state_changed(pjsip_inv_session *inv, pjsip_trans
* Pass the session ref held by session->inv_session to
* session_end_completion().
*/
- if (ast_sip_push_task(session->serializer, session_end_completion, session)) {
+ if (session
+ && ast_sip_push_task(session->serializer, session_end_completion, session)) {
/* Do it anyway even though this is not the right thread. */
session_end_completion(session);
}
diff --git a/rest-api-templates/api.wiki.mustache b/rest-api-templates/api.wiki.mustache
index 0a54a64a7..ad12bb695 100644
--- a/rest-api-templates/api.wiki.mustache
+++ b/rest-api-templates/api.wiki.mustache
@@ -1,7 +1,8 @@
{{#api_declaration}}
h1. {{name_title}}
-|| Method || Path || Return Model || Summary ||
+|| Method || Path<br>h5. Parameters are case-sensitive || Return Model || Summary ||
+
{{#apis}}
{{#operations}}
| {{http_method}} | [{{wiki_path}}|#{{nickname}}] | {{#response_class}}{{#is_primitive}}{{name}}{{/is_primitive}}{{^is_primitive}}[{{wiki_name}}|{{wiki_prefix}} REST Data Models#{{singular_name}}]{{/is_primitive}}{{/response_class}} | {{summary}} |
@@ -17,6 +18,7 @@ h2. {{nickname}}: {{http_method}} {{wiki_path}}
{{#has_path_parameters}}
h3. Path parameters
+Parameters are case-sensitive.
{{#path_parameters}}
* {{name}}: _{{data_type}}_ - {{{wiki_description}}}
{{#default_value}}