=== UPGRADE-11.txt -- Upgrade info for 10 to 11
=== 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
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
AST_STRING_FIELD(outbound_proxy);
/*! Path information to place in Route headers */
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 */
struct timeval expiration_time;
* \param uri Full contact URI
* \param expiration_time Optional expiration time of the contact
* \param path_info Path information
+ * \param user_agent User-Agent header from REGISTER request
*
* \retval -1 failure
* \retval 0 success
*/
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
<configOption name="path">
<synopsis>Stored Path vector for use in Route headers on outgoing requests.</synopsis>
</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 name="aor">
<synopsis>The configuration for a location of an endpoint</synopsis>
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];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
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);
}
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);
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", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));
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",
"Contact: %s\r\n"
- "AOR: %s",
+ "AOR: %s\r\n"
+ "UserAgent: %s",
contact->uri,
- aor_name);
+ aor_name,
+ contact->user_agent);
}
return 0;
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 ao2_container *, contacts, NULL, ao2_cleanup);
const char *aor_name = ast_sorcery_object_get_id(task_data->aor);
RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
struct ast_sip_contact *response_contact;
+ char *user_agent = NULL;
+ pjsip_user_agent_hdr *user_agent_hdr;
/* Retrieve the current contacts, we'll need to know whether to update or not */
contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor);
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 */
while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) {
int expiration;
continue;
}
- 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);
+ 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,
+ 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",
contact_uri, aor_name, expiration);
ast_test_suite_event_notify("AOR_CONTACT_ADDED",
"Contact: %s\r\n"
"AOR: %s\r\n"
- "Expiration: %d",
+ "Expiration: %d\r\n"
+ "UserAgent: %s",
contact_uri,
aor_name,
- expiration);
+ expiration,
+ user_agent);
} else if (expiration) {
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));
if (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_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
"Contact: %s\r\n"
"AOR: %s\r\n"
- "Expiration: %d",
+ "Expiration: %d\r\n"
+ "UserAgent: %s",
contact_uri,
aor_name,
- expiration);
+ expiration,
+ updated->user_agent);
} 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_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name);
ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
"Contact: %s\r\n"
- "AOR: %s",
+ "AOR: %s\r\n"
+ "UserAgent: %s",
contact_uri,
- aor_name);
+ aor_name,
+ user_agent);
}
}