<p>Nick French has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/9505">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">res_pjsip: Implement additional SIP RFCs for Google Voice trunk compatability<br><br>Implement the following additional SIP features that are required<br>by the Google Voice SIP registrar:<br><br>- Service-Routes (RFC 3608) and P-Preferred-Identity (RFC 3325), by storing<br> headers returned from a REGISTER response and using them in subsequent<br> INVITE/CANCELs<br>- OAuth / Bearer token authentication (draft-ietf-sipcore-sip-authn-02), by<br> using similar token requests as currently found in chan_motif but piping<br> them through to pjsip via REGISTER Authorization header<br>- Mechanisms to use separate TLS transports for separate registrations and<br> their associated message dialog, by creating a transport without going<br> through the pjsip transport pool and storing it in the client_state for reuse<br>- User-configurable additions to SIP Contact header<br><br>All functionality changes are controlled by pjsip.conf configuration options<br>and do not affect non-configured pjsip endpoints otherwise.<br><br>Change-Id: Id214c2d1c550a41fcf564b7df8f3da7be565bd58<br>---<br>M include/asterisk/res_pjsip.h<br>M res/res_pjsip.c<br>M res/res_pjsip/config_auth.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_outbound_authenticator_digest.c<br>M res/res_pjsip_outbound_registration.c<br>A third-party/pjproject/patches/0110-oauth.patch<br>A third-party/pjproject/patches/0120-contact-params.patch<br>8 files changed, 789 insertions(+), 22 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/05/9505/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index 849f087..493fb94 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -401,6 +401,8 @@</span><br><span> AST_SIP_AUTH_TYPE_USER_PASS,</span><br><span> /*! Credentials stored as an MD5 sum */</span><br><span> AST_SIP_AUTH_TYPE_MD5,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Oauth */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_SIP_AUTH_TYPE_OAUTH,</span><br><span> /*! Credentials not stored this is a fake auth */</span><br><span> AST_SIP_AUTH_TYPE_ARTIFICIAL</span><br><span> };</span><br><span>@@ -419,6 +421,12 @@</span><br><span> AST_STRING_FIELD(auth_pass);</span><br><span> /*! Authentication credentials in MD5 format (hash of user:realm:pass) */</span><br><span> AST_STRING_FIELD(md5_creds);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Refresh token to use for OAuth authentication */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(refresh_token);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Client ID to use for OAuth authentication */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(oauth_clientid);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Secret to use for OAuth authentication */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(oauth_secret);</span><br><span> );</span><br><span> /*! The time period (in seconds) that a nonce may be reused */</span><br><span> unsigned int nonce_lifetime;</span><br><span>@@ -734,6 +742,8 @@</span><br><span> AST_STRING_FIELD(transport);</span><br><span> /*! Outbound proxy to use */</span><br><span> AST_STRING_FIELD(outbound_proxy);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Outbound registration associated with this endpoint */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(outbound_registration);</span><br><span> /*! Explicit AORs to dial if none are specified */</span><br><span> AST_STRING_FIELD(aors);</span><br><span> /*! Musiconhold class to suggest that the other side use when placing on hold */</span><br><span>@@ -3186,4 +3196,13 @@</span><br><span> */</span><br><span> void ast_sip_transport_state_unregister(struct ast_sip_tpmgr_state_callback *element);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Register an override to the default selection of transports based on endpoint name</span><br><span style="color: hsl(120, 100%, 40%);">+ * \since gvsip</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param callback Callback to evoke when determining the transport when creating a new dialog</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+typedef int (*transport_from_endpoint_callback)(const struct ast_sip_endpoint *endpoint, pjsip_transport** transport);</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_set_transport_from_endpoint_override(transport_from_endpoint_callback callback);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #endif /* _RES_PJSIP_H */</span><br><span>diff --git a/res/res_pjsip.c b/res/res_pjsip.c</span><br><span>index 507267a..e0686d7 100644</span><br><span>--- a/res/res_pjsip.c</span><br><span>+++ b/res/res_pjsip.c</span><br><span>@@ -398,6 +398,9 @@</span><br><span> <configOption name="outbound_proxy"></span><br><span> <synopsis>Full SIP URI of the outbound proxy used to send requests</synopsis></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="outbound_registration"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Name of the registration config associated with this endpoint</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="rewrite_contact"></span><br><span> <synopsis>Allow Contact header to be rewritten with the source IP address-port</synopsis></span><br><span> <description><para></span><br><span>@@ -1133,11 +1136,12 @@</span><br><span> This option specifies which of the password style config options should be read</span><br><span> when trying to authenticate an endpoint inbound request. If set to <literal>userpass</literal></span><br><span> then we'll read from the 'password' option. For <literal>md5</literal> we'll read</span><br><span style="color: hsl(0, 100%, 40%);">- from 'md5_cred'.</span><br><span style="color: hsl(120, 100%, 40%);">+ from 'md5_cred'. If set to <literal>oauth</literal> then we'll read from the refresh_toke/oauth_client_id/oauth_secret fields.</span><br><span> </para></span><br><span> <enumlist></span><br><span> <enum name="md5"/></span><br><span> <enum name="userpass"/></span><br><span style="color: hsl(120, 100%, 40%);">+ <enum name="oauth"/></span><br><span> </enumlist></span><br><span> </description></span><br><span> </configOption></span><br><span>@@ -1152,6 +1156,15 @@</span><br><span> <synopsis>Plain text password used for authentication.</synopsis></span><br><span> <description><para>Only used when auth_type is <literal>userpass</literal>.</para></description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="refresh_token"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Google OAuth 2.0 refresh token</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="oauth_clientid"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Google OAuth 2.0 application's client id</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="oauth_secret"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Google OAuth 2.0 application's secret</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="realm"></span><br><span> <synopsis>SIP realm for endpoint</synopsis></span><br><span> <description><para></span><br><span>@@ -2134,6 +2147,9 @@</span><br><span> <parameter name="OutboundProxy"></span><br><span> <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='outbound_proxy']/synopsis/node())"/></para></span><br><span> </parameter></span><br><span style="color: hsl(120, 100%, 40%);">+ <parameter name="OutboundRegistration"></span><br><span style="color: hsl(120, 100%, 40%);">+ <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='outbound_registration']/synopsis/node())"/></para></span><br><span style="color: hsl(120, 100%, 40%);">+ </parameter></span><br><span> <parameter name="MohSuggest"></span><br><span> <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='endpoint']/configOption[@name='moh_suggest']/synopsis/node())"/></para></span><br><span> </parameter></span><br><span>@@ -2792,6 +2808,14 @@</span><br><span> /*! Local host address for IPv6 (string form) */</span><br><span> static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN];</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static transport_from_endpoint_callback transport_from_endpoint_override_callback;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void ast_sip_set_transport_from_endpoint_override(transport_from_endpoint_callback callback)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Transport override set!\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ transport_from_endpoint_override_callback = callback;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int register_service(void *data)</span><br><span> {</span><br><span> pjsip_module **module = data;</span><br><span>@@ -3266,6 +3290,7 @@</span><br><span> pjsip_tpselector *selector)</span><br><span> {</span><br><span> pjsip_sip_uri *uri;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_transport* transport;</span><br><span> pjsip_tpselector sel = { .type = PJSIP_TPSELECTOR_NONE, };</span><br><span> </span><br><span> uri = pjsip_uri_get_uri(dlg->target);</span><br><span>@@ -3274,6 +3299,14 @@</span><br><span> }</span><br><span> </span><br><span> ast_sip_set_tpselector_from_ep_or_uri(endpoint, uri, selector);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (transport_from_endpoint_override_callback && transport_from_endpoint_override_callback(endpoint, &transport)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Overriding endpoint transport to use %p\n", (void*)transport);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ selector->type = PJSIP_TPSELECTOR_TRANSPORT;</span><br><span style="color: hsl(120, 100%, 40%);">+ selector->u.transport = transport;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> pjsip_dlg_set_transport(dlg, selector);</span><br><span> </span><br><span> return 0;</span><br><span>diff --git a/res/res_pjsip/config_auth.c b/res/res_pjsip/config_auth.c</span><br><span>index b1bf9c4..9d87f4d 100644</span><br><span>--- a/res/res_pjsip/config_auth.c</span><br><span>+++ b/res/res_pjsip/config_auth.c</span><br><span>@@ -56,6 +56,8 @@</span><br><span> auth->type = AST_SIP_AUTH_TYPE_USER_PASS;</span><br><span> } else if (!strcasecmp(var->value, "md5")) {</span><br><span> auth->type = AST_SIP_AUTH_TYPE_MD5;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp(var->value, "oauth")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ auth->type = AST_SIP_AUTH_TYPE_OAUTH;</span><br><span> } else {</span><br><span> ast_log(LOG_WARNING, "Unknown authentication storage type '%s' specified for %s\n",</span><br><span> var->value, var->name);</span><br><span>@@ -66,7 +68,8 @@</span><br><span> </span><br><span> static const char *auth_types_map[] = {</span><br><span> [AST_SIP_AUTH_TYPE_USER_PASS] = "userpass",</span><br><span style="color: hsl(0, 100%, 40%);">- [AST_SIP_AUTH_TYPE_MD5] = "md5"</span><br><span style="color: hsl(120, 100%, 40%);">+ [AST_SIP_AUTH_TYPE_MD5] = "md5",</span><br><span style="color: hsl(120, 100%, 40%);">+ [AST_SIP_AUTH_TYPE_OAUTH] = "oauth"</span><br><span> };</span><br><span> </span><br><span> const char *ast_sip_auth_type_to_str(enum ast_sip_auth_type type)</span><br><span>@@ -106,6 +109,13 @@</span><br><span> res = -1;</span><br><span> }</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_SIP_AUTH_TYPE_OAUTH:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(auth->refresh_token) || ast_strlen_zero(auth->oauth_clientid) || ast_strlen_zero(auth->oauth_secret)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "'oauth' authentication specified but refresh_token, oauth_clientid, or "</span><br><span style="color: hsl(120, 100%, 40%);">+ "oauth_secret not specified for auth '%s'\n", ast_sorcery_object_get_id(auth));</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> case AST_SIP_AUTH_TYPE_USER_PASS:</span><br><span> case AST_SIP_AUTH_TYPE_ARTIFICIAL:</span><br><span> break;</span><br><span>@@ -365,6 +375,12 @@</span><br><span> "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_user));</span><br><span> ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "password",</span><br><span> "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, auth_pass));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "refresh_token",</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, refresh_token));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "oauth_clientid",</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, oauth_clientid));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "oauth_secret",</span><br><span style="color: hsl(120, 100%, 40%);">+ "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, oauth_secret));</span><br><span> ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "md5_cred",</span><br><span> "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_auth, md5_creds));</span><br><span> ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "realm",</span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index f4a9ecb..8e09bb5 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -1797,6 +1797,7 @@</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.rewrite_contact));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_registration", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_registration));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);</span><br><span>diff --git a/res/res_pjsip_outbound_authenticator_digest.c b/res/res_pjsip_outbound_authenticator_digest.c</span><br><span>index 063b4d3..49b3884 100644</span><br><span>--- a/res/res_pjsip_outbound_authenticator_digest.c</span><br><span>+++ b/res/res_pjsip_outbound_authenticator_digest.c</span><br><span>@@ -83,6 +83,9 @@</span><br><span> pj_cstr(&auth_creds[i].data, auths[i]->md5_creds);</span><br><span> auth_creds[i].data_type = PJSIP_CRED_DATA_DIGEST;</span><br><span> break;</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_SIP_AUTH_TYPE_OAUTH:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* nothing to do. handled seperately in res_pjsip_outbound_registration */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span> case AST_SIP_AUTH_TYPE_ARTIFICIAL:</span><br><span> ast_log(LOG_ERROR, "Trying to set artificial outbound auth credentials shouldn't happen.\n");</span><br><span> break;</span><br><span>diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c</span><br><span>index 0d815ad..40f070a 100644</span><br><span>--- a/res/res_pjsip_outbound_registration.c</span><br><span>+++ b/res/res_pjsip_outbound_registration.c</span><br><span>@@ -27,6 +27,7 @@</span><br><span> </span><br><span> #include <pjsip.h></span><br><span> #include <pjsip_ua.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <pjsip/sip_dialog.h></span><br><span> </span><br><span> #include "asterisk/res_pjsip.h"</span><br><span> #include "asterisk/res_pjsip_cli.h"</span><br><span>@@ -37,7 +38,11 @@</span><br><span> #include "asterisk/threadstorage.h"</span><br><span> #include "asterisk/threadpool.h"</span><br><span> #include "asterisk/statsd.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/pbx.h"</span><br><span> #include "res_pjsip/include/res_pjsip_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjsip_session.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/vector.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_pjproject.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span> <configInfo name="res_pjsip_outbound_registration" language="en_US"></span><br><span>@@ -76,6 +81,9 @@</span><br><span> <configOption name="contact_user"></span><br><span> <synopsis>Contact User to use in request</synopsis></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="contact_additional_params"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Additional parameters for contact</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="expiration" default="3600"></span><br><span> <synopsis>Expiration time for registrations in seconds</synopsis></span><br><span> </configOption></span><br><span>@@ -144,7 +152,11 @@</span><br><span> <literal>pjsip.conf</literal>. As with other <literal>res_pjsip</literal> modules, this will use the first available transport of the appropriate type if unconfigured.</para></note></span><br><span> </description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="transport_reuse" default="yes"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Determine if same transport can be re-used by different registrations</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="line"></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> <synopsis>Whether to add a 'line' parameter to the Contact for inbound call matching</synopsis></span><br><span> <description><para></span><br><span> When enabled this option will cause a 'line' parameter to be added to the Contact</span><br><span>@@ -171,6 +183,9 @@</span><br><span> header as necessary.</span><br><span> </para></description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="support_outbound"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Enables Outbound support for outbound REGISTER requests.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> </configObject></span><br><span> </configFile></span><br><span> </configInfo></span><br><span>@@ -224,6 +239,11 @@</span><br><span> </manager></span><br><span> ***/</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* forward declarations */</span><br><span style="color: hsl(120, 100%, 40%);">+static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_auth_vector *auth_vector);</span><br><span style="color: hsl(120, 100%, 40%);">+static int transport_from_endpoint_override(const struct ast_sip_endpoint *endpoint, pjsip_transport** transport);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Some thread local storage used to determine if the running thread invoked the callback */</span><br><span> AST_THREADSTORAGE(register_callback_invoked);</span><br><span> </span><br><span>@@ -291,6 +311,8 @@</span><br><span> AST_STRING_FIELD(client_uri);</span><br><span> /*! \brief Optional user for contact header */</span><br><span> AST_STRING_FIELD(contact_user);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \bried Optional additional parameters for contact */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(contact_additional_params);</span><br><span> /*! \brief Explicit transport to use for registration */</span><br><span> AST_STRING_FIELD(transport);</span><br><span> /*! \brief Outbound proxy to use */</span><br><span>@@ -316,8 +338,21 @@</span><br><span> struct ast_sip_auth_vector outbound_auths;</span><br><span> /*! \brief Whether Path support is enabled */</span><br><span> unsigned int support_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Whether Outbound support is enabled */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int support_outbound;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Determine if same transport can be re-used by different registrations */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int transport_reuse;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* \brief Vector type to store service routes */</span><br><span style="color: hsl(120, 100%, 40%);">+AST_VECTOR(service_route_vector_type, pj_str_t);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* \brief Caching pool to use to create pool to store saved pjsip strings */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_caching_pool cachingpool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* \brief Pool to use to store saved pjsip strings */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_pool_t *reg_pool;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Outbound registration client state information (persists for lifetime of regc) */</span><br><span> struct sip_outbound_registration_client_state {</span><br><span> /*! \brief Current state of this registration */</span><br><span>@@ -347,18 +382,28 @@</span><br><span> unsigned int auth_rejection_permanent;</span><br><span> /*! \brief Determines whether SIP Path support should be advertised */</span><br><span> unsigned int support_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Determines whether SIP Outbound support should be advertised */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int support_outbound;</span><br><span> /*! CSeq number of last sent auth request. */</span><br><span> unsigned int auth_cseq;</span><br><span> /*! \brief Serializer for stuff and things */</span><br><span> struct ast_taskprocessor *serializer;</span><br><span> /*! \brief Configured authentication credentials */</span><br><span> struct ast_sip_auth_vector outbound_auths;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief List of service-routes in register response */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct service_route_vector_type service_route_vector;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief P-Associated-URI from register response */</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_str_t associated_uri;</span><br><span> /*! \brief Registration should be destroyed after completion of transaction */</span><br><span> unsigned int destroy:1;</span><br><span> /*! \brief Non-zero if we have attempted sending a REGISTER with authentication */</span><br><span> unsigned int auth_attempted:1;</span><br><span> /*! \brief The name of the transport to be used for the registration */</span><br><span> char *transport_name;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief The transport used by the registration */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_transport *transport;</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! \brief Determine if same transport can be re-used by different registrations */</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int transport_reuse;</span><br><span> /*! \brief The name of the registration sorcery object */</span><br><span> char *registration_name;</span><br><span> };</span><br><span>@@ -520,9 +565,112 @@</span><br><span> }</span><br><span> </span><br><span> static pj_str_t PATH_NAME = { "path", 4 };</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_str_t OUTBOUND_NAME = { "outbound", 8 };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/*! \brief Helper function which sends a message and cleans up, if needed, on failure */</span><br><span style="color: hsl(0, 100%, 40%);">-static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper to send message on specified transport */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t send_on_transport(struct sip_outbound_registration_client_state *client_state, </span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_TRANSPORT, };</span><br><span style="color: hsl(120, 100%, 40%);">+ selector.u.transport = client_state->transport;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_regc_set_transport(client_state->client, &selector);</span><br><span style="color: hsl(120, 100%, 40%);">+ return pjsip_regc_send(client_state->client, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stateless_send_resolver_callback_data</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration_client_state *client_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Callback used to manually select transport when transport_reuse is off */</span><br><span style="color: hsl(120, 100%, 40%);">+static void</span><br><span style="color: hsl(120, 100%, 40%);">+stateless_send_resolver_callback( pj_status_t status, void *token, const struct pjsip_server_addresses *addr)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct stateless_send_resolver_callback_data *, data, token, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tpselector orig_selector = { .type = PJSIP_TPSELECTOR_NONE, };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration_client_state *client_state = data->client_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata = data->tdata;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Resolver failed. Cannot send message\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_set_tpselector_from_transport_name(client_state->transport_name, &orig_selector);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (orig_selector.type != PJSIP_TPSELECTOR_LISTENER)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "transport_reuse requires setting a transport\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ status = PJ_EUNKNOWN;</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Copy server addresses */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (addr && addr != &tdata->dest_info.addr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_memcpy( &tdata->dest_info.addr, addr, sizeof(pjsip_server_addresses));</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (orig_selector.u.listener->create_transport2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ orig_selector.u.listener->create_transport2(orig_selector.u.listener,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_get_pjsip_endpoint(),</span><br><span style="color: hsl(120, 100%, 40%);">+ &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr,</span><br><span style="color: hsl(120, 100%, 40%);">+ tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ tdata,</span><br><span style="color: hsl(120, 100%, 40%);">+ &client_state->transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ orig_selector.u.listener->create_transport(orig_selector.u.listener,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_get_pjsip_endpoint(),</span><br><span style="color: hsl(120, 100%, 40%);">+ &tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr,</span><br><span style="color: hsl(120, 100%, 40%);">+ tdata->dest_info.addr.entry[tdata->dest_info.cur_addr].addr_len,</span><br><span style="color: hsl(120, 100%, 40%);">+ &client_state->transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Registration using newly created transport %p\n", (void*)client_state->transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ send_on_transport(client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Send a message using a manually-built transport */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t registration_client_send_manual(struct sip_outbound_registration_client_state *client_state,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_status_t status;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_host_info dest_info;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stateless_send_resolver_callback_data* data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Due to the message going out the callback may now be invoked, so bump the count */</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(client_state, +1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If we already have a transport, just use it. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->transport && !client_state->transport->is_shutdown) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Registration re-using transport %p\n", (void*)client_state->transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ return send_on_transport(client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* If not, then create a new one. First, resolve the endpoint's host */</span><br><span style="color: hsl(120, 100%, 40%);">+ status = pjsip_process_route_set(tdata, &dest_info);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+ return status;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ data = ast_malloc(sizeof(struct stateless_send_resolver_callback_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ data->client_state = client_state;</span><br><span style="color: hsl(120, 100%, 40%);">+ data->tdata = tdata;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup(tdata->pool, &tdata->dest_info.name, &dest_info.addr.host);</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_endpt_resolve( ast_sip_get_pjsip_endpoint(), tdata->pool, &dest_info, data,</span><br><span style="color: hsl(120, 100%, 40%);">+ &stateless_send_resolver_callback);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return status;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Send a message using a transport from the normal pjsip transport factory */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t registration_client_send_normal(struct sip_outbound_registration_client_state *client_state,</span><br><span> pjsip_tx_data *tdata)</span><br><span> {</span><br><span> pj_status_t status;</span><br><span>@@ -545,6 +693,8 @@</span><br><span> */</span><br><span> ast_sip_set_tpselector_from_transport_name(client_state->transport_name, &selector);</span><br><span> pjsip_regc_set_transport(client_state->client, &selector);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Registration using factory-chosen transport\n");</span><br><span> status = pjsip_regc_send(client_state->client, tdata);</span><br><span> </span><br><span> /* If the attempt to send the message failed and the callback was not invoked we need to</span><br><span>@@ -557,12 +707,69 @@</span><br><span> return status;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper function which sends a message and cleans up, if needed, on failure */</span><br><span style="color: hsl(120, 100%, 40%);">+static pj_status_t registration_client_send(struct sip_outbound_registration_client_state *client_state,</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!client_state->transport_reuse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return registration_client_send_manual(client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ return registration_client_send_normal(client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper function to add string to Supported header */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_supported_hdr *hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* insert a new Supported header */</span><br><span style="color: hsl(120, 100%, 40%);">+ hdr = pjsip_supported_hdr_create(tdata->pool);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!hdr) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_tx_data_dec_ref(tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* add on to the existing Supported header */</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strassign(&hdr->values[hdr->count++], name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper function to add configured supported headers */</span><br><span style="color: hsl(120, 100%, 40%);">+static int add_configured_supported_headers(struct sip_outbound_registration_client_state *client_state, pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->support_path) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!add_to_supported_header(tdata, &PATH_NAME)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (client_state->support_outbound) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!add_to_supported_header(tdata, &OUTBOUND_NAME)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Callback function for registering */</span><br><span> static int handle_client_registration(void *data)</span><br><span> {</span><br><span> RAII_VAR(struct sip_outbound_registration_client_state *, client_state, data, ao2_cleanup);</span><br><span> pjsip_tx_data *tdata;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (set_outbound_initial_authentication_credentials(client_state->client, &client_state->outbound_auths)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Failed to set initial authentication credentials\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (client_state->status == SIP_REGISTRATION_STOPPED</span><br><span> || pjsip_regc_register(client_state->client, PJ_FALSE, &tdata) != PJ_SUCCESS) {</span><br><span> return 0;</span><br><span>@@ -578,23 +785,9 @@</span><br><span> (int) info.client_uri.slen, info.client_uri.ptr);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (client_state->support_path) {</span><br><span style="color: hsl(0, 100%, 40%);">- pjsip_supported_hdr *hdr;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!hdr) {</span><br><span style="color: hsl(0, 100%, 40%);">- /* insert a new Supported header */</span><br><span style="color: hsl(0, 100%, 40%);">- hdr = pjsip_supported_hdr_create(tdata->pool);</span><br><span style="color: hsl(0, 100%, 40%);">- if (!hdr) {</span><br><span style="color: hsl(0, 100%, 40%);">- pjsip_tx_data_dec_ref(tdata);</span><br><span style="color: hsl(0, 100%, 40%);">- return -1;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* add on to the existing Supported header */</span><br><span style="color: hsl(0, 100%, 40%);">- pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!add_configured_supported_headers(client_state, tdata)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Failed to set supported headers\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span> }</span><br><span> </span><br><span> registration_client_send(client_state, tdata);</span><br><span>@@ -707,6 +900,7 @@</span><br><span> update_client_state_status(client_state, SIP_REGISTRATION_STOPPING);</span><br><span> client_state->destroy = 1;</span><br><span> if (pjsip_regc_unregister(client_state->client, &tdata) == PJ_SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+ && add_configured_supported_headers(client_state, tdata)</span><br><span> && registration_client_send(client_state, tdata) == PJ_SUCCESS) {</span><br><span> ao2_ref(client_state, -1);</span><br><span> return 0;</span><br><span>@@ -885,6 +1079,32 @@</span><br><span> ao2_ref(monitor, -1);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void save_response_fields_to_client_state(struct registration_response *response)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t associated_uri_str = { "P-Associated-URI", 16 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t service_route_str = { "Service-Route", 13 };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_hdr *service_route_hdr = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg *msg = response->rdata->msg_info.msg;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_hdr *associated_uri_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_INIT(&response->client_state->service_route_vector, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ while((service_route_hdr = (pjsip_hdr*)pjsip_msg_find_hdr_by_name(msg, &service_route_str, service_route_hdr ? service_route_hdr->next : NULL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_str_t value = ((pjsip_generic_string_hdr*)service_route_hdr)->hvalue;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_str_t copy;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup_with_null(reg_pool, ©, &value);</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_VECTOR_APPEND(&response->client_state->service_route_vector, copy);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Stored service-route: %s\n", copy.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((associated_uri_hdr = (pjsip_hdr*)pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_str_t value = ((pjsip_generic_string_hdr*)associated_uri_hdr)->hvalue;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup_with_null(reg_pool, &response->client_state->associated_uri, &value);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Stored associated uri: %s\n", response->client_state->associated_uri.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Callback function for handling a response to a registration attempt */</span><br><span> static int handle_registration_response(void *data)</span><br><span> {</span><br><span>@@ -964,6 +1184,9 @@</span><br><span> registration_transport_shutdown_cb, response->client_state->registration_name,</span><br><span> monitor_matcher);</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ save_response_fields_to_client_state(response);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> } else if (response->client_state->destroy) {</span><br><span> /* We need to deal with the pending destruction instead. */</span><br><span> } else if (response->retry_after) {</span><br><span>@@ -1283,6 +1506,132 @@</span><br><span> return rc;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* \brief Get google oauth2 access token using refresh token */</span><br><span style="color: hsl(120, 100%, 40%);">+static int fetch_access_token(struct ast_sip_auth *auth)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(char *, cmd, NULL, ast_free);</span><br><span style="color: hsl(120, 100%, 40%);">+ char cBuf[4096] = "";</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *url = "https://www.googleapis.com/oauth2/v3/token";</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_json_error error;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ast_json *, jobj, NULL, ast_json_unref);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* set timeout to be shorter than default 180s (also checks func_curl is available) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_func_write(NULL, "CURLOPT(conntimeout)", "10")) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "CURL is unavailable. This is required for OAuth 2.0 authentication. Please ensure it is loaded.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_asprintf(&cmd, "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",</span><br><span style="color: hsl(120, 100%, 40%);">+ url, auth->oauth_clientid, auth->oauth_secret, auth->refresh_token);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Performing OAuth 2.0 authentication using command: %s\n", cmd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_func_read(NULL, cmd, cBuf, sizeof(cBuf) - 1)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "An error occurred while retreiving OAuth 2.0 access token\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "OAuth 2.0 authentication returned: %s\n", cBuf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ jobj = ast_json_load_string(cBuf, &error);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (jobj) {</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *token = ast_json_string_get(ast_json_object_get(jobj, "access_token"));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (token) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_string_field_set(auth, auth_pass, token);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "An error occurred while performing OAuth 2.0 authentication: %s\n", cBuf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \internal</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Set pjsip registration context with any authentication credientials that need to be</span><br><span style="color: hsl(120, 100%, 40%);">+ * sent in the initial registration request</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param regc The pjsip registration context</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param auth_vector The vector of configured authentication credientials</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_sip_auth_vector *auth_vector)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ size_t auth_size = AST_VECTOR_SIZE(auth_vector);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sip_auth **auths = ast_alloca(auth_size * sizeof(*auths));</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_cred_info *auth_creds = ast_alloca(1 * sizeof(*auth_creds));</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_auth_clt_pref prefs;</span><br><span style="color: hsl(120, 100%, 40%);">+ int res = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_sip_retrieve_auths(auth_vector, auths)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ goto cleanup;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < auth_size; ++i) {</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (auths[i]->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case AST_SIP_AUTH_TYPE_OAUTH:</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&auth_creds[0].username, auths[i]->auth_user);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&auth_creds[0].scheme, "Bearer");</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&auth_creds[0].realm, auths[i]->realm);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Obtaining OAuth access token\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (fetch_access_token(auths[i])) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "Obtaining OAuth access token failed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ res = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_debug(2, "Setting data to %s\n", auths[i]->auth_pass);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&auth_creds[0].data, auths[i]->auth_pass);</span><br><span style="color: hsl(120, 100%, 40%);">+ auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_regc_set_credentials(regc, 1, auth_creds);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* for oauth, send auth without waiting for unauthorized response */</span><br><span style="color: hsl(120, 100%, 40%);">+ prefs.initial_auth = PJ_TRUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_cstr(&prefs.algorithm, "oauth");</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_regc_set_prefs(regc, &prefs);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ /* other cases handled after receiving auth rejection */</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+cleanup:</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_cleanup_auths(auths, auth_size);</span><br><span style="color: hsl(120, 100%, 40%);">+ return res;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Helper to convert ; seperated list to pjsip_param list */</span><br><span style="color: hsl(120, 100%, 40%);">+static pjsip_param* get_params_list_from_string(const char* param_string)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_param *params;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *word;</span><br><span style="color: hsl(120, 100%, 40%);">+ char *next;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ params = PJ_POOL_ALLOC_T(reg_pool, pjsip_param);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_list_init(params);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ buf = ast_strdupa(param_string);</span><br><span style="color: hsl(120, 100%, 40%);">+ next = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ while ((word = strsep(&next, ";"))) {</span><br><span style="color: hsl(120, 100%, 40%);">+ char name[31];</span><br><span style="color: hsl(120, 100%, 40%);">+ char value[31];</span><br><span style="color: hsl(120, 100%, 40%);">+ if (sscanf(word, "%30[^=]=%30[^=]", name, value) == 2) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_param *param = PJ_POOL_ALLOC_T(reg_pool, pjsip_param);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup2_with_null(reg_pool, ¶m->name, name);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup2_with_null(reg_pool, ¶m->value, value);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_list_insert_after(params, param);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return params;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! \brief Helper function that allocates a pjsip registration client and configures it */</span><br><span> static int sip_outbound_registration_regc_alloc(void *data)</span><br><span> {</span><br><span>@@ -1382,6 +1731,15 @@</span><br><span> return -1;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_strlen_zero(registration->contact_additional_params)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_param *params = get_params_list_from_string(registration->contact_additional_params);</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_regc_update_contact(state->client_state->client, 1, &contact_uri, params);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!registration->transport_reuse) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_set_transport_from_endpoint_override(&transport_from_endpoint_override);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -1409,6 +1767,8 @@</span><br><span> state->client_state->max_retries = registration->max_retries;</span><br><span> state->client_state->retries = 0;</span><br><span> state->client_state->support_path = registration->support_path;</span><br><span style="color: hsl(120, 100%, 40%);">+ state->client_state->support_outbound = registration->support_outbound;</span><br><span style="color: hsl(120, 100%, 40%);">+ state->client_state->transport_reuse = registration->transport_reuse;</span><br><span> state->client_state->auth_rejection_permanent = registration->auth_rejection_permanent;</span><br><span> </span><br><span> pjsip_regc_update_expires(state->client_state->client, registration->expiration);</span><br><span>@@ -1550,7 +1910,8 @@</span><br><span> </span><br><span> cancel_registration(state->client_state);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS</span><br><span style="color: hsl(120, 100%, 40%);">+ && add_configured_supported_headers(state->client_state, tdata)) {</span><br><span> registration_client_send(state->client_state, tdata);</span><br><span> }</span><br><span> </span><br><span>@@ -2137,6 +2498,107 @@</span><br><span> reregister_all();</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Callback function for matching an outbound registration based on name */</span><br><span style="color: hsl(120, 100%, 40%);">+static int find_registration(void *obj, void *arg, int flags)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct sip_outbound_registration_state *state = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ const char* target_name = arg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ const char* registration_name = ast_sorcery_object_get_id(state->registration);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return !strcmp(target_name, registration_name) ? CMP_MATCH : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int transport_from_endpoint_override(const struct ast_sip_endpoint *endpoint, pjsip_transport** transport)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!endpoint || ast_strlen_zero(endpoint->outbound_registration)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Outgoing request not associated with a registration. No mangling necessary.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ states = ao2_global_obj_ref(current_states);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!states) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Cannot find outbound registration states\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ state = ao2_callback(states, 0, find_registration, (void*)endpoint->outbound_registration);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Cannot find matching outbound registration state: %s\n", endpoint->outbound_registration);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Setting transport to %p\n", (void*)state->client_state->transport);</span><br><span style="color: hsl(120, 100%, 40%);">+ *transport = state->client_state->transport;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \brief Mangle outgoing INVITEs by adding headers based on the response to the associated registration request */</span><br><span style="color: hsl(120, 100%, 40%);">+static void handle_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t route_str = { "Route", 5 };</span><br><span style="color: hsl(120, 100%, 40%);">+ static const pj_str_t pj_pai_name = { "P-Preferred-Identity", 20 };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct ao2_container *, states, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct sip_outbound_registration_state *, state, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct service_route_vector_type service_routes;</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_generic_string_hdr *pai_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!session || !session->endpoint || ast_strlen_zero(session->endpoint->outbound_registration)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Outgoing request not associated with a registration. No mangling necessary.\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ states = ao2_global_obj_ref(current_states);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!states) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Cannot find outbound registration states\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ state = ao2_callback(states, 0, find_registration, (void*)session->endpoint->outbound_registration);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!state) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Cannot find matching outbound registration state\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Found matching outbound registration state\n");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* add Route for every Service-Route in associated registration response */</span><br><span style="color: hsl(120, 100%, 40%);">+ service_routes = state->client_state->service_route_vector;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ for (i = 0; i < AST_VECTOR_SIZE(&service_routes); ++i)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_generic_string_hdr* route_hdr;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_str_t service_route_str = AST_VECTOR_GET(&service_routes, i);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_DEBUG, "Found service-route. Adding route header for %s\n", service_route_str.ptr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ route_hdr = pjsip_generic_string_hdr_create(tdata->pool, &route_str, &service_route_str);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)route_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* add ppi header for first Associated-URI in associated registration response */</span><br><span style="color: hsl(120, 100%, 40%);">+ pai_hdr = pjsip_generic_string_hdr_create(tdata->pool, &pj_pai_name, &state->client_state->associated_uri);</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)pai_hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* add outbound & path to supported header */</span><br><span style="color: hsl(120, 100%, 40%);">+ add_configured_supported_headers(state->client_state, tdata);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_sip_session_supplement gvsip_supplement = {</span><br><span style="color: hsl(120, 100%, 40%);">+ .method = "INVITE, CANCEL",</span><br><span style="color: hsl(120, 100%, 40%);">+ .outgoing_request = handle_outgoing_request,</span><br><span style="color: hsl(120, 100%, 40%);">+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static int unload_module(void)</span><br><span> {</span><br><span> int remaining;</span><br><span>@@ -2178,6 +2640,8 @@</span><br><span> </span><br><span> ast_debug(2, "Successful shutdown.\n");</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_pjproject_caching_pool_destroy(&cachingpool);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ao2_cleanup(shutdown_group);</span><br><span> shutdown_group = NULL;</span><br><span> </span><br><span>@@ -2204,6 +2668,9 @@</span><br><span> ao2_global_obj_replace_unref(current_states, new_states);</span><br><span> ao2_ref(new_states, -1);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_pjproject_caching_pool_init(&cachingpool, &pj_pool_factory_default_policy, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ reg_pool = pj_pool_create(&cachingpool.factory, "registration", 4096, 4096, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span> * Register sorcery object descriptions.</span><br><span> */</span><br><span>@@ -2219,6 +2686,7 @@</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "server_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, server_uri));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "client_uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, client_uri));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_user));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "contact_additional_params", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, contact_additional_params));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, transport));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, outbound_proxy));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "expiration", "3600", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, expiration));</span><br><span>@@ -2229,6 +2697,8 @@</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "auth_rejection_permanent", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, auth_rejection_permanent));</span><br><span> ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, outbound_auths_to_var_list, 0, 0);</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_outbound));</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "transport_reuse", "yes", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, transport_reuse));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "line", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, line));</span><br><span> ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct sip_outbound_registration, endpoint));</span><br><span> </span><br><span>@@ -2249,6 +2719,8 @@</span><br><span> /* Register how this module identifies endpoints. */</span><br><span> ast_sip_register_endpoint_identifier(&line_identifier);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sip_session_register_supplement(&gvsip_supplement);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Register CLI commands. */</span><br><span> cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);</span><br><span> if (!cli_formatter) {</span><br><span>diff --git a/third-party/pjproject/patches/0110-oauth.patch b/third-party/pjproject/patches/0110-oauth.patch</span><br><span>new file mode 100644</span><br><span>index 0000000..ac1f2d5</span><br><span>--- /dev/null</span><br><span>+++ b/third-party/pjproject/patches/0110-oauth.patch</span><br><span>@@ -0,0 +1,127 @@</span><br><span style="color: hsl(120, 100%, 40%);">+diff -x '*.o' -x '*.a' -ru a/pjsip/include/pjsip/sip_auth_msg.h b/pjsip/include/pjsip/sip_auth_msg.h</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/include/pjsip/sip_auth_msg.h 2011-05-05 01:14:19.000000000 -0500</span><br><span>++++ b/pjsip/include/pjsip/sip_auth_msg.h 2018-06-11 21:48:01.497904085 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -89,6 +89,23 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ typedef struct pjsip_pgp_credential pjsip_pgp_credential;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">++ * This structure describe credential used in Authorization and</span><br><span style="color: hsl(120, 100%, 40%);">++ * Proxy-Authorization header for oauth authentication scheme.</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++struct pjsip_oauth_credential</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_str_t realm; /**< Realm of the credential */</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_param other_param; /**< Other parameters. */</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_str_t username; /**< Username parameter. */</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_str_t token; /**< Token parameter. */</span><br><span style="color: hsl(120, 100%, 40%);">++};</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">++ * @see pjsip_oauth_credential</span><br><span style="color: hsl(120, 100%, 40%);">++ */</span><br><span style="color: hsl(120, 100%, 40%);">++typedef struct pjsip_oauth_credential pjsip_oauth_credential;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++/**</span><br><span style="color: hsl(120, 100%, 40%);">+ * This structure describes SIP Authorization header (and also SIP</span><br><span style="color: hsl(120, 100%, 40%);">+ * Proxy-Authorization header).</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -106,6 +123,8 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_common_credential common; /**< Common fields. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_digest_credential digest; /**< Digest credentials. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_pgp_credential pgp; /**< PGP credentials. */</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_oauth_credential oauth; /**< OAuth credentials. */</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ } credential;</span><br><span style="color: hsl(120, 100%, 40%);">+ };</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+diff -x '*.o' -x '*.a' -ru a/pjsip/include/pjsip/sip_auth_parser.h b/pjsip/include/pjsip/sip_auth_parser.h</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/include/pjsip/sip_auth_parser.h 2011-05-05 01:14:19.000000000 -0500</span><br><span>++++ b/pjsip/include/pjsip/sip_auth_parser.h 2018-06-11 21:37:18.105232901 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -64,6 +64,7 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_FALSE_STR, /**< "false" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_DIGEST_STR, /**< "digest" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_PGP_STR, /**< "pgp" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_BEARER_STR, /**< "bearer" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_MD5_STR, /**< "md5" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_AUTH_STR; /**< "auth" string const. */</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_client.c b/pjsip/src/pjsip/sip_auth_client.c</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsip/sip_auth_client.c 2017-03-31 01:02:48.000000000 -0500</span><br><span>++++ b/pjsip/src/pjsip/sip_auth_client.c 2018-06-11 22:26:04.728266296 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -959,13 +959,25 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ hs = pjsip_authorization_hdr_create(tdata->pool);</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_strdup(tdata->pool, &hs->scheme, &c->scheme);</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_strdup(tdata->pool, &hs->credential.digest.username,</span><br><span style="color: hsl(120, 100%, 40%);">+- &c->username);</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_strdup(tdata->pool, &hs->credential.digest.realm,</span><br><span style="color: hsl(120, 100%, 40%);">+- &c->realm);</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_strdup(tdata->pool, &hs->credential.digest.uri, &uri);</span><br><span style="color: hsl(120, 100%, 40%);">+- pj_strdup(tdata->pool, &hs->credential.digest.algorithm,</span><br><span style="color: hsl(120, 100%, 40%);">++ if (pj_stricmp(&c->scheme, &pjsip_BEARER_STR)==0)</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.oauth.username,</span><br><span style="color: hsl(120, 100%, 40%);">++ &c->username);</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.oauth.realm,</span><br><span style="color: hsl(120, 100%, 40%);">++ &c->realm);</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.oauth.token,</span><br><span style="color: hsl(120, 100%, 40%);">++ &c->data);</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ else //if (pj_stricmp(&c->scheme, &pjsip_DIGEST_STR)==0)</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.digest.username,</span><br><span style="color: hsl(120, 100%, 40%);">++ &c->username);</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.digest.realm,</span><br><span style="color: hsl(120, 100%, 40%);">++ &c->realm);</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.digest.uri, &uri);</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_strdup(tdata->pool, &hs->credential.digest.algorithm,</span><br><span style="color: hsl(120, 100%, 40%);">+ &sess->pref.algorithm);</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hs);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_msg.c b/pjsip/src/pjsip/sip_auth_msg.c</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsip/sip_auth_msg.c 2016-01-26 23:42:20.000000000 -0600</span><br><span>++++ b/pjsip/src/pjsip/sip_auth_msg.c 2018-06-11 22:31:08.414019962 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -103,6 +103,19 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++static int print_oauth_credential(pjsip_oauth_credential *cred, char *buf, pj_size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">++{</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_ssize_t printed;</span><br><span style="color: hsl(120, 100%, 40%);">++ char *startbuf = buf;</span><br><span style="color: hsl(120, 100%, 40%);">++ char *endbuf = buf + size;</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ copy_advance_pair_quote_cond_always(buf, "token=", 6, cred->token, '"', '"');</span><br><span style="color: hsl(120, 100%, 40%);">++ copy_advance_pair_quote_cond_always(buf, ", username=", 11, cred->username, '"', '"');</span><br><span style="color: hsl(120, 100%, 40%);">++ copy_advance_pair_quote_cond_always(buf, ", realm=", 8, cred->realm, '"', '"');</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">++ return (int) (buf-startbuf);</span><br><span style="color: hsl(120, 100%, 40%);">++}</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ static int pjsip_authorization_hdr_print( pjsip_authorization_hdr *hdr,</span><br><span style="color: hsl(120, 100%, 40%);">+ char *buf, pj_size_t size)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -125,6 +138,10 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ printed = print_pgp_credential(&hdr->credential.pgp, buf, endbuf - buf);</span><br><span style="color: hsl(120, 100%, 40%);">+ } </span><br><span style="color: hsl(120, 100%, 40%);">++ else if (pj_stricmp(&hdr->scheme, &pjsip_BEARER_STR) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ printed = print_oauth_credential(&hdr->credential.oauth, buf, endbuf - buf);</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">+ else {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_assert(0);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+diff -x '*.o' -x '*.a' -ru a/pjsip/src/pjsip/sip_auth_parser.c b/pjsip/src/pjsip/sip_auth_parser.c</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsip/sip_auth_parser.c 2014-06-09 21:56:56.000000000 -0500</span><br><span>++++ b/pjsip/src/pjsip/sip_auth_parser.c 2018-06-11 21:53:03.831715838 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -59,6 +59,7 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_QUOTED_DIGEST_STR = { "\"Digest\"", 8},</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_PGP_STR = { "PGP", 3 },</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_QUOTED_PGP_STR = { "\"PGP\"", 5 },</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_BEARER_STR = { "Bearer", 6 },</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_MD5_STR = { "md5", 3 },</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_QUOTED_MD5_STR = { "\"md5\"", 5},</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_AUTH_STR = { "auth", 4},</span><br><span>diff --git a/third-party/pjproject/patches/0120-contact-params.patch b/third-party/pjproject/patches/0120-contact-params.patch</span><br><span>new file mode 100644</span><br><span>index 0000000..8fcc45b</span><br><span>--- /dev/null</span><br><span>+++ b/third-party/pjproject/patches/0120-contact-params.patch</span><br><span>@@ -0,0 +1,96 @@</span><br><span style="color: hsl(120, 100%, 40%);">+diff -ru a/pjsip/include/pjsip-ua/sip_regc.h b/pjsip/include/pjsip-ua/sip_regc.h</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/include/pjsip-ua/sip_regc.h 2016-06-24 08:03:25.000000000 -0500</span><br><span>++++ b/pjsip/include/pjsip-ua/sip_regc.h 2018-07-04 13:29:26.165775909 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -413,7 +413,8 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_DECL(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,</span><br><span style="color: hsl(120, 100%, 40%);">+ int ccnt,</span><br><span style="color: hsl(120, 100%, 40%);">+- const pj_str_t contact[] );</span><br><span style="color: hsl(120, 100%, 40%);">++ const pj_str_t contact[],</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_param* params );</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /**</span><br><span style="color: hsl(120, 100%, 40%);">+ * Update the expires value. The next REGISTER request will contain</span><br><span style="color: hsl(120, 100%, 40%);">+ /* Transaction settings */</span><br><span style="color: hsl(120, 100%, 40%);">+diff -ru a/pjsip/src/pjsip-ua/sip_reg.c b/pjsip/src/pjsip-ua/sip_reg.c</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsip-ua/sip_reg.c 2016-06-30 03:23:08.000000000 -0500</span><br><span>++++ b/pjsip/src/pjsip-ua/sip_reg.c 2018-07-04 13:30:23.440884417 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -250,7 +250,8 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ static pj_status_t set_contact( pjsip_regc *regc,</span><br><span style="color: hsl(120, 100%, 40%);">+ int contact_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+- const pj_str_t contact[] )</span><br><span style="color: hsl(120, 100%, 40%);">++ const pj_str_t contact[],</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_param *params )</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ const pj_str_t CONTACT = { "Contact", 7 };</span><br><span style="color: hsl(120, 100%, 40%);">+ pjsip_contact_hdr *h;</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -321,6 +322,20 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_list_push_back(&sip_uri->other_param, xuid_param);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">++ /* Add additional contact params */</span><br><span style="color: hsl(120, 100%, 40%);">++ if (params)</span><br><span style="color: hsl(120, 100%, 40%);">++ {</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_param* param = params->next;</span><br><span style="color: hsl(120, 100%, 40%);">++ while (param != params) {</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_param *param_copy;</span><br><span style="color: hsl(120, 100%, 40%);">++ param_copy = PJ_POOL_ZALLOC_T(regc->pool, pjsip_param);</span><br><span style="color: hsl(120, 100%, 40%);">++ param_copy->name = param->name;</span><br><span style="color: hsl(120, 100%, 40%);">++ param_copy->value = param->value;</span><br><span style="color: hsl(120, 100%, 40%);">++ pj_list_push_back(&hdr->other_param, param_copy);</span><br><span style="color: hsl(120, 100%, 40%);">++ param = param->next;</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++ }</span><br><span style="color: hsl(120, 100%, 40%);">++</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_list_push_back(®c->contact_hdr_list, hdr);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+@@ -376,7 +391,7 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Set "Contact" header. */</span><br><span style="color: hsl(120, 100%, 40%);">+- status = set_contact( regc, contact_cnt, contact);</span><br><span style="color: hsl(120, 100%, 40%);">++ status = set_contact( regc, contact_cnt, contact, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (status != PJ_SUCCESS)</span><br><span style="color: hsl(120, 100%, 40%);">+ return status;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+@@ -709,14 +724,15 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_DEF(pj_status_t) pjsip_regc_update_contact( pjsip_regc *regc,</span><br><span style="color: hsl(120, 100%, 40%);">+ int contact_cnt,</span><br><span style="color: hsl(120, 100%, 40%);">+- const pj_str_t contact[] )</span><br><span style="color: hsl(120, 100%, 40%);">++ const pj_str_t contact[],</span><br><span style="color: hsl(120, 100%, 40%);">++ const pjsip_param *params )</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_status_t status;</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ PJ_ASSERT_RETURN(regc, PJ_EINVAL);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ pj_lock_acquire(regc->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+- status = set_contact( regc, contact_cnt, contact );</span><br><span style="color: hsl(120, 100%, 40%);">++ status = set_contact( regc, contact_cnt, contact, params );</span><br><span style="color: hsl(120, 100%, 40%);">+ pj_lock_release(regc->lock);</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ return status;</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1125,7 +1141,7 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Update contact address */</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_regc_update_contact(regc, param.contact_cnt, param.contact);</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_regc_update_contact(regc, param.contact_cnt, param.contact, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ update_contact = PJ_TRUE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+diff -ru a/pjsip/src/pjsua-lib/pjsua_acc.c b/pjsip/src/pjsua-lib/pjsua_acc.c</span><br><span style="color: hsl(120, 100%, 40%);">+--- a/pjsip/src/pjsua-lib/pjsua_acc.c 2017-09-15 00:32:08.000000000 -0500</span><br><span>++++ b/pjsip/src/pjsua-lib/pjsua_acc.c 2018-07-04 13:30:55.098286217 -0500</span><br><span style="color: hsl(120, 100%, 40%);">+@@ -1865,7 +1865,7 @@</span><br><span style="color: hsl(120, 100%, 40%);">+ if (contact_rewrite_method == PJSUA_CONTACT_REWRITE_NO_UNREG &&</span><br><span style="color: hsl(120, 100%, 40%);">+ acc->regc != NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+ {</span><br><span style="color: hsl(120, 100%, 40%);">+- pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact);</span><br><span style="color: hsl(120, 100%, 40%);">++ pjsip_regc_update_contact(acc->regc, 1, &acc->reg_contact, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Perform new registration */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/9505">change 9505</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/9505"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Id214c2d1c550a41fcf564b7df8f3da7be565bd58 </div>
<div style="display:none"> Gerrit-Change-Number: 9505 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Nick French <naf@ou.edu> </div>