]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Fix statsd regression. 76/3176/1
authorRichard Mudgett <rmudgett@digium.com>
Mon, 11 Jul 2016 15:25:04 +0000 (10:25 -0500)
committerRichard Mudgett <rmudgett@digium.com>
Tue, 12 Jul 2016 17:03:20 +0000 (12:03 -0500)
The ASTERISK-25904 change-id I8fad8aae9305481469c38d2146e1ba3a56d3108f
patch introduced several regressions when the newly created "Updated"
state goes out for each endpoint registration refresh.

1) It restarted any OPTIONS RTT ping cycle.

2) It would interfere with a currently active ping and throw off that
ping's resulting RTT calculation.

3) It cleared the RTT time each time the endpoint was refreshed.

4) The cleared RTT time was sent out as a statsd update each time.

5) It created two AMI events for each update.

* Revert the original patch and reimplement it.  Now the current contact
status state is re-sent instead of the state being momentarily toggled
every time the endpoint refreshes its registration.  The statsd events are
not created for the re-sent refresh because they are sent after every
OPTIONS ping.

ASTERISK-26160 #close
Reported by: Matt Jordan

Change-Id: Ie072be790fbb2a8f5c1c874266e4143fa31f66d1

CHANGES
include/asterisk/res_pjsip.h
res/res_pjsip/pjsip_configuration.c
res/res_pjsip/pjsip_options.c

diff --git a/CHANGES b/CHANGES
index 6e6bec6d07a68b22a2b8612af3ce592499da7b11..cbe03fd3e54ee2d1145ed39c80370e9975017114 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -397,8 +397,6 @@ res_pjsip
     "contact_deny" - List of Contact header addresses to deny
     "contact_permit" - List of Contact header addresses to permit
 
- * Added new status Updated to AMI event ContactStatus on update registration
-
  * Added "reg_server" to contacts.
    If the Asterisk system name is set in asterisk.conf, it will be stored
    into the "reg_server" field in the ps_contacts table to facilitate
index f9f9e2037ebf4ea7f7d1e19d1563687522571e2f..f43a11cb04f4a434e690937386b25b738084c501 100644 (file)
@@ -271,7 +271,6 @@ enum ast_sip_contact_status_type {
        UNKNOWN,
        CREATED,
        REMOVED,
-       UPDATED,
 };
 
 /*!
@@ -296,6 +295,8 @@ struct ast_sip_contact_status {
        int64_t rtt;
        /*! Last status for a contact (default - unavailable) */
        enum ast_sip_contact_status_type last_status;
+       /*! TRUE if the contact was refreshed. e.g., re-registered */
+       unsigned int refresh:1;
 };
 
 /*!
index 8a5ff416ad6a09ce0a65257528a4fda65430f920..6890cedf0a857cb9f2012b57fc678a80331ad7e8 100644 (file)
@@ -105,6 +105,40 @@ static void endpoint_update_state(struct ast_endpoint *endpoint, enum ast_endpoi
        ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint));
 }
 
+static void endpoint_publish_contact_status(struct ast_endpoint *endpoint, struct ast_sip_contact_status *contact)
+{
+       struct ast_json *blob;
+       char rtt[32];
+
+       snprintf(rtt, sizeof(rtt), "%" PRId64, contact->rtt);
+       blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
+               "contact_status", ast_sip_get_contact_status_label(contact->status),
+               "aor", contact->aor,
+               "uri", contact->uri,
+               "roundtrip_usec", rtt,
+               "endpoint_name", ast_endpoint_get_resource(endpoint));
+       if (blob) {
+               ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
+               ast_json_unref(blob);
+       }
+}
+
+/*! \brief Callback function for publishing the status of an endpoint */
+static int persistent_endpoint_publish_status(void *obj, void *arg, int flags)
+{
+       struct sip_persistent_endpoint *persistent = obj;
+       struct ast_endpoint *endpoint = persistent->endpoint;
+       struct ast_sip_contact_status *status = arg;
+
+       /* If the status' aor isn't one of the endpoint's, we skip */
+       if (!strstr(persistent->aors, status->aor)) {
+               return 0;
+       }
+
+       endpoint_publish_contact_status(endpoint, status);
+       return 0;
+}
+
 /*! \brief Callback function for changing the state of an endpoint */
 static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
 {
@@ -112,30 +146,17 @@ static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
        struct ast_endpoint *endpoint = persistent->endpoint;
        struct ast_sip_contact_status *status = arg;
        struct ao2_container *contacts;
-       struct ast_json *blob;
        struct ao2_iterator i;
        struct ast_sip_contact *contact;
        enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
 
-       if (status) {
-               char rtt[32];
-
-               /* If the status' aor isn't one of the endpoint's, we skip */
-               if (!strstr(persistent->aors, status->aor)) {
-                       return 0;
-               }
-
-               snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt);
-               blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
-                       "contact_status", ast_sip_get_contact_status_label(status->status),
-                       "aor", status->aor,
-                       "uri", status->uri,
-                       "roundtrip_usec", rtt,
-                       "endpoint_name", ast_endpoint_get_resource(endpoint));
-               ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
-               ast_json_unref(blob);
+       /* If the status' aor isn't one of the endpoint's, we skip */
+       if (!strstr(persistent->aors, status->aor)) {
+               return 0;
        }
 
