summaryrefslogtreecommitdiff
path: root/res/res_pjsip
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2016-07-11 10:25:04 -0500
committerRichard Mudgett <rmudgett@digium.com>2016-07-12 11:52:10 -0500
commit97b4c7a5b42eb84eaeaf9ec3f524de40e1d7fd74 (patch)
tree88b5f4397b9bc6b9e885a1b0bf0b391aa5b981ec /res/res_pjsip
parent5ee205d8bb0dfbae5be89661aa3a787fbdf9986b (diff)
res_pjsip: Fix statsd regression.
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
Diffstat (limited to 'res/res_pjsip')
-rw-r--r--res/res_pjsip/pjsip_configuration.c64
-rw-r--r--res/res_pjsip/pjsip_options.c79
2 files changed, 100 insertions, 43 deletions
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 8791816c3..ac07a7534 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -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.
*/
@@ -225,6 +246,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;
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index e220f90e4..7b37a7a18 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -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)
@@ -160,7 +158,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);
@@ -172,6 +170,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) {
@@ -185,22 +203,34 @@ static void update_contact_status(const struct ast_sip_contact *contact,
return;
}
- update->last_status = status->status;
- update->status = value;
+ 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);
+ /*
+ * 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);
+ 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",
@@ -317,10 +347,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);
@@ -376,7 +406,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;
}
@@ -536,7 +566,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);
}
}
@@ -555,8 +585,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);
}
/*!
@@ -585,8 +614,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)
@@ -1062,7 +1091,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);
}
}