res_hep: Provide an option to pick the UUID type
authorMatt Jordan <mjordan@digium.com>
Thu, 12 May 2016 01:17:15 +0000 (20:17 -0500)
committerMatt Jordan <mjordan@digium.com>
Sat, 14 May 2016 14:42:20 +0000 (09:42 -0500)
At one point in time, it seemed like a good idea to use the Asterisk
channel name as the HEP correlation UUID. In particular, it felt like
this would be a useful identifier to tie PJSIP messages and RTCP
messages together, along with whatever other data we may eventually send
to Homer. This also had the benefit of keeping the correlation UUID
channel technology agnostic.

In practice, it isn't as useful as hoped, for two reasons:
1) The first INVITE request received doesn't have a channel. As a
   result, there is always an 'odd message out', leading it to be
   potentially uncorrelated in Homer.
2) Other systems sending capture packets (Kamailio) use the SIP Call-ID.
   This causes RTCP information to be uncorrelated to the SIP message
   traffic seen by those capture nodes.

In order to support both (in case someone is trying to use res_hep_rtcp
with a non-PJSIP channel), this patch adds a new option, uuid_type, with
two valid values - 'call-id' and 'channel'. The uuid_type option is used
by a module to determine the preferred UUID type. When available, that
source of a correlation UUID is used; when not, the more readily available
source is used.

For res_hep_pjsip:
 - uuid_type = call-id: the module uses the SIP Call-ID header value
 - uuid_type = channel: the module uses the channel name if available,
                        falling back to SIP Call-ID if not
For res_hep_rtcp:
 - uuid_type = call-id: the module uses the SIP Call-ID header if the
                        channel type is PJSIP and we have a channel,
                        falling back to the Stasis event provided
                        channel name if not
 - uuid_type = channel: the module uses the channel name

ASTERISK-25352 #close

Change-Id: Ide67e59a52d9c806e3cc0a797ea1a4b88a00122c

CHANGES
configs/samples/hep.conf.sample
include/asterisk/res_hep.h
res/res_hep.c
res/res_hep.exports.in
res/res_hep_pjsip.c
res/res_hep_rtcp.c

diff --git a/CHANGES b/CHANGES
index ec44e30..3ec0bfb 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -289,6 +289,16 @@ res_pjsip
    into the "reg_server" field in the ps_contacts table to facilitate
    multi-server setups.
 
+res_hep
+------------------
+ * Added a new option, 'uuid_type', that sets the preferred source of the Homer
+   correlation UUID. The valid options are:
+   - call-id: Use the PJSIP SIP Call-ID header value
+   - channel: Use the Asterisk channel name
+   The default value is 'call-id'. In the event that a HEP module cannot find a
+   valid value using the specified 'uuid_type', the module may fallback to a
+   more readily available source for the correlation UUID.
+
 app_confbridge
 ------------------
  * Added a bridge profile option called regcontext that allows you to
index 40b17aa..6e409d1 100644 (file)
@@ -13,4 +13,8 @@ capture_password = foo             ; If specified, the authorization passsword
 capture_id = 1234                  ; A unique integer identifier for this
                                    ; server. This ID will be embedded sent
                                    ; with each packet from this server.
+uuid_type = call-id                ; Specify the preferred source for the Homer
+                                   ; correlation UUID. Valid options are:
+                                   ; - 'call-id' for the PJSIP SIP Call-ID
+                                   ; - 'channel' for the Asterisk channel name
 
index 8839fd6..bd0129e 100644 (file)
@@ -49,6 +49,11 @@ enum hepv3_capture_type {
        HEPV3_CAPTURE_TYPE_IAX    = 0x10,
 };
 
