Store SIP User-Agent information in contacts.

When an endpoint sends a REGISTER request to Asterisk, we now will
associate the User-Agent header with all contacts that were bound in
that REGISTER request.
........

Merged revisions 408270 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@408272 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/97/197/1
Mark Michelson 12 years ago
parent 438a7abc27
commit ed66eefdf0

@ -20,6 +20,14 @@
=== UPGRADE-11.txt -- Upgrade info for 10 to 11 === UPGRADE-11.txt -- Upgrade info for 10 to 11
=== UPGRADE-12.txt -- Upgrade info for 11 to 12 === UPGRADE-12.txt -- Upgrade info for 11 to 12
=========================================================== ===========================================================
From 12.1.0 to 12.2.0:
PJSIP:
- The PJSIP registrar now stores the contents of the User-Agent header of incoming
REGISTER requests for each contact that is registered. If using realtime for
PJSIP contacts, this means that the schema has been updated to add a user_agent
column. An alembic revision has been added to facilitate this update.
From 12.0.0 to 12.1.0:
* The sound_place_into_conference sound used in Confbridge is now deprecated * The sound_place_into_conference sound used in Confbridge is now deprecated
and is no longer functional since it has been broken since its inception and is no longer functional since it has been broken since its inception
and the fix involved using a different method to achieve the same goal. The and the fix involved using a different method to achieve the same goal. The