+       endpoint_publish_contact_status(endpoint, status);
+
        /* Find all the contacts for this endpoint.  If ANY are available,
         * mark the endpoint as ONLINE.
         */
@@ -222,6 +243,13 @@ static void persistent_endpoint_contact_status_observer(const void *object)
 {
        struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object;
 
+       if (contact_status->refresh) {
+               /* We are only re-publishing the contact status. */
+               ao2_callback(persistent_endpoints, OBJ_NODATA,
+                       persistent_endpoint_publish_status, contact_status);
+               return;
+       }
+
        /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
        if (contact_status->rtt_start.tv_sec > 0) {
                return;
index dc3bce06f1d23e15476f97954cb1e626c3fa607f..808ee171a1c53749cc6b4abce3dfff5a60233862 100644 (file)
@@ -43,7 +43,6 @@ static const char *status_map [] = {
        [UNKNOWN] = "Unknown",
        [CREATED] = "Created",
        [REMOVED] = "Removed",
-       [UPDATED] = "Updated",
 };
 
 static const char *short_status_map [] = {
@@ -52,7 +51,6 @@ static const char *short_status_map [] = {
        [UNKNOWN] = "Unknown",
        [CREATED] = "Created",
        [REMOVED] = "Removed",
-       [UPDATED] = "Updated",
 };
 
 const char *ast_sip_get_contact_status_label(const enum ast_sip_contact_status_type status)
@@ -157,7 +155,7 @@ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const
  * \brief Update an ast_sip_contact_status's elements.
  */
 static void update_contact_status(const struct ast_sip_contact *contact,
-       enum ast_sip_contact_status_type value)
+       enum ast_sip_contact_status_type value, int is_contact_refresh)
 {
        RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup);
        RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup);
@@ -169,6 +167,26 @@ static void update_contact_status(const struct ast_sip_contact *contact,
                return;
        }
 
+       if (is_contact_refresh
+               && status->status == CREATED) {
+               /*
+                * The contact status hasn't been updated since creation
+                * and we don't want to re-send a created status.
+                */
+               if (contact->qualify_frequency
+                       || status->rtt_start.tv_sec > 0) {
+                       /* Ignore, the status will change soon. */
+                       return;
+               }
+
+               /*
+                * Convert to a regular contact status update
+                * because the status may never change.
+                */
+               is_contact_refresh = 0;
+               value = UNKNOWN;
+       }
+
        update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
                ast_sorcery_object_get_id(status));
        if (!update) {
@@ -178,22 +196,35 @@ static void update_contact_status(const struct ast_sip_contact *contact,
        }
 
        ast_string_field_set(update, uri, contact->uri);
-       update->last_status = status->status;
-       update->status = value;
-
-       /* if the contact is available calculate the rtt as
-          the diff between the last start time and "now" */
-       update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0 ?
-               ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0;
-       update->rtt_start = ast_tv(0, 0);
-
-       ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
-               "Contact: %s\r\n"
-               "Status: %s\r\n"
-               "RTT: %" PRId64,
-               ast_sorcery_object_get_id(update),
-               ast_sip_get_contact_status_label(update->status),
-               update->rtt);
+
+       if (is_contact_refresh) {
+               /* Copy everything just to set the refresh flag. */
+               update->status = status->status;
+               update->last_status = status->last_status;
+               update->rtt = status->rtt;
+               update->rtt_start = status->rtt_start;
+               update->refresh = 1;
+       } else {
+               update->last_status = status->status;
+               update->status = value;
+
+               /*
+                * if the contact is available calculate the rtt as
+                * the diff between the last start time and "now"
+                */
+               update->rtt = update->status == AVAILABLE && status->rtt_start.tv_sec > 0
+                       ? ast_tvdiff_us(ast_tvnow(), status->rtt_start)
+                       : 0;
+               update->rtt_start = ast_tv(0, 0);
+
+               ast_test_suite_event_notify("AOR_CONTACT_QUALIFY_RESULT",
+                       "Contact: %s\r\n"
+                       "Status: %s\r\n"
+                       "RTT: %" PRId64,
+                       ast_sorcery_object_get_id(update),
+                       ast_sip_get_contact_status_label(update->status),
+                       update->rtt);
+       }
 
        if (ast_sorcery_update(ast_sip_get_sorcery(), update)) {
                ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n",
@@ -306,10 +337,10 @@ static void qualify_contact_cb(void *token, pjsip_event *e)
                /* Fall through */
        case PJSIP_EVENT_TRANSPORT_ERROR:
        case PJSIP_EVENT_TIMER:
-               update_contact_status(contact, UNAVAILABLE);
+               update_contact_status(contact, UNAVAILABLE, 0);
                break;
        case PJSIP_EVENT_RX_MSG:
-               update_contact_status(contact, AVAILABLE);
+               update_contact_status(contact, AVAILABLE, 0);
                break;
        }
        ao2_cleanup(contact);
