summaryrefslogtreecommitdiff
path: root/res/res_pjsip/pjsip_options.c
diff options
context:
space:
mode:
authorAlexei Gradinari <alex2grad@gmail.com>2016-06-22 15:25:23 -0400
committerAlexei Gradinari <alex2grad@gmail.com>2016-06-22 15:29:50 -0400
commit6fa3ed067957e580e208ead7a62a095ac26f5fa9 (patch)
tree7d48f6d6631bcc8ca17f05f18fbd392da414b3f4 /res/res_pjsip/pjsip_options.c
parentaec09d9c09f04c886b15c731faee9f8d4fb9833f (diff)
res_pjsip: improve realtime performance #2
The patch removes updating all Endpoints' status on startup. Instead, only non-qualified aors with static contact and non-qualified non-expired contacts are retrieved from the realtime to update the endpoint status to ONLINE. The endpoint name was added to the contact object to simply find the endpoint that created this contact. The status of endpoints with qualified aors will be updated by 'qualify' functions. ASTERISK-26061 #close Change-Id: Id324c1776fa55d3741e0c5457ecac0304cb1a0df
Diffstat (limited to 'res/res_pjsip/pjsip_options.c')
-rw-r--r--res/res_pjsip/pjsip_options.c128
1 files changed, 127 insertions, 1 deletions
diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c
index 381de3754..dc3bce06f 100644
--- a/res/res_pjsip/pjsip_options.c
+++ b/res/res_pjsip/pjsip_options.c
@@ -330,7 +330,12 @@ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_con
if (endpoint) {
endpoint_local = ao2_bump(endpoint);
} else {
- endpoint_local = find_an_endpoint(contact);
+ if (!ast_strlen_zero(contact->endpoint_name)) {
+ endpoint_local = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", contact->endpoint_name);
+ }
+ if (!endpoint_local) {
+ endpoint_local = find_an_endpoint(contact);
+ }
if (!endpoint_local) {
ast_log(LOG_ERROR, "Unable to find an endpoint to qualify contact %s\n",
contact->uri);
@@ -1240,6 +1245,126 @@ static const struct ast_sorcery_observer observer_callbacks_options = {
.deleted = aor_observer_deleted
};
+static int aor_update_endpoint_state(void *obj, void *arg, int flags)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ const char *endpoint_name = ast_sorcery_object_get_id(endpoint);
+ char *aor = arg;
+ char *endpoint_aor;
+ char *endpoint_aors;
+
+ if (ast_strlen_zero(aor) || ast_strlen_zero(endpoint->aors)) {
+ return 0;
+ }
+
+ endpoint_aors = ast_strdupa(endpoint->aors);
+ while ((endpoint_aor = ast_strip(strsep(&endpoint_aors, ",")))) {
+ if (!strcmp(aor, endpoint_aor)) {
+ if (ast_sip_persistent_endpoint_update_state(endpoint_name, AST_ENDPOINT_ONLINE) == -1) {
+ ast_log(LOG_WARNING, "Unable to find persistent endpoint '%s' for aor '%s'\n",
+ endpoint_name, aor);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int on_aor_update_endpoint_state(void *obj, void *arg, int flags)
+{
+ struct ast_sip_aor *aor = obj;
+ struct ao2_container *endpoints;
+ RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
+ const char *aor_name = ast_sorcery_object_get_id(aor);
+ char *aor_like;
+
+ if (ast_strlen_zero(aor_name)) {
+ return -1;
+ }
+
+ if (aor->permanent_contacts && ((int)(aor->qualify_frequency * 1000)) <= 0) {
+ aor_like = ast_alloca(strlen(aor_name) + 3);
+ sprintf(aor_like, "%%%s%%", aor_name);
+ var = ast_variable_new("aors LIKE", aor_like, "");
+ if (!var) {
+ return -1;
+ }
+ endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
+ "endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var);
+
+ if (endpoints) {
+ /*
+ * Because aors are a string list, we have to use a pattern match but since a simple
+ * pattern match could return an endpoint that has an aor of "aaabccc" when searching
+ * for "abc", we still have to iterate over them to find an exact aor match.
+ */
+ ao2_callback(endpoints, 0, aor_update_endpoint_state, (char *)aor_name);
+ ao2_ref(endpoints, -1);
+ }
+ }
+
+ return 0;
+}
+
+static int contact_update_endpoint_state(void *obj, void *arg, int flags)
+{
+ const struct ast_sip_contact *contact = obj;
+ struct timeval tv = ast_tvnow();
+
+ if (!ast_strlen_zero(contact->endpoint_name) && ((int)(contact->qualify_frequency * 1000)) <= 0 &&
+ contact->expiration_time.tv_sec > tv.tv_sec) {
+
+ if (ast_sip_persistent_endpoint_update_state(contact->endpoint_name, AST_ENDPOINT_ONLINE) == -1) {
+ ast_log(LOG_WARNING, "Unable to find persistent endpoint '%s' for contact '%s/%s'\n",
+ contact->endpoint_name, contact->aor, contact->uri);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static void update_all_unqualified_endpoints(void)
+{
+ struct ao2_container *aors;
+ struct ao2_container *contacts;
+ RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy);
+ RAII_VAR(struct ast_variable *, var_contact, NULL, ast_variables_destroy);
+ RAII_VAR(char *, time_now, NULL, ast_free);
+ struct timeval tv = ast_tvnow();
+
+ if (!(var_aor = ast_variable_new("contact !=", "", ""))) {
+ return;
+ }
+ if (!(var_aor->next = ast_variable_new("qualify_frequency <=", "0", ""))) {
+ return;
+ }
+
+ if (ast_asprintf(&time_now, "%ld", tv.tv_sec) == -1) {
+ return;
+ }
+ if (!(var_contact = ast_variable_new("expiration_time >", time_now, ""))) {
+ return;
+ }
+ if (!(var_contact->next = ast_variable_new("qualify_frequency <=", "0", ""))) {
+ return;
+ }
+
+ aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
+ "aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor);
+ if (aors) {
+ ao2_callback(aors, OBJ_NODATA, on_aor_update_endpoint_state, NULL);
+ ao2_ref(aors, -1);
+ }
+
+ contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
+ "contact", AST_RETRIEVE_FLAG_MULTIPLE, var_contact);
+ if (contacts) {
+ ao2_callback(contacts, OBJ_NODATA, contact_update_endpoint_state, NULL);
+ ao2_ref(contacts, -1);
+ }
+}
+
int ast_res_pjsip_init_options_handling(int reload)
{
static const pj_str_t STR_OPTIONS = { "OPTIONS", 7 };
@@ -1281,6 +1406,7 @@ int ast_res_pjsip_init_options_handling(int reload)
ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify);
ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options));
+ update_all_unqualified_endpoints();
qualify_and_schedule_all();
return 0;