@ -153,6 +153,8 @@ struct ast_sip_contact {
AST_STRING_FIELD(outbound_proxy); AST_STRING_FIELD(outbound_proxy);
/*! Path information to place in Route headers */ /*! Path information to place in Route headers */
AST_STRING_FIELD(path); AST_STRING_FIELD(path);
/*! Content of the User-Agent header in REGISTER request */
AST_STRING_FIELD(user_agent);
); );
/*! Absolute time that this contact is no longer valid after */ /*! Absolute time that this contact is no longer valid after */
struct timeval expiration_time; struct timeval expiration_time;
@ -905,12 +907,13 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
* \param uri Full contact URI * \param uri Full contact URI
* \param expiration_time Optional expiration time of the contact * \param expiration_time Optional expiration time of the contact
* \param path_info Path information * \param path_info Path information
* \param user_agent User-Agent header from REGISTER request
* *
* \retval -1 failure * \retval -1 failure
* \retval 0 success * \retval 0 success
*/ */
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info); struct timeval expiration_time, const char *path_info, const char *user_agent);
/*! /*!
* \brief Update a contact * \brief Update a contact

@ -897,6 +897,13 @@
<configOption name="path"> <configOption name="path">
<synopsis>Stored Path vector for use in Route headers on outgoing requests.</synopsis> <synopsis>Stored Path vector for use in Route headers on outgoing requests.</synopsis>
</configOption> </configOption>
<configOption name="user_agent">
<synopsis>User-Agent header from registration.</synopsis>
<description><para>
The User-Agent is automatically stored based on data present in incoming SIP
REGISTER requests and is not intended to be configured manually.
</para></description>
</configOption>
</configObject> </configObject>
<configObject name="aor"> <configObject name="aor">
<synopsis>The configuration for a location of an endpoint</synopsis> <synopsis>The configuration for a location of an endpoint</synopsis>

@ -178,7 +178,8 @@ 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); 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, const char *path_info) int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent)
{ {
char name[AST_UUID_STR_LEN]; char name[AST_UUID_STR_LEN];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
@ -201,6 +202,10 @@ int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri, struc
ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy); ast_string_field_set(contact, outbound_proxy, aor->outbound_proxy);
} }
if (!ast_strlen_zero(user_agent)) {
ast_string_field_set(contact, user_agent, user_agent);
}
return ast_sorcery_create(ast_sip_get_sorcery(), contact); return ast_sorcery_create(ast_sip_get_sorcery(), contact);
} }
@ -665,6 +670,7 @@ int ast_sip_initialize_sorcery_location(void)
ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T, 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); PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy)); ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent));
ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration)); ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));

@ -170,9 +170,11 @@ static int registrar_delete_contact(void *obj, void *arg, int flags)
ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact->uri, aor_name);
ast_test_suite_event_notify("AOR_CONTACT_REMOVED", ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
"Contact: %s\r\n" "Contact: %s\r\n"
"AOR: %s", "AOR: %s\r\n"
"UserAgent: %s",
contact->uri, contact->uri,
aor_name); aor_name,
contact->user_agent);
} }
return 0; return 0;
@ -407,6 +409,8 @@ static int registrar_validate_path(struct rx_task_data *task_data, struct ast_st
static int rx_task(void *data) static int rx_task(void *data)
{ {
static const pj_str_t USER_AGENT = { "User-Agent", 10 };
RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup); RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup);
RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
@ -418,6 +422,8 @@ static int rx_task(void *data)
const char *aor_name = ast_sorcery_object_get_id(task_data->aor); const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
RAII_VAR(struct ast_str *, path_str, NULL, ast_free); RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
struct ast_sip_contact *response_contact; struct ast_sip_contact *response_contact;
char *user_agent = NULL;
pjsip_user_agent_hdr *user_agent_hdr;
/* Retrieve the current contacts, we'll need to know whether to update or not */ /* Retrieve the current contacts, we'll need to know whether to update or not */
contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor); contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
@ -456,6 +462,13 @@ static int rx_task(void *data)
return PJ_TRUE; return PJ_TRUE;
} }
user_agent_hdr = pjsip_msg_find_hdr_by_name(task_data->rdata->msg_info.msg, &USER_AGENT, NULL);
if (user_agent_hdr) {
size_t alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
user_agent = ast_alloca(alloc_size);
ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
}
/* Iterate each provided Contact header and add, update, or delete */ /* Iterate each provided Contact header and add, update, or delete */
while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
int expiration; int expiration;
@ -485,17 +498,25 @@ static int rx_task(void *data)
continue; continue;
} }
ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), if (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_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL,
user_agent)) {
ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
contact_uri, aor_name);
continue;
}
ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
contact_uri, aor_name, expiration); contact_uri, aor_name, expiration);
ast_test_suite_event_notify("AOR_CONTACT_ADDED", ast_test_suite_event_notify("AOR_CONTACT_ADDED",
"Contact: %s\r\n" "Contact: %s\r\n"
"AOR: %s\r\n" "AOR: %s\r\n"
"Expiration: %d", "Expiration: %d\r\n"
"UserAgent: %s",
contact_uri, contact_uri,
aor_name, aor_name,
expiration); expiration,
user_agent);
} else if (expiration) { } else if (expiration) {
RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup); RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup);
updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
@ -504,6 +525,9 @@ static int rx_task(void *data)
if (path_str) { if (path_str) {
ast_string_field_set(updated, path, ast_str_buffer(path_str)); ast_string_field_set(updated, path, ast_str_buffer(path_str));
} }
if (user_agent) {
ast_string_field_set(updated, user_agent, user_agent);
}
ast_sip_location_update_contact(updated); ast_sip_location_update_contact(updated);
ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
@ -511,18 +535,24 @@ static int rx_task(void *data)
ast_test_suite_event_notify("AOR_CONTACT_REFRESHED", ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
"Contact: %s\r\n" "Contact: %s\r\n"
"AOR: %s\r\n" "AOR: %s\r\n"
"Expiration: %d", "Expiration: %d\r\n"
"UserAgent: %s",
contact_uri, contact_uri,
aor_name, aor_name,
expiration); expiration,
updated->user_agent);
} else { } else {
/* We want to report the user agent that was actually in the removed contact */
user_agent = ast_strdupa(contact->user_agent);
ast_sip_location_delete_contact(contact); ast_sip_location_delete_contact(contact);
ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
ast_test_suite_event_notify("AOR_CONTACT_REMOVED", ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
"Contact: %s\r\n" "Contact: %s\r\n"
"AOR: %s", "AOR: %s\r\n"
"UserAgent: %s",
contact_uri, contact_uri,
aor_name); aor_name,
user_agent);
} }
} }

Loading…
Cancel
Save