@@ -365,7 +396,7 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con
                != PJ_SUCCESS) {
                ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n",
                        contact->uri);
-               update_contact_status(contact, UNAVAILABLE);
+               update_contact_status(contact, UNAVAILABLE, 0);
                ao2_ref(contact, -1);
                return -1;
        }
@@ -525,7 +556,7 @@ static void qualify_and_schedule(struct ast_sip_contact *contact)
 
                schedule_qualify(contact, contact->qualify_frequency * 1000);
        } else {
-               update_contact_status(contact, UNKNOWN);
+               update_contact_status(contact, UNKNOWN, 0);
        }
 }
 
@@ -544,8 +575,7 @@ static void contact_created(const void *obj)
  */
 static void contact_updated(const void *obj)
 {
-       update_contact_status((struct ast_sip_contact *) obj, UPDATED);
-       qualify_and_schedule((struct ast_sip_contact *) obj);
+       update_contact_status(obj, AVAILABLE, 1);
 }
 
 /*!
@@ -574,8 +604,8 @@ static void contact_deleted(const void *obj)
 
 static const struct ast_sorcery_observer contact_observer = {
        .created = contact_created,
+       .updated = contact_updated,
        .deleted = contact_deleted,
-       .updated = contact_updated
 };
 
 static pj_bool_t options_start(void)
@@ -1051,7 +1081,7 @@ static void qualify_and_schedule_contact(struct ast_sip_contact *contact)
        if (contact->qualify_frequency) {
                schedule_qualify(contact, initial_interval);
        } else {
-               update_contact_status(contact, UNKNOWN);
+               update_contact_status(contact, UNKNOWN, 0);
        }
 }