+enum hep_uuid_type {
+       HEP_UUID_TYPE_CALL_ID = 0,
+       HEP_UUID_TYPE_CHANNEL,
+};
+
 /*! \brief HEPv3 Capture Info */
 struct hepv3_capture_info {
        /*! The source address of the packet */
@@ -104,6 +109,15 @@ struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t
  */
 int hepv3_send_packet(struct hepv3_capture_info *capture_info);
 
+/*!
+ * \brief Get the preferred UUID type
+ *
+ * \since 13.10.0
+ *
+ * \retval The type of UUID the packet should use
+ */
+enum hep_uuid_type hepv3_get_uuid_type(void);
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
index e831fff..4520135 100644 (file)
                                                </enumlist>
                                        </description>
                                </configOption>
+                               <configOption name="uuid_type" default="call-id">
+                                       <synopsis>The preferred type of UUID to pass to Homer.</synopsis>
+                                       <description>
+                                               <enumlist>
+                                                       <enum name="call-id"><para>Use the PJSIP Call-Id</para></enum>
+                                                       <enum name="channel"><para>Use the Asterisk channel name</para></enum>
+                                               </enumlist>
+                                       </description>
+                               </configOption>
                                <configOption name="capture_address" default="192.168.1.1:9061">
                                        <synopsis>The address and port of the Homer server to send packets to.</synopsis>
                                </configOption>
@@ -231,6 +240,7 @@ struct hep_generic {
 struct hepv3_global_config {
        unsigned int enabled;                    /*!< Whether or not sending is enabled */
        unsigned int capture_id;                 /*!< Capture ID for this agent */
+       enum hep_uuid_type uuid_type;            /*!< The preferred type of the UUID */
        AST_DECLARE_STRING_FIELDS(
                AST_STRING_FIELD(capture_address);   /*!< Address to send to */
                AST_STRING_FIELD(capture_password);  /*!< Password for Homer server */
@@ -329,6 +339,25 @@ static void *module_config_alloc(void)
        return config;
 }
 
+/*! \brief Handler for the uuid_type attribute */
+static int uuid_type_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
+{
+       struct hepv3_global_config *global_config = obj;
+
+       if (strcasecmp(var->name, "uuid_type")) {
+               return -1;
+       }
+
+       if (!strcasecmp(var->value, "channel")) {
+               global_config->uuid_type = HEP_UUID_TYPE_CHANNEL;
+       } else if (!strcasecmp(var->value, "call-id")) {
+               global_config->uuid_type = HEP_UUID_TYPE_CALL_ID;
+       } else {
+               return -1;
+       }
+       return 0;
+}
+
 /*! \brief HEPv3 run-time data destructor */
 static void hepv3_data_dtor(void *obj)
 {
@@ -376,6 +405,13 @@ static void capture_info_dtor(void *obj)
        ast_free(info->payload);
 }
 
+enum hep_uuid_type hepv3_get_uuid_type(void)
+{
+       RAII_VAR(struct module_config *, config, ao2_global_obj_ref(global_config), ao2_cleanup);
+
+       return config->general->uuid_type;
+}
+
 struct hepv3_capture_info *hepv3_create_capture_info(const void *payload, size_t len)
 {
        struct hepv3_capture_info *info;
@@ -607,6 +643,7 @@ static int load_module(void)
        aco_option_register(&cfg_info, "capture_address", ACO_EXACT, global_options, DEFAULT_HEP_SERVER, OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_address));
        aco_option_register(&cfg_info, "capture_password", ACO_EXACT, global_options, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct hepv3_global_config, capture_password));
        aco_option_register(&cfg_info, "capture_id", ACO_EXACT, global_options, "0", OPT_UINT_T, 0, STRFLDSET(struct hepv3_global_config, capture_id));
+       aco_option_register_custom(&cfg_info, "uuid_type", ACO_EXACT, global_options, "call-id", uuid_type_handler, 0);
 
        if (aco_process_config(&cfg_info, 0) == ACO_PROCESS_ERROR) {
                goto error;
index d09d3f4..df0f2b4 100644 (file)
@@ -2,6 +2,7 @@
        global:
                LINKER_SYMBOL_PREFIX*hepv3_send_packet;
                LINKER_SYMBOL_PREFIX*hepv3_create_capture_info;
+               LINKER_SYMBOL_PREFIX*hepv3_get_uuid_type;
        local:
                *;
 };
index 87d68e3..effcc85 100644 (file)
@@ -51,13 +51,18 @@ static char *assign_uuid(const pj_str_t *call_id, const pj_str_t *local_tag, con
        RAII_VAR(struct ast_sip_session *, session, NULL, ao2_cleanup);
        pjsip_dialog *dlg;
        char *uuid = NULL;
+       enum hep_uuid_type uuid_type = hepv3_get_uuid_type();
 
-       if ((dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE))
+       if ((uuid_type == HEP_UUID_TYPE_CHANNEL)
+               && (dlg = pjsip_ua_find_dialog(call_id, local_tag, remote_tag, PJ_FALSE))
            && (session = ast_sip_dialog_get_session(dlg))
            && (session->channel)) {
 
                uuid = ast_strdup(ast_channel_name(session->channel));
-       } else {
+       }
+
+       /* If we couldn't get the channel or we never wanted it, default to the call-id */
+       if (!uuid) {
 
                uuid = ast_malloc(pj_strlen(call_id) + 1);
                if (uuid) {
index 25aed15..8643d4d 100644 (file)
@@ -36,6 +36,8 @@ ASTERISK_REGISTER_FILE()
 #include "asterisk/res_hep.h"
 #include "asterisk/module.h"
 #include "asterisk/netsock2.h"
+#include "asterisk/channel.h"
+#include "asterisk/pbx.h"
 #include "asterisk/stasis.h"
 #include "asterisk/rtp_engine.h"
 #include "asterisk/json.h"
@@ -43,6 +45,35 @@ ASTERISK_REGISTER_FILE()
 
 static struct stasis_subscription *stasis_rtp_subscription;
 
+static char *assign_uuid(struct ast_json *json_channel)
+{
+       const char *channel_name = ast_json_string_get(ast_json_object_get(json_channel, "name"));
+       enum hep_uuid_type uuid_type = hepv3_get_uuid_type();
+       char *uuid = NULL;
+
+       if (!channel_name) {
+               return NULL;
+       }
+
+       if (uuid_type == HEP_UUID_TYPE_CALL_ID && ast_begins_with(channel_name, "PJSIP")) {
+               struct ast_channel *chan = ast_channel_get_by_name(channel_name);
+               char buf[128];
+
+               if (chan && !ast_func_read(chan, "CHANNEL(pjsip,call-id)", buf, sizeof(buf))) {
+                       uuid = ast_strdup(buf);
+               }
+
+               ast_channel_cleanup(chan);
+       }
+
+       /* If we couldn't get the call-id or didn't want it, just use the channel name */
+       if (!uuid) {
+               uuid = ast_strdup(channel_name);
+       }
+
+       return uuid;
+}
+
 static void rtcp_message_handler(struct stasis_message *message)
 {
 
@@ -94,7 +125,7 @@ static void rtcp_message_handler(struct stasis_message *message)
        ast_sockaddr_parse(&capture_info->src_addr, ast_json_string_get(from), PARSE_PORT_REQUIRE);
        ast_sockaddr_parse(&capture_info->dst_addr, ast_json_string_get(to), PARSE_PORT_REQUIRE);
 
-       capture_info->uuid = ast_strdup(ast_json_string_get(ast_json_object_get(json_channel, "name")));
+       capture_info->uuid = assign_uuid(json_channel);
        if (!capture_info->uuid) {
                ao2_ref(capture_info, -1);
                return;