Store SIP User-Agent information in contacts.
authorMark Michelson <mmichelson@digium.com>
Mon, 17 Feb 2014 15:36:45 +0000 (15:36 +0000)
committerMark Michelson <mmichelson@digium.com>
Mon, 17 Feb 2014 15:36:45 +0000 (15:36 +0000)
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

UPGRADE.txt
include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/location.c
res/res_pjsip_registrar.c

index 9712c49..b996f07 100644 (file)
 === 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
index 82f942b..80919c7 100644 (file)
@@ -153,6 +153,8 @@ struct ast_sip_contact {
                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;
@@ -905,12 +907,13 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
  * \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
index 3ad482d..7406c23 100644 (file)
                                <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>
index fbc48fe..8826286 100644 (file)
@@ -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);
 }
 
-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);
@@ -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);
        }
 
+       if (!ast_strlen_zero(user_agent)) {
+               ast_string_field_set(contact, user_agent, user_agent);
+       }
+
        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,
                                          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));
index 7624472..5f02087 100644 (file)
@@ -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_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;
@@ -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 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);
 
@@ -418,6 +422,8 @@ static int rx_task(void *data)
        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);
@@ -456,6 +462,13 @@ static int rx_task(void *data)
                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;
@@ -485,17 +498,25 @@ 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)), 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));
@@ -504,6 +525,9 @@ static int rx_task(void *data)
                        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",
@@ -511,18 +535,24 @@ static int rx_task(void *data)
                        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);
                }
        }