summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_pjsip.c16
-rwxr-xr-xcontrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py32
-rw-r--r--include/asterisk/res_pjsip.h153
-rw-r--r--include/asterisk/res_pjsip_session.h27
-rw-r--r--res/res_pjsip.c234
-rw-r--r--res/res_pjsip/location.c7
-rw-r--r--res/res_pjsip/pjsip_distributor.c2
-rw-r--r--res/res_pjsip/pjsip_options.c74
-rw-r--r--res/res_pjsip_caller_id.c2
-rw-r--r--res/res_pjsip_diversion.c2
-rw-r--r--res/res_pjsip_header_funcs.c2
-rw-r--r--res/res_pjsip_messaging.c10
-rw-r--r--res/res_pjsip_mwi.c4
-rw-r--r--res/res_pjsip_nat.c2
-rw-r--r--res/res_pjsip_notify.c4
-rw-r--r--res/res_pjsip_outbound_registration.c34
-rw-r--r--res/res_pjsip_path.c250
-rw-r--r--res/res_pjsip_refer.c2
-rw-r--r--res/res_pjsip_registrar.c113
-rw-r--r--res/res_pjsip_session.c33
-rw-r--r--res/res_pjsip_t38.c2
21 files changed, 869 insertions, 136 deletions
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index bab4be581..4a1a6aa2f 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -129,7 +129,7 @@ static void chan_pjsip_incoming_response(struct ast_sip_session *session, struct
/*! \brief SIP session supplement structure */
static struct ast_sip_session_supplement chan_pjsip_supplement = {
.method = "INVITE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
.session_begin = chan_pjsip_session_begin,
.session_end = chan_pjsip_session_end,
.incoming_request = chan_pjsip_incoming_request,
@@ -140,7 +140,7 @@ static int chan_pjsip_incoming_ack(struct ast_sip_session *session, struct pjsip
static struct ast_sip_session_supplement chan_pjsip_ack_supplement = {
.method = "ACK",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL,
.incoming_request = chan_pjsip_incoming_ack,
};
@@ -863,7 +863,7 @@ static int transmit_info_with_vidupdate(void *data)
RAII_VAR(struct ast_sip_session *, session, data, ao2_cleanup);
struct pjsip_tx_data *tdata;
- if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
+ if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
ast_log(LOG_ERROR, "Could not create text video update INFO request\n");
return -1;
}
@@ -1261,7 +1261,7 @@ static int transmit_info_dtmf(void *data)
body.body_text = ast_str_buffer(body_text);
- if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, &tdata)) {
+ if (ast_sip_create_request("INFO", session->inv_session->dlg, session->endpoint, NULL, NULL, &tdata)) {
ast_log(LOG_ERROR, "Could not create DTMF INFO request\n");
return -1;
}
@@ -1539,7 +1539,7 @@ static int request(void *obj)
return -1;
}
- if (!(session = ast_sip_session_create_outgoing(endpoint, args.aor, request_user, req_data->caps))) {
+ if (!(session = ast_sip_session_create_outgoing(endpoint, NULL, args.aor, request_user, req_data->caps))) {
req_data->cause = AST_CAUSE_NO_ROUTE_DESTINATION;
return -1;
}
@@ -1618,9 +1618,9 @@ static int sendtext(void *obj)
ast_debug(3, "Sending in dialog SIP message\n");
- ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, &tdata);
+ ast_sip_create_request("MESSAGE", data->session->inv_session->dlg, data->session->endpoint, NULL, NULL, &tdata);
ast_sip_add_body(tdata, &body);
- ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint);
+ ast_sip_send_request(tdata, data->session->inv_session->dlg, data->session->endpoint, NULL, NULL);
return 0;
}
@@ -1831,7 +1831,7 @@ static int pbx_start_incoming_request(struct ast_sip_session *session, pjsip_rx_
static struct ast_sip_session_supplement pbx_start_supplement = {
.method = "INVITE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_LAST,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_LAST,
.incoming_request = pbx_start_incoming_request,
};
diff --git a/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
new file mode 100755
index 000000000..979aea8f9
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/2fc7930b41b3_add_pjsip_endpoint_options_for_12_1.py
@@ -0,0 +1,32 @@
+"""Add pjsip endpoint options for 12.1
+
+Revision ID: 2fc7930b41b3
+Revises: 581a4264e537
+Create Date: 2014-01-14 09:23:53.923454
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '2fc7930b41b3'
+down_revision = '581a4264e537'
+
+from alembic import op
+import sqlalchemy as sa
+
+YESNO_VALUES = ['yes', 'no']
+REDIRECT_METHODS = ['user', 'uri_core', 'uri_pjsip']
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('redirect_method', sa.Enum(*REDIRECT_METHODS, name='redirect_methods')))
+ op.add_column('ps_endpoints', sa.Column('set_var', sa.Text()))
+ op.add_column('ps_contacts', sa.Column('path', sa.Text()))
+ op.add_column('ps_aors', sa.Column('support_path', sa.Enum(*YESNO_VALUES, name='yesno_values')))
+ op.add_column('ps_registrations', sa.Column('support_path', sa.Enum(*YESNO_VALUES, name='yesno_values')))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'redirect_method')
+ op.drop_column('ps_endpoints', 'set_var')
+ op.drop_column('ps_contacts', 'path')
+ op.drop_column('ps_aors', 'support_path')
+ op.drop_column('ps_registrations', 'support_path')
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 04a24cde3..1fea42f2b 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -151,6 +151,8 @@ struct ast_sip_contact {
AST_STRING_FIELD(uri);
/*! Outbound proxy to use for qualify */
AST_STRING_FIELD(outbound_proxy);
+ /*! Path information to place in Route headers */
+ AST_STRING_FIELD(path);
);
/*! Absolute time that this contact is no longer valid after */
struct timeval expiration_time;
@@ -214,6 +216,8 @@ struct ast_sip_aor {
unsigned int remove_existing;
/*! Any permanent configured contacts */
struct ao2_container *permanent_contacts;
+ /*! Determines whether SIP Path headers are supported */
+ unsigned int support_path;
};
/*!
@@ -901,11 +905,13 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
* \param aor Pointer to the AOR
* \param uri Full contact URI
* \param expiration_time Optional expiration time of the contact
+ * \param path_info Path information
*
* \retval -1 failure
* \retval 0 success
*/
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time);
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
+ struct timeval expiration_time, const char *path_info);
/*!
* \brief Update a contact
@@ -1209,18 +1215,22 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint,
*
* \param method The method of the SIP request to send
* \param dlg Optional. If specified, the dialog on which to request the message.
- * \param endpoint Optional. If specified, the request will be created out-of-dialog
- * to the endpoint.
+ * \param endpoint Optional. If specified, the request will be created out-of-dialog to the endpoint.
* \param uri Optional. If specified, the request will be sent to this URI rather
- * this value.
* than one configured for the endpoint.
+ * \param contact The contact with which this request is associated for out-of-dialog requests.
* \param[out] tdata The newly-created request
+ *
+ * The provided contact is attached to tdata with its reference bumped, but will
+ * not survive for the entire lifetime of tdata since the contact is cleaned up
+ * when all supplements have completed execution.
+ *
* \retval 0 Success
* \retval -1 Failure
*/
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
struct ast_sip_endpoint *endpoint, const char *uri,
- pjsip_tx_data **tdata);
+ struct ast_sip_contact *contact, pjsip_tx_data **tdata);
/*!
* \brief General purpose method for sending a SIP request
@@ -1235,10 +1245,48 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
* \param tdata The request to send
* \param dlg Optional. If specified, the dialog on which the request should be sent
* \param endpoint Optional. If specified, the request is sent out-of-dialog to the endpoint.
+ * \param token Data to be passed to the callback upon receipt of response
+ * \param callback Callback to be called upon receipt of response
+ *
* \retval 0 Success
* \retval -1 Failure
*/
-int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint);
+int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
+ struct ast_sip_endpoint *endpoint, void *token,
+ void (*callback)(void *token, pjsip_event *e));
+
+/*!
+ * \brief General purpose method for creating a SIP response
+ *
+ * Its typical use would be to create responses for out of dialog
+ * requests.
+ *
+ * \param rdata The rdata from the incoming request.
+ * \param st_code The response code to transmit.
+ * \param contact The contact with which this request is associated.
+ * \param[out] tdata The newly-created response
+ *
+ * The provided contact is attached to tdata with its reference bumped, but will
+ * not survive for the entire lifetime of tdata since the contact is cleaned up
+ * when all supplements have completed execution.
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
+ struct ast_sip_contact *contact, pjsip_tx_data **p_tdata);
+
+/*!
+ * \brief Send a response to an out of dialog request
+ *
+ * \param res_addr The response address for this response
+ * \param tdata The response to send
+ * \param endpoint The ast_sip_endpoint associated with this response
+ *
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint);
/*!
* \brief Determine if an incoming request requires authentication
@@ -1745,4 +1793,97 @@ int ast_sip_for_each_channel(const struct ast_sip_endpoint *endpoint,
ao2_callback_fn on_channel_snapshot,
void *arg);
+enum ast_sip_supplement_priority {
+ /*! Top priority. Supplements with this priority are those that need to run before any others */
+ AST_SIP_SUPPLEMENT_PRIORITY_FIRST = 0,
+ /*! Channel creation priority.
+ * chan_pjsip creates a channel at this priority. If your supplement depends on being run before
+ * or after channel creation, then set your priority to be lower or higher than this value.
+ */
+ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL = 1000000,
+ /*! Lowest priority. Supplements with this priority should be run after all other supplements */
+ AST_SIP_SUPPLEMENT_PRIORITY_LAST = INT_MAX,
+};
+
+/*!
+ * \brief A supplement to SIP message processing
+ *
+ * These can be registered by any module in order to add
+ * processing to incoming and outgoing SIP out of dialog
+ * requests and responses
+ */
+struct ast_sip_supplement {
+ /*! Method on which to call the callbacks. If NULL, call on all methods */
+ const char *method;
+ /*! Priority for this supplement. Lower numbers are visited before higher numbers */
+ enum ast_sip_supplement_priority priority;
+ /*!
+ * \brief Called on incoming SIP request
+ * This method can indicate a failure in processing in its return. If there
+ * is a failure, it is required that this method sends a response to the request.
+ * This method is always called from a SIP servant thread.
+ *
+ * \note
+ * The following PJSIP methods will not work properly:
+ * pjsip_rdata_get_dlg()
+ * pjsip_rdata_get_tsx()
+ * The reason is that the rdata passed into this function is a cloned rdata structure,
+ * and its module data is not copied during the cloning operation.
+ * If you need to get the dialog, you can get it via session->inv_session->dlg.
+ *
+ * \note
+ * There is no guarantee that a channel will be present on the session when this is called.
+ */
+ int (*incoming_request)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
+ /*!
+ * \brief Called on an incoming SIP response
+ * This method is always called from a SIP servant thread.
+ *
+ * \note
+ * The following PJSIP methods will not work properly:
+ * pjsip_rdata_get_dlg()
+ * pjsip_rdata_get_tsx()
+ * The reason is that the rdata passed into this function is a cloned rdata structure,
+ * and its module data is not copied during the cloning operation.
+ * If you need to get the dialog, you can get it via session->inv_session->dlg.
+ *
+ * \note
+ * There is no guarantee that a channel will be present on the session when this is called.
+ */
+ void (*incoming_response)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata);
+ /*!
+ * \brief Called on an outgoing SIP request
+ * This method is always called from a SIP servant thread.
+ */
+ void (*outgoing_request)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata);
+ /*!
+ * \brief Called on an outgoing SIP response
+ * This method is always called from a SIP servant thread.
+ */
+ void (*outgoing_response)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata);
+ /*! Next item in the list */
+ AST_LIST_ENTRY(ast_sip_supplement) next;
+};
+
+/*!
+ * \brief Register a supplement to SIP out of dialog processing
+ *
+ * This allows for someone to insert themselves in the processing of out
+ * of dialog SIP requests and responses. This, for example could allow for
+ * a module to set channel data based on headers in an incoming message.
+ * Similarly, a module could reject an incoming request if desired.
+ *
+ * \param supplement The supplement to register
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_register_supplement(struct ast_sip_supplement *supplement);
+
+/*!
+ * \brief Unregister a an supplement to SIP out of dialog processing
+ *
+ * \param supplement The supplement to unregister
+ */
+void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement);
+
#endif /* _RES_PJSIP_H */
diff --git a/include/asterisk/res_pjsip_session.h b/include/asterisk/res_pjsip_session.h
index 615a6214c..0d79c6b3a 100644
--- a/include/asterisk/res_pjsip_session.h
+++ b/include/asterisk/res_pjsip_session.h
@@ -98,6 +98,8 @@ struct ast_sip_session {
char exten[AST_MAX_EXTENSION];
/* The endpoint with which Asterisk is communicating */
struct ast_sip_endpoint *endpoint;
+ /* The contact associated with this session */
+ struct ast_sip_contact *contact;
/* The PJSIP details of the session, which includes the dialog */
struct pjsip_inv_session *inv_session;
/* The Asterisk channel associated with the session */
@@ -138,18 +140,6 @@ typedef int (*ast_sip_session_request_creation_cb)(struct ast_sip_session *sessi
typedef int (*ast_sip_session_response_cb)(struct ast_sip_session *session, pjsip_rx_data *rdata);
typedef int (*ast_sip_session_sdp_creation_cb)(struct ast_sip_session *session, pjmedia_sdp_session *sdp);
-enum ast_sip_session_supplement_priority {
- /*! Top priority. Supplements with this priority are those that need to run before any others */
- AST_SIP_SESSION_SUPPLEMENT_PRIORITY_FIRST = 0,
- /*! Channel creation priority.
- * chan_pjsip creates a channel at this priority. If your supplement depends on being run before
- * or after channel creation, then set your priority to be lower or higher than this value.
- */
- AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL = 1000000,
- /*! Lowest priority. Supplements with this priority should be run after all other supplements */
- AST_SIP_SESSION_SUPPLEMENT_PRIORITY_LAST = INT_MAX,
-};
-
/*!
* \brief A supplement to SIP message processing
*
@@ -160,7 +150,7 @@ struct ast_sip_session_supplement {
/*! Method on which to call the callbacks. If NULL, call on all methods */
const char *method;
/*! Priority for this supplement. Lower numbers are visited before higher numbers */
- enum ast_sip_session_supplement_priority priority;
+ enum ast_sip_supplement_priority priority;
/*!
* \brief Notification that the session has begun
* This method will always be called from a SIP servant thread.
@@ -342,9 +332,11 @@ struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_
* this reference when the session is destroyed.
*
* \param endpoint The endpoint that this session communicates with
+ * \param contact The contact associated with this session
* \param inv_session The PJSIP INVITE session data
*/
-struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, pjsip_inv_session *inv);
+struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
+ struct ast_sip_contact *contact, pjsip_inv_session *inv);
/*!
* \brief Create a new outgoing SIP session
@@ -354,11 +346,14 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
* this reference when the session is destroyed.
*
* \param endpoint The endpoint that this session uses for settings
- * \param location Optional name of the location to call, be it named location or explicit URI
+ * \param contact The contact that this session will communicate with
+ * \param location Name of the location to call, be it named location or explicit URI. Overrides contact if present.
* \param request_user Optional request user to place in the request URI if permitted
* \param req_caps The requested capabilities
*/
-struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user, struct ast_format_cap *req_caps);
+struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint,
+ struct ast_sip_contact *contact, const char *location, const char *request_user,
+ struct ast_format_cap *req_caps);
/*!
* \brief Defer local termination of a session until remote side terminates, or an amount of time passes
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index e6f00a8e9..bd8418152 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -883,6 +883,9 @@
OPTIONS request is sent to a contact for qualify purposes.
</para></description>
</configOption>
+ <configOption name="path">
+ <synopsis>Stored Path vector for use in Route headers on outgoing requests.</synopsis>
+ </configOption>
</configObject>
<configObject name="aor">
<synopsis>The configuration for a location of an endpoint</synopsis>
@@ -986,6 +989,15 @@
OPTIONS request is sent to a contact for qualify purposes.
</para></description>
</configOption>
+ <configOption name="support_path">
+ <synopsis>Enables Path support for REGISTER requests and Route support for other requests.</synopsis>
+ <description><para>
+ When this option is enabled, the Path headers in register requests will be saved
+ and its contents will be used in Route headers for outbound out-of-dialog requests
+ and in Path headers for outbound 200 responses. Path support will also be indicated
+ in the Supported header.
+ </para></description>
+ </configOption>
</configObject>
<configObject name="system">
<synopsis>Options that apply to the SIP stack as well as other system-wide settings</synopsis>
@@ -1105,6 +1117,7 @@
</manager>
***/
+#define MOD_DATA_CONTACT "contact"
static pjsip_endpoint *ast_pjsip_endpoint;
@@ -1598,10 +1611,18 @@ static int create_in_dialog_request(const pjsip_method *method, struct pjsip_dia
return 0;
}
+static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata);
+static pjsip_module supplement_module = {
+ .name = { "Out of dialog supplement hook", 29 },
+ .id = -1,
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION - 1,
+ .on_rx_request = supplement_on_rx_request,
+};
+
static int create_out_of_dialog_request(const pjsip_method *method, struct ast_sip_endpoint *endpoint,
- const char *uri, pjsip_tx_data **tdata)
+ const char *uri, struct ast_sip_contact *provided_contact, pjsip_tx_data **tdata)
{
- RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_sip_contact *, contact, ao2_bump(provided_contact), ao2_cleanup);
pj_str_t remote_uri;
pj_str_t from;
pj_pool_t *pool;
@@ -1613,7 +1634,9 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
return -1;
}
- contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+ if (!contact) {
+ contact = ast_sip_location_retrieve_contact_from_aor_list(endpoint->aors);
+ }
if (!contact || ast_strlen_zero(contact->uri)) {
ast_log(LOG_ERROR, "Unable to retrieve contact for endpoint %s\n",
ast_sorcery_object_get_id(endpoint));
@@ -1665,6 +1688,8 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
return -1;
}
+ ast_sip_mod_data_set((*tdata)->pool, (*tdata)->mod_data, supplement_module.id, MOD_DATA_CONTACT, ao2_bump(contact));
+
/* We can release this pool since request creation copied all the necessary
* data into the outbound request's pool
*/
@@ -1674,7 +1699,7 @@ static int create_out_of_dialog_request(const pjsip_method *method, struct ast_s
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
struct ast_sip_endpoint *endpoint, const char *uri,
- pjsip_tx_data **tdata)
+ struct ast_sip_contact *contact, pjsip_tx_data **tdata)
{
const pjsip_method *pmethod = get_pjsip_method(method);
@@ -1686,8 +1711,46 @@ int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg,
if (dlg) {
return create_in_dialog_request(pmethod, dlg, tdata);
} else {
- return create_out_of_dialog_request(pmethod, endpoint, uri, tdata);
+ return create_out_of_dialog_request(pmethod, endpoint, uri, contact, tdata);
+ }
+}
+
+AST_RWLIST_HEAD_STATIC(supplements, ast_sip_supplement);
+
+int ast_sip_register_supplement(struct ast_sip_supplement *supplement)
+{
+ struct ast_sip_supplement *iter;
+ int inserted = 0;
+ SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) {
+ if (iter->priority > supplement->priority) {
+ AST_RWLIST_INSERT_BEFORE_CURRENT(supplement, next);
+ inserted = 1;
+ break;
+ }
+ }
+ AST_RWLIST_TRAVERSE_SAFE_END;
+
+ if (!inserted) {
+ AST_RWLIST_INSERT_TAIL(&supplements, supplement, next);
+ }
+ ast_module_ref(ast_module_info->self);
+ return 0;
+}
+
+void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
+{
+ struct ast_sip_supplement *iter;
+ SCOPED_LOCK(lock, &supplements, AST_RWLIST_WRLOCK, AST_RWLIST_UNLOCK);
+ AST_RWLIST_TRAVERSE_SAFE_BEGIN(&supplements, iter, next) {
+ if (supplement == iter) {
+ AST_RWLIST_REMOVE_CURRENT(next);
+ ast_module_unref(ast_module_info->self);
+ break;
+ }
}
+ AST_RWLIST_TRAVERSE_SAFE_END;
}
static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg)
@@ -1699,45 +1762,120 @@ static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg
return 0;
}
+static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
+{
+ pj_str_t method;
+
+ if (ast_strlen_zero(supplement_method)) {
+ return PJ_TRUE;
+ }
+
+ pj_cstr(&method, supplement_method);
+
+ return pj_stristr(&method, message_method) ? PJ_TRUE : PJ_FALSE;
+}
+
+/*! \brief Structure to hold information about an outbound request */
+struct send_request_data {
+ struct ast_sip_endpoint *endpoint; /*! The endpoint associated with this request */
+ void *token; /*! Information to be provided to the callback upon receipt of a response */
+ void (*callback)(void *token, pjsip_event *e); /*! The callback to be called upon receipt of a response */
+};
+
+static void send_request_data_destroy(void *obj)
+{
+ struct send_request_data *req_data = obj;
+ ao2_cleanup(req_data->endpoint);
+}
+
+static struct send_request_data *send_request_data_alloc(struct ast_sip_endpoint *endpoint,
+ void *token, void (*callback)(void *token, pjsip_event *e))
+{
+ struct send_request_data *req_data = ao2_alloc(sizeof(*req_data), send_request_data_destroy);
+
+ if (!req_data) {
+ return NULL;
+ }
+
+ req_data->endpoint = ao2_bump(endpoint);
+ req_data->token = token;
+ req_data->callback = callback;
+
+ return req_data;
+}
+
static void send_request_cb(void *token, pjsip_event *e)
{
- RAII_VAR(struct ast_sip_endpoint *, endpoint, token, ao2_cleanup);
+ RAII_VAR(struct send_request_data *, req_data, token, ao2_cleanup);
pjsip_transaction *tsx = e->body.tsx_state.tsx;
pjsip_rx_data *challenge = e->body.tsx_state.src.rdata;
pjsip_tx_data *tdata;
+ struct ast_sip_supplement *supplement;
+
+ AST_RWLIST_RDLOCK(&supplements);
+ AST_LIST_TRAVERSE(&supplements, supplement, next) {
+ if (supplement->incoming_response && does_method_match(&challenge->msg_info.cseq->method.name, supplement->method)) {
+ supplement->incoming_response(req_data->endpoint, challenge);
+ }
+ }
+ AST_RWLIST_UNLOCK(&supplements);
- if (tsx->status_code != 401 && tsx->status_code != 407) {
+ if (tsx->status_code == 401 || tsx->status_code == 407) {
+ if (!ast_sip_create_request_with_auth(&req_data->endpoint->outbound_auths, challenge, tsx, &tdata)) {
+ pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, req_data->token, req_data->callback);
+ }
return;
}
- if (!ast_sip_create_request_with_auth(&endpoint->outbound_auths, challenge, tsx, &tdata)) {
- pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, NULL, NULL);
+ if (req_data->callback) {
+ req_data->callback(req_data->token, e);
}
}
-static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint)
+static int send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint,
+ void *token, void (*callback)(void *token, pjsip_event *e))
{
- ao2_ref(endpoint, +1);
- if (pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, endpoint, send_request_cb) != PJ_SUCCESS) {
+ struct ast_sip_supplement *supplement;
+ struct send_request_data *req_data = send_request_data_alloc(endpoint, token, callback);
+ struct ast_sip_contact *contact = ast_sip_mod_data_get(tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT);
+
+ if (!req_data) {
+ return -1;
+ }
+
+ AST_RWLIST_RDLOCK(&supplements);
+ AST_LIST_TRAVERSE(&supplements, supplement, next) {
+ if (supplement->outgoing_request && does_method_match(&tdata->msg->line.req.method.name, supplement->method)) {
+ supplement->outgoing_request(endpoint, contact, tdata);
+ }
+ }
+ AST_RWLIST_UNLOCK(&supplements);
+
+ ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
+ ao2_cleanup(contact);
+
+ if (pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata, -1, req_data, send_request_cb) != PJ_SUCCESS) {
ast_log(LOG_ERROR, "Error attempting to send outbound %.*s request to endpoint %s\n",
(int) pj_strlen(&tdata->msg->line.req.method.name),
pj_strbuf(&tdata->msg->line.req.method.name),
ast_sorcery_object_get_id(endpoint));
- ao2_ref(endpoint, -1);
+ ao2_cleanup(req_data);
return -1;
}
return 0;
}
-int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
+int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg,
+ struct ast_sip_endpoint *endpoint, void *token,
+ void (*callback)(void *token, pjsip_event *e))
{
ast_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
if (dlg) {
return send_in_dialog_request(tdata, dlg);
} else {
- return send_out_of_dialog_request(tdata, endpoint);
+ return send_out_of_dialog_request(tdata, endpoint, token, callback);
}
}
@@ -2011,6 +2149,57 @@ void *ast_sip_dict_set(pj_pool_t* pool, void *ht,
return ht;
}
+static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata)
+{
+ struct ast_sip_supplement *supplement;
+
+ if (pjsip_rdata_get_dlg(rdata)) {
+ return PJ_FALSE;
+ }
+
+ AST_RWLIST_RDLOCK(&supplements);
+ AST_LIST_TRAVERSE(&supplements, supplement, next) {
+ if (supplement->incoming_request && does_method_match(&rdata->msg_info.msg->line.req.method.name, supplement->method)) {
+ supplement->incoming_request(ast_pjsip_rdata_get_endpoint(rdata), rdata);
+ }
+ }
+ AST_RWLIST_UNLOCK(&supplements);
+
+ return PJ_FALSE;
+}
+
+int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
+{
+ struct ast_sip_supplement *supplement;
+ pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
+ struct ast_sip_contact *contact = ast_sip_mod_data_get(tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT);
+
+ AST_RWLIST_RDLOCK(&supplements);
+ AST_LIST_TRAVERSE(&supplements, supplement, next) {
+ if (supplement->outgoing_response && does_method_match(&cseq->method.name, supplement->method)) {
+ supplement->outgoing_response(sip_endpoint, contact, tdata);
+ }
+ }
+ AST_RWLIST_UNLOCK(&supplements);
+
+ ast_sip_mod_data_set(tdata->pool, tdata->mod_data, supplement_module.id, MOD_DATA_CONTACT, NULL);
+ ao2_cleanup(contact);
+
+ return pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), res_addr, tdata, NULL, NULL);
+}
+
+int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code,
+ struct ast_sip_contact *contact, pjsip_tx_data **tdata)
+{
+ int res = pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, st_code, NULL, tdata);
+
+ if (!res) {
+ ast_sip_mod_data_set((*tdata)->pool, (*tdata)->mod_data, supplement_module.id, MOD_DATA_CONTACT, ao2_bump(contact));
+ }
+
+ return res;
+}
+
static void remove_request_headers(pjsip_endpoint *endpt)
{
const pjsip_hdr *request_headers = pjsip_endpt_get_request_headers(endpt);
@@ -2128,8 +2317,23 @@ static int load_module(void)
return AST_MODULE_LOAD_DECLINE;
}
+ if (ast_sip_register_service(&supplement_module)) {
+ ast_log(LOG_ERROR, "Failed to initialize supplement hooks. Aborting load\n");
+ ast_sip_destroy_distributor();
+ ast_res_pjsip_destroy_configuration();
+ ast_sip_destroy_global_headers();
+ stop_monitor_thread();
+ pj_pool_release(memory_pool);
+ memory_pool = NULL;
+ pjsip_endpt_destroy(ast_pjsip_endpoint);
+ ast_pjsip_endpoint = NULL;
+ pj_caching_pool_destroy(&caching_pool);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
if (ast_sip_initialize_outbound_authentication()) {
ast_log(LOG_ERROR, "Failed to initialize outbound authentication. Aborting load\n");
+ ast_sip_unregister_service(&supplement_module);
ast_sip_destroy_distributor();
ast_res_pjsip_destroy_configuration();
ast_sip_destroy_global_headers();
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 31eaeeee4..499ee9a6c 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -178,7 +178,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
}
-int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time)
+int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info)
{
char name[AST_UUID_STR_LEN];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
@@ -193,6 +193,9 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struc
contact->expiration_time = expiration_time;
contact->qualify_frequency = aor->qualify_frequency;
contact->authenticate_qualify = aor->authenticate_qualify;
+ if (path_info && aor->support_path) {
+ ast_string_field_set(contact, path, path_info);
+ }
if (!ast_strlen_zero(aor->outbound_proxy)) {
ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
@@ -610,6 +613,7 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
+ ast_sorcery_object_field_register(sorcery, "contact", "path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, path));
ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, 0, 0);
ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
@@ -626,6 +630,7 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
+ ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
ast_sip_register_cli_formatter(&cli_contact_formatter);
diff --git a/res/res_pjsip/pjsip_distributor.c b/res/res_pjsip/pjsip_distributor.c
index 5cc645cc3..69cbed784 100644
--- a/res/res_pjsip/pjsip_distributor.c
+++ b/res/res_pjsip/pjsip_distributor.c
@@ -326,7 +326,7 @@ static pj_bool_t authenticate(pjsip_rx_data *rdata)
static pjsip_module auth_mod = {
.name = {"Request Authenticator", 21},
- .priority = PJSIP_MOD_PRIORITY_APPLICATION - 1,
+ .priority = PJSIP_MOD_PRIORITY_APPLICATION - 2,
.on_rx_request = authenticate,
};
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index 0409c1557..2f7998d3b 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -34,7 +34,7 @@
#define DEFAULT_ENCODING "text/plain"
#define QUALIFIED_BUCKETS 211
-static int qualify_contact(struct ast_sip_contact *contact);
+static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact);
/*!
* \internal
@@ -186,7 +186,7 @@ static int on_endpoint(void *obj, void *arg, int flags)
* \internal
* \brief Find endpoints associated with the given contact.
*/
-static struct ao2_container *find_endpoints(struct ast_sip_contact *contact)
+static struct ao2_iterator *find_endpoints(struct ast_sip_contact *contact)
{
RAII_VAR(struct ao2_container *, endpoints,
ast_sip_get_endpoints(), ao2_cleanup);
@@ -201,43 +201,15 @@ static struct ao2_container *find_endpoints(struct ast_sip_contact *contact)
static void qualify_contact_cb(void *token, pjsip_event *e)
{
RAII_VAR(struct ast_sip_contact *, contact, token, ao2_cleanup);
- RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
- RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-
- pjsip_transaction *tsx = e->body.tsx_state.tsx;
- pjsip_rx_data *challenge = e->body.tsx_state.src.rdata;
- pjsip_tx_data *tdata;
switch(e->body.tsx_state.type) {
case PJSIP_EVENT_TRANSPORT_ERROR:
case PJSIP_EVENT_TIMER:
update_contact_status(contact, UNAVAILABLE);
- return;
- default:
break;
- }
-
- if (!contact->authenticate_qualify || (tsx->status_code != 401 &&
- tsx->status_code != 407)) {
+ default:
update_contact_status(contact, AVAILABLE);
- return;
- }
-
- /* try to find endpoints that are associated with the contact */
- if (!(endpoints = find_endpoints(contact))) {
- ast_log(LOG_ERROR, "No endpoints found for contact %s, cannot authenticate",
- contact->uri);
- return;
- }
-
- /* find "first" endpoint in order to authenticate - actually any
- endpoint should do that matched on the contact */
- endpoint = ao2_callback(endpoints, 0, NULL, NULL);
-
- if (!ast_sip_create_request_with_auth(&endpoint->outbound_auths,
- challenge, tsx, &tdata)) {
- pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(), tdata,
- -1, NULL, NULL);
+ break;
}
}
@@ -248,11 +220,25 @@ static void qualify_contact_cb(void *token, pjsip_event *e)
* \detail Sends a SIP OPTIONS request to the given contact in order to make
* sure that contact is available.
*/
-static int qualify_contact(struct ast_sip_contact *contact)
+static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact)
{
pjsip_tx_data *tdata;
+ RAII_VAR(struct ast_sip_endpoint *, endpoint_local, ao2_bump(endpoint), ao2_cleanup);
+
+
+ if (!endpoint_local) {
+ struct ao2_iterator *endpoint_iterator = find_endpoints(contact);
+
+ /* try to find endpoints that are associated with the contact */
+ if (endpoint_iterator) {
+ /* find "first" endpoint in order to authenticate - actually any
+ endpoint should do that matched on the contact */
+ endpoint_local = ao2_iterator_next(endpoint_iterator);
+ ao2_iterator_destroy(endpoint_iterator);
+ }
+ }
- if (ast_sip_create_request("OPTIONS", NULL, NULL, contact->uri, &tdata)) {
+ if (ast_sip_create_request("OPTIONS", NULL, NULL, NULL, contact, &tdata)) {
ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n",
contact->uri);
return -1;
@@ -270,8 +256,8 @@ static int qualify_contact(struct ast_sip_contact *contact)
init_start_time(contact);
ao2_ref(contact, +1);
- if (pjsip_endpt_send_request(ast_sip_get_pjsip_endpoint(),
- tdata, -1, contact, qualify_contact_cb) != PJ_SUCCESS) {
+ if (ast_sip_send_request(tdata, NULL, endpoint_local, contact,
+ qualify_contact_cb) != PJ_SUCCESS) {
/* The callback will be called so we don't need to drop the contact ref*/
ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
contact->uri);
@@ -339,7 +325,7 @@ static struct sched_data *sched_data_create(struct ast_sip_contact *contact)
static int qualify_contact_task(void *obj)
{
RAII_VAR(struct ast_sip_contact *, contact, obj, ao2_cleanup);
- return qualify_contact(contact);
+ return qualify_contact(NULL, contact);
}
/*!
@@ -489,8 +475,7 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
pj_status_t status;
/* Make the response object */
- if ((status = pjsip_endpt_create_response(
- endpt, rdata, code, NULL, &tdata) != PJ_SUCCESS)) {
+ if ((status = ast_sip_create_response(rdata, code, NULL, &tdata) != PJ_SUCCESS)) {
ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
return status;
}
@@ -527,8 +512,8 @@ static pj_status_t send_options_response(pjsip_rx_data *rdata, int code)
pjsip_tx_data_dec_ref(tdata);
return status;
}
- status = pjsip_endpt_send_response(endpt, &res_addr, tdata,
- NULL, NULL);
+ status = ast_sip_send_response(&res_addr, tdata,
+ ast_pjsip_rdata_get_endpoint(rdata));
}
if (status != PJ_SUCCESS) {
@@ -586,12 +571,13 @@ static pjsip_module options_module = {
* \internal
* \brief Send qualify request to the given contact.
*/
-static int cli_on_contact(void *obj, void *arg, int flags)
+static int cli_on_contact(void *obj, void *arg, void *data, int flags)
{
struct ast_sip_contact *contact = obj;
+ struct ast_sip_endpoint *endpoint = data;
int *cli_fd = arg;
ast_cli(*cli_fd, " contact %s\n", contact->uri);
- qualify_contact(contact);
+ qualify_contact(endpoint, contact);
return 0;
}
@@ -655,7 +641,7 @@ static int cli_qualify_contacts(void *data)
}
ast_cli(cli_fd, "Sending qualify to endpoint %s\n", endpoint_name);
- ao2_callback(contacts, OBJ_NODATA, cli_on_contact, &cli_fd);
+ ao2_callback_data(contacts, OBJ_NODATA, cli_on_contact, &cli_fd, endpoint);
}
return 0;
}
diff --git a/res/res_pjsip_caller_id.c b/res/res_pjsip_caller_id.c
index 1b25be28c..5996f13f3 100644
--- a/res/res_pjsip_caller_id.c
+++ b/res/res_pjsip_caller_id.c
@@ -689,7 +689,7 @@ static void caller_id_outgoing_response(struct ast_sip_session *session, pjsip_t
static struct ast_sip_session_supplement caller_id_supplement = {
.method = "INVITE,UPDATE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
.incoming_request = caller_id_incoming_request,
.incoming_response = caller_id_incoming_response,
.outgoing_request = caller_id_outgoing_request,
diff --git a/res/res_pjsip_diversion.c b/res/res_pjsip_diversion.c
index 358ef2644..0b4e2106c 100644
--- a/res/res_pjsip_diversion.c
+++ b/res/res_pjsip_diversion.c
@@ -320,7 +320,7 @@ static struct ast_sip_session_supplement diversion_supplement = {
.method = "INVITE",
/* this supplement needs to be called after caller id
and after the channel has been created */
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL + 100,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 100,
.incoming_request = diversion_incoming_request,
.incoming_response = diversion_incoming_response,
.outgoing_request = diversion_outgoing_request,
diff --git a/res/res_pjsip_header_funcs.c b/res/res_pjsip_header_funcs.c
index 063fbb761..4861cd0a9 100644
--- a/res/res_pjsip_header_funcs.c
+++ b/res/res_pjsip_header_funcs.c
@@ -596,7 +596,7 @@ static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * td
static struct ast_sip_session_supplement header_funcs_supplement = {
.method = "INVITE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
.incoming_request = incoming_request,
.outgoing_request = outgoing_request,
};
diff --git a/res/res_pjsip_messaging.c b/res/res_pjsip_messaging.c
index bb3a51cdf..0f884aeda 100644
--- a/res/res_pjsip_messaging.c
+++ b/res/res_pjsip_messaging.c
@@ -577,7 +577,7 @@ static int msg_send(void *data)
return -1;
}
- if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, &tdata)) {
+ if (ast_sip_create_request("MESSAGE", NULL, endpoint, uri, NULL, &tdata)) {
ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not create request\n");
return -1;
}
@@ -593,7 +593,7 @@ static int msg_send(void *data)
vars_to_headers(mdata->msg, tdata);
- if (ast_sip_send_request(tdata, NULL, endpoint)) {
+ if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) {
ast_log(LOG_ERROR, "PJSIP MESSAGE - Could not send request\n");
return -1;
}
@@ -630,9 +630,7 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
pj_status_t status;
pjsip_response_addr res_addr;
- pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint();
-
- status = pjsip_endpt_create_response(endpt, rdata, code, NULL, &tdata);
+ status = ast_sip_create_response(rdata, code, NULL, &tdata);
if (status != PJ_SUCCESS) {
ast_log(LOG_ERROR, "Unable to create response (%d)\n", status);
return status;
@@ -647,7 +645,7 @@ static pj_status_t send_response(pjsip_rx_data *rdata, enum pjsip_status_code co
ast_log(LOG_ERROR, "Unable to get response address (%d)\n", status);
return status;
}
- status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL);
+ status = ast_sip_send_response(&res_addr, tdata, ast_pjsip_rdata_get_endpoint(rdata));
}
if (status != PJ_SUCCESS) {
diff --git a/res/res_pjsip_mwi.c b/res/res_pjsip_mwi.c
index 4f32f382a..42aa34f1e 100644
--- a/res/res_pjsip_mwi.c
+++ b/res/res_pjsip_mwi.c
@@ -273,7 +273,7 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag
pjsip_event_hdr *event;
const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL);
- if (ast_sip_create_request("NOTIFY", NULL, endpoint, contact->uri, &tdata)) {
+ if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, contact, &tdata)) {
ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri);
return 0;
}
@@ -310,7 +310,7 @@ static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flag
pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, allow_events));
msg_body = pjsip_msg_body_create(tdata->pool, &mwi_type->type, &mwi_type->subtype, body_text);
tdata->msg->body = msg_body;
- ast_sip_send_request(tdata, NULL, endpoint);
+ ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL);
return 0;
}
diff --git a/res/res_pjsip_nat.c b/res/res_pjsip_nat.c
index 3416fffc6..092ff008b 100644
--- a/res/res_pjsip_nat.c
+++ b/res/res_pjsip_nat.c
@@ -241,7 +241,7 @@ static void nat_outgoing_invite_request(struct ast_sip_session *session, struct
/*! \brief Supplement for adding NAT functionality to dialog */
static struct ast_sip_session_supplement nat_supplement = {
.method = "INVITE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_FIRST + 1,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_FIRST + 1,
.incoming_request = nat_incoming_invite_request,
.outgoing_request = nat_outgoing_invite_request,
};
diff --git a/res/res_pjsip_notify.c b/res/res_pjsip_notify.c
index 8e9b20261..b2f24cbf2 100644
--- a/res/res_pjsip_notify.c
+++ b/res/res_pjsip_notify.c
@@ -470,7 +470,7 @@ static int notify_contact(void *obj, void *arg, int flags)
pjsip_tx_data *tdata;
if (ast_sip_create_request("NOTIFY", NULL, data->endpoint,
- contact->uri, &tdata)) {
+ NULL, contact, &tdata)) {
ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for "
"contact %s\n", contact->uri);
return -1;
@@ -479,7 +479,7 @@ static int notify_contact(void *obj, void *arg, int flags)
ast_sip_add_header(tdata, "Subscription-State", "terminated");
data->build_notify(tdata, data->info);
- if (ast_sip_send_request(tdata, NULL, data->endpoint)) {
+ if (ast_sip_send_request(tdata, NULL, data->endpoint, NULL, NULL)) {
ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for "
"contact %s\n", contact->uri);
return -1;
diff --git a/res/res_pjsip_outbound_registration.c b/res/res_pjsip_outbound_registration.c
index 63f34a014..55279c58c 100644
--- a/res/res_pjsip_outbound_registration.c
+++ b/res/res_pjsip_outbound_registration.c
@@ -116,6 +116,14 @@
<configOption name="type">
<synopsis>Must be of type 'registration'.</synopsis>
</configOption>
+ <configOption name="support_path">
+ <synopsis>Enables Path support for outbound REGISTER requests.</synopsis>
+ <description><para>
+ When this option is enabled, outbound REGISTER requests will advertise
+ support for Path headers so that intervening proxies can add to the Path
+ header as necessary.
+ </para></description>
+ </configOption>
</configObject>
</configFile>
</configInfo>
@@ -189,6 +197,8 @@ struct sip_outbound_registration_client_state {
unsigned int forbidden_retry_interval;
/*! \brief Treat authentication challenges that we cannot handle as permanent failures */
unsigned int auth_rejection_permanent;
+ /*! \brief Determines whether SIP Path support should be advertised */
+ unsigned int support_path;
/*! \brief Serializer for stuff and things */
struct ast_taskprocessor *serializer;
/*! \brief Configured authentication credentials */
@@ -234,6 +244,8 @@ struct sip_outbound_registration {
struct sip_outbound_registration_state *state;
/*! \brief Configured authentication credentials */
struct ast_sip_auth_vector outbound_auths;
+ /*! \brief Whether Path support is enabled */
+ unsigned int support_path;
};
/*! \brief Helper function which cancels the timer on a client */
@@ -245,6 +257,8 @@ static void cancel_registration(struct sip_outbound_registration_client_state *c
}
}
+static pj_str_t PATH_NAME = { "path", 4 };
+
/*! \brief Callback function for registering */
static int handle_client_registration(void *data)
{
@@ -266,6 +280,24 @@ static int handle_client_registration(void *data)
ast_debug(3, "REGISTER attempt %d to '%s' with client '%s'\n",
client_state->retries + 1, server_uri, client_uri);
+ if (client_state->support_path) {
+ pjsip_supported_hdr *hdr;
+
+ hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
+ if (!hdr) {
+ /* insert a new Supported header */
+ hdr = pjsip_supported_hdr_create(tdata->pool);
+ if (!hdr) {
+ return -1;
+ }
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
+ }
+
+ /* add on to the existing Supported header */
+ pj_strassign(&hdr->values[hdr->count++], &PATH_NAME);
+ }
+
/* Due to the registration the callback may now get called, so bump the ref count */
ao2_ref(client_state, +1);
if (pjsip_regc_send(client_state->client, tdata) != PJ_SUCCESS) {
@@ -818,6 +850,7 @@ static int sip_outbound_registration_perform(void *data)
registration->state->client_state->forbidden_retry_interval = registration->forbidden_retry_interval;
registration->state->client_state->max_retries = registration->max_retries;
registration->state->client_state->retries = 0;
+ registration->state->client_state->support_path = registration->support_path;
pjsip_regc_update_expires(registration->state->client_state->client, registration->expiration);
@@ -1100,6 +1133,7 @@ static int load_module(void)
ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "max_retries", "10", OPT_UINT_T, 0, FLDSET(struct sip_outbound_registration, max_retries));
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));
ast_sorcery_object_field_register_custom(ast_sip_get_sorcery(), "registration", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, 0, 0);
+ ast_sorcery_object_field_register(ast_sip_get_sorcery(), "registration", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct sip_outbound_registration, support_path));
ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
sip_outbound_registration_perform_all();
diff --git a/res/res_pjsip_path.c b/res/res_pjsip_path.c
new file mode 100644
index 000000000..28d8b589f
--- /dev/null
+++ b/res/res_pjsip_path.c
@@ -0,0 +1,250 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Kinsey Moore <kmoore@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*** MODULEINFO
+ <depend>pjproject</depend>
+ <depend>res_pjsip</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+#include <pjsip.h>
+#include <pjsip_ua.h>
+
+#include "asterisk/res_pjsip.h"
+#include "asterisk/res_pjsip_session.h"
+#include "asterisk/module.h"
+#include "asterisk/strings.h"
+
+static const pj_str_t PATH_NAME = { "Path", 4 };
+static pj_str_t PATH_SUPPORTED_NAME = { "path", 4 };
+
+static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri)
+{
+ char *configured_aors, *aor_name;
+ pjsip_sip_uri *sip_uri;
+ char *domain_name;
+ RAII_VAR(struct ast_str *, id, NULL, ast_free);
+
+ if (ast_strlen_zero(endpoint->aors)) {
+ return NULL;
+ }
+
+ sip_uri = pjsip_uri_get_uri(uri);
+ domain_name = ast_alloca(sip_uri->host.slen + 1);
+ ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1);
+
+ configured_aors = ast_strdupa(endpoint->aors);
+
+ /* Iterate the configured AORs to see if the user or the user+domain match */
+ while ((aor_name = strsep(&configured_aors, ","))) {
+ struct ast_sip_domain_alias *alias = NULL;
+
+ if (!pj_strcmp2(&sip_uri->user, aor_name)) {
+ break;
+ }
+
+ if (!id && !(id = ast_str_create(sip_uri->user.slen + sip_uri->host.slen + 2))) {
+ return NULL;
+ }
+
+ ast_str_set(&id, 0, "%.*s@", (int)sip_uri->user.slen, sip_uri->user.ptr);
+ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
+ ast_str_append(&id, 0, "%s", alias->domain);
+ ao2_cleanup(alias);
+ } else {
+ ast_str_append(&id, 0, "%s", domain_name);
+ }
+
+ if (!strcmp(aor_name, ast_str_buffer(id))) {
+ ast_free(id);
+ break;
+ }
+ }
+
+ if (ast_strlen_zero(aor_name)) {
+ return NULL;
+ }
+
+ return ast_sip_location_retrieve_aor(aor_name);
+}
+
+/*!
+ * \brief Get the path string associated with this contact and tdata
+ *
+ * \param endpoint The endpoint from which to pull associated path data
+ * \param contact_uri The URI identifying the associated contact
+ * \param path_str The place to store the retrieved path information
+ *
+ * \retval zero on success
+ * \retval non-zero on failure or no available path information
+ */
+static int path_get_string(pj_pool_t *pool, struct ast_sip_contact *contact, pj_str_t *path_str)
+{
+ if (!contact || ast_strlen_zero(contact->path)) {
+ return -1;
+ }
+
+ *path_str = pj_strdup3(pool, contact->path);
+ return 0;
+}
+
+static int add_supported(pjsip_tx_data *tdata)
+{
+ pjsip_supported_hdr *hdr;
+
+ hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
+ if (!hdr) {
+ /* insert a new Supported header */
+ hdr = pjsip_supported_hdr_create(tdata->pool);
+ if (!hdr) {
+ return -1;
+ }
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
+ }
+
+ /* add on to the existing Supported header */
+ pj_strassign(&hdr->values[hdr->count++], &PATH_SUPPORTED_NAME);
+
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Adds a Route header to an outgoing request if
+ * path information is available.
+ *
+ * \param endpoint The endpoint with which this request is associated
+ * \param contact The contact to which this request is being sent
+ * \param tdata The outbound request
+ */
+static void path_outgoing_request(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
+{
+ RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+
+ if (!endpoint) {
+ return;
+ }
+
+ aor = find_aor(endpoint, tdata->msg->line.req.uri);
+ if (!aor || !aor->support_path) {
+ return;
+ }
+
+ if (add_supported(tdata)) {
+ return;
+ }
+
+ if (contact && !ast_strlen_zero(contact->path)) {
+ ast_sip_set_outbound_proxy(tdata, contact->path);
+ }
+}
+
+static void path_session_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ path_outgoing_request(session->endpoint, session->contact, tdata);
+}
+
+/*!
+ * \internal
+ * \brief Adds a path header to an outgoing 2XX response
+ *
+ * \param endpoint The endpoint to which the INVITE response is to be sent
+ * \param contact The contact to which the INVITE response is to be sent
+ * \param tdata The outbound INVITE response
+ */
+static void path_outgoing_response(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, pjsip_tx_data *tdata)
+{
+ struct pjsip_status_line status = tdata->msg->line.status;
+ pj_str_t path_dup;
+ pjsip_generic_string_hdr *path_hdr;
+ pjsip_contact_hdr *contact_hdr;
+ RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
+ pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ, NULL);
+ const pj_str_t REGISTER_METHOD = {"REGISTER", 8};
+
+ if (!endpoint
+ || !pj_stristr(&REGISTER_METHOD, &cseq->method.name)
+ || !PJSIP_IS_STATUS_IN_CLASS(status.code, 200)) {
+ return;
+ }
+
+ contact_hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
+ if (!contact_hdr) {
+ return;
+ }
+
+ aor = find_aor(endpoint, contact_hdr->uri);
+ if (!aor || !aor->support_path || add_supported(tdata)
+ || path_get_string(tdata->pool, contact, &path_dup)) {
+ return;
+ }
+
+ path_hdr = pjsip_generic_string_hdr_create(tdata->pool, &PATH_NAME, &path_dup);
+ if (!path_hdr) {
+ return;
+ }
+
+ pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)path_hdr);
+}
+
+static void path_session_outgoing_response(struct ast_sip_session *session, pjsip_tx_data *tdata)
+{
+ path_outgoing_response(session->endpoint, session->contact, tdata);
+}
+
+static struct ast_sip_supplement path_supplement = {
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
+ .outgoing_request = path_outgoing_request,
+ .outgoing_response = path_outgoing_response,
+};
+
+static struct ast_sip_session_supplement path_session_supplement = {
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 100,
+ .outgoing_request = path_session_outgoing_request,
+ .outgoing_response = path_session_outgoing_response,
+};
+
+static int load_module(void)
+{
+ if (ast_sip_register_supplement(&path_supplement)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ if (ast_sip_session_register_supplement(&path_session_supplement)) {
+ ast_sip_unregister_supplement(&path_supplement);
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sip_unregister_supplement(&path_supplement);
+ ast_sip_session_unregister_supplement(&path_session_supplement);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Path Header Support",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_APP_DEPEND,
+);
diff --git a/res/res_pjsip_refer.c b/res/res_pjsip_refer.c
index 7664f1a22..916cf5eb9 100644
--- a/res/res_pjsip_refer.c
+++ b/res/res_pjsip_refer.c
@@ -919,7 +919,7 @@ static void refer_outgoing_request(struct ast_sip_session *session, struct pjsip
}
static struct ast_sip_session_supplement refer_supplement = {
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL + 1,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
.incoming_request = refer_incoming_request,
.outgoing_request = refer_outgoing_request,
};
diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c
index 89e8cd141..7624472fc 100644
--- a/res/res_pjsip_registrar.c
+++ b/res/res_pjsip_registrar.c
@@ -347,6 +347,64 @@ static struct rx_task_data *rx_task_data_create(pjsip_rx_data *rdata,
return task_data;
}
+static const pj_str_t path_hdr_name = { "Path", 4 };
+
+static int build_path_data(struct rx_task_data *task_data, struct ast_str **path_str)
+{
+ pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, NULL);
+
+ if (!path_hdr) {
+ return 0;
+ }
+
+ *path_str = ast_str_create(64);
+ if (!path_str) {
+ return -1;
+ }
+
+ ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
+
+ while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
+ ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
+ }
+
+ return 0;
+}
+
+static int registrar_validate_path(struct rx_task_data *task_data, struct ast_str **path_str)
+{
+ const pj_str_t path_supported_name = { "path", 4 };
+ pjsip_supported_hdr *supported_hdr;
+ int i;
+
+ if (!task_data->aor->support_path) {
+ return 0;
+ }
+
+ if (build_path_data(task_data, path_str)) {
+ return -1;
+ }
+
+ if (!*path_str) {
+ return 0;
+ }
+
+ supported_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
+ if (!supported_hdr) {
+ return -1;
+ }
+
+ /* Find advertised path support */
+ for (i = 0; i < supported_hdr->count; i++) {
+ if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
+ return 0;
+ }
+ }
+
+ /* Path header present, but support not advertised */
+ return -1;
+}
+
static int rx_task(void *data)
{
RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
@@ -358,6 +416,8 @@ static int rx_task(void *data)
pjsip_tx_data *tdata;
pjsip_response_addr addr;
const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
+ RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
+ struct ast_sip_contact *response_contact;
/* Retrieve the current contacts, we'll need to know whether to update or not */
contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
@@ -374,6 +434,14 @@ static int rx_task(void *data)
return PJ_TRUE;
}
+ if (registrar_validate_path(task_data, &path_str)) {
+ /* Ensure that intervening proxies did not make invalid modifications to the request */
+ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 420, NULL, NULL, NULL);
+ ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
+ ast_sorcery_object_get_id(task_data->endpoint));
+ return PJ_TRUE;
+ }
+
if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) {
/* Enforce the maximum number of contacts */
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL);
@@ -417,7 +485,8 @@ static int rx_task(void *data)
continue;
}
- ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)));
+ ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(),
+ ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL);
ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
contact_uri, aor_name, expiration);
ast_test_suite_event_notify("AOR_CONTACT_ADDED",
@@ -432,6 +501,9 @@ static int rx_task(void *data)
updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
updated->qualify_frequency = task_data->aor->qualify_frequency;
updated->authenticate_qualify = task_data->aor->authenticate_qualify;
+ if (path_str) {
+ ast_string_field_set(updated, path, ast_str_buffer(path_str));
+ }
ast_sip_location_update_contact(updated);
ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
@@ -465,12 +537,16 @@ static int rx_task(void *data)
/* Update the contacts as things will probably have changed */
ao2_cleanup(contacts);
+
contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
+ response_contact = ao2_callback(contacts, 0, NULL, NULL);
/* Send a response containing all of the contacts (including static) that are present on this AOR */
- if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), task_data->rdata, 200, NULL, &tdata) != PJ_SUCCESS) {
+ if (ast_sip_create_response(task_data->rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
+ ao2_cleanup(response_contact);
return PJ_TRUE;
}
+ ao2_cleanup(response_contact);
/* Add the date header to the response, some UAs use this to set their date and time */
registrar_add_date_header(tdata);
@@ -478,7 +554,7 @@ static int rx_task(void *data)
ao2_callback(contacts, 0, registrar_add_contact, tdata);
if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) {
- pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL);
+ ast_sip_send_response(&addr, tdata, task_data->endpoint);
} else {
pjsip_tx_data_dec_ref(tdata);
}
@@ -495,8 +571,9 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);
pjsip_sip_uri *uri;
- char user_name[64], domain_name[64];
+ char *domain_name;
char *configured_aors, *aor_name;
+ RAII_VAR(struct ast_str *, id, NULL, ast_free);
if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
return PJ_FALSE;
@@ -518,29 +595,33 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
}
uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
- ast_copy_pj_str(user_name, &uri->user, sizeof(user_name));
- ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name));
+ domain_name = ast_alloca(uri->host.slen + 1);
+ ast_copy_pj_str(domain_name, &uri->host, uri->host.slen + 1);
configured_aors = ast_strdupa(endpoint->aors);
/* Iterate the configured AORs to see if the user or the user+domain match */
while ((aor_name = strsep(&configured_aors, ","))) {
- char id[AST_UUID_STR_LEN];
- RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup);
+ struct ast_sip_domain_alias *alias = NULL;
- snprintf(id, sizeof(id), "%s@%s", user_name, domain_name);
- if (!strcmp(aor_name, id)) {
+ if (!pj_strcmp2(&uri->user, aor_name)) {
break;
}
+ if (!id && !(id = ast_str_create(uri->user.slen + uri->host.slen + 2))) {
+ return PJ_TRUE;
+ }
+
+ ast_str_set(&id, 0, "%.*s@", (int)uri->user.slen, uri->user.ptr);
if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) {
- snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain);
- if (!strcmp(aor_name, id)) {
- break;
- }
+ ast_str_append(&id, 0, "%s", alias->domain);
+ ao2_cleanup(alias);
+ } else {
+ ast_str_append(&id, 0, "%s", domain_name);
}
- if (!strcmp(aor_name, user_name)) {
+ if (!strcmp(aor_name, ast_str_buffer(id))) {
+ ast_free(id);
break;
}
}
@@ -549,7 +630,7 @@ static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
/* The provided AOR name was not found (be it within the configuration or sorcery itself) */
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
- ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint));
+ ast_log(LOG_WARNING, "AOR '%.*s' not found for endpoint '%s'\n", (int)uri->user.slen, uri->user.ptr, ast_sorcery_object_get_id(endpoint));
return PJ_TRUE;
}
diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c
index a00299ebb..03d2e577a 100644
--- a/res/res_pjsip_session.c
+++ b/res/res_pjsip_session.c
@@ -1045,6 +1045,7 @@ static void session_destructor(void *obj)
}
ast_party_id_free(&session->id);
ao2_cleanup(session->endpoint);
+ ao2_cleanup(session->contact);
ast_format_cap_destroy(session->req_caps);
ast_format_cap_destroy(session->direct_media_cap);
@@ -1112,7 +1113,8 @@ struct ast_sip_channel_pvt *ast_sip_channel_pvt_alloc(void *pvt, struct ast_sip_
return channel;
}
-struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint, pjsip_inv_session *inv_session)
+struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
+ struct ast_sip_contact *contact, pjsip_inv_session *inv_session)
{
RAII_VAR(struct ast_sip_session *, session, ao2_alloc(sizeof(*session), session_destructor), ao2_cleanup);
struct ast_sip_session_supplement *iter;
@@ -1140,10 +1142,9 @@ struct ast_sip_session *ast_sip_session_alloc(struct ast_sip_endpoint *endpoint,
ast_sip_dialog_set_serializer(inv_session->dlg, session->serializer);
ast_sip_dialog_set_endpoint(inv_session->dlg, endpoint);
pjsip_dlg_inc_session(inv_session->dlg, &session_module);
- ao2_ref(session, +1);
- inv_session->mod_data[session_module.id] = session;
- ao2_ref(endpoint, +1);
- session->endpoint = endpoint;
+ inv_session->mod_data[session_module.id] = ao2_bump(session);
+ session->endpoint = ao2_bump(endpoint);
+ session->contact = ao2_bump(contact);
session->inv_session = inv_session;
session->req_caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK);
@@ -1192,21 +1193,27 @@ static int session_outbound_auth(pjsip_dialog *dlg, pjsip_tx_data *tdata, void *
return 0;
}
-struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint, const char *location, const char *request_user, struct ast_format_cap *req_caps)
+struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint *endpoint,
+ struct ast_sip_contact *contact, const char *location, const char *request_user,
+ struct ast_format_cap *req_caps)
{
const char *uri = NULL;
- RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_sip_contact *, found_contact, NULL, ao2_cleanup);
pjsip_timer_setting timer;
pjsip_dialog *dlg;
struct pjsip_inv_session *inv_session;
RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
/* If no location has been provided use the AOR list from the endpoint itself */
- location = S_OR(location, endpoint->aors);
+ if (location || !contact) {
+ location = S_OR(location, endpoint->aors);
- contact = ast_sip_location_retrieve_contact_from_aor_list(location);
- if (!contact || ast_strlen_zero(contact->uri)) {
- uri = location;
+ found_contact = ast_sip_location_retrieve_contact_from_aor_list(location);
+ if (!found_contact || ast_strlen_zero(found_contact->uri)) {
+ uri = location;
+ } else {
+ uri = found_contact->uri;
+ }
} else {
uri = contact->uri;
}
@@ -1238,7 +1245,7 @@ struct ast_sip_session *ast_sip_session_create_outgoing(struct ast_sip_endpoint
timer.sess_expires = endpoint->extensions.timer.sess_expires;
pjsip_timer_init_session(inv_session, &timer);
- if (!(session = ast_sip_session_alloc(endpoint, inv_session))) {
+ if (!(session = ast_sip_session_alloc(endpoint, found_contact ? found_contact : contact, inv_session))) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
return NULL;
}
@@ -1534,7 +1541,7 @@ static void handle_new_invite_request(pjsip_rx_data *rdata)
return;
}
- session = ast_sip_session_alloc(endpoint, inv_session);
+ session = ast_sip_session_alloc(endpoint, NULL, inv_session);
if (!session) {
if (pjsip_inv_initial_answer(inv_session, rdata, 500, NULL, NULL, &tdata) == PJ_SUCCESS) {
pjsip_inv_terminate(inv_session, 500, PJ_FALSE);
diff --git a/res/res_pjsip_t38.c b/res/res_pjsip_t38.c
index afe12505d..1bb36ca1d 100644
--- a/res/res_pjsip_t38.c
+++ b/res/res_pjsip_t38.c
@@ -498,7 +498,7 @@ static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
/*! \brief Supplement for adding framehook to session channel */
static struct ast_sip_session_supplement t38_supplement = {
.method = "INVITE",
- .priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL + 1,
+ .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL + 1,
.incoming_request = t38_incoming_invite_request,
.outgoing_request = t38_outgoing_invite_request,
};