/*! * \brief Retrieve a ast_sip_contact_status object from sorcery creating * one if not found. */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (status) { return status; } status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s\n", contact->uri); return NULL; } status->status = UNKNOWN; status->rtt_start = ast_tv(0, 0); status->rtt = 0; if (ast_sorcery_create(ast_sip_get_sorcery(), status)) { ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n", contact->uri); ao2_ref(status, -1); return NULL; } return status; }
/*! * \internal * \brief Initialize the start time on a contact status so the round * trip time can be calculated upon a valid response. */ static void init_start_time(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; struct ast_sip_contact_status *update; status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n", contact->uri); return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { ast_log(LOG_ERROR, "Unable to copy ast_sip_contact_status for contact %s\n", contact->uri); return; } update->status = status->status; update->last_status = status->last_status; update->rtt = status->rtt; update->rtt_start = ast_tvnow(); if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", contact->uri); } ao2_ref(status, -1); ao2_ref(update, -1); }
/*! * \brief Retrieve a ast_sip_contact_status object from sorcery creating * one if not found. */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; SCOPED_MUTEX(lock, &creation_lock); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (status) { return status; } status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return NULL; } ast_string_field_set(status, uri, contact->uri); status->rtt_start = ast_tv(0, 0); status->rtt = 0; if (ast_sorcery_create(ast_sip_get_sorcery(), status)) { ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n", contact->uri); ao2_ref(status, -1); return NULL; } ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(status->status)); return status; }
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len) { const char *family_prefix = data; size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */ char family[family_len + 1]; char tree[prefix_len + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix); snprintf(family, sizeof(family), "%s/%s", family_prefix, type); if (!(entries = ast_db_gettree_by_prefix(family, tree))) { return; } for (entry = entries; entry; entry = entry->next) { /* The key in the entry includes the family, so we need to strip it out */ const char *key = entry->key + family_len + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(void *, object, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); if (!(json = ast_json_load_string(entry->data, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { return; } ao2_link(objects, object); } }
static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(char *, value, NULL, ast_free_ptr); RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); void *object = NULL; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, id)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id); ao2_cleanup(object); return NULL; } return object; }
/*! * \internal * \brief Initialize the start time on a contact status so the round * trip time can be calculated upon a valid response. */ static void init_start_time(const struct ast_sip_contact *contact) { RAII_VAR(struct ast_sip_contact_status *, status, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact_status *, update, NULL, ao2_cleanup); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n", contact->uri); return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { ast_log(LOG_ERROR, "Unable to copy ast_sip_contact_status for contact %s\n", contact->uri); return; } ast_string_field_set(status, uri, contact->uri); update->status = status->status; update->last_status = status->last_status; update->rtt = status->rtt; update->rtt_start = ast_tvnow(); if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", contact->uri); } }
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[MAX_OBJECT_FIELD * 2 + 3]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri); if (!(contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name))) { return -1; } ast_string_field_set(contact, uri, uri); contact->expiration_time = expiration_time; contact->qualify_frequency = aor->qualify_frequency; contact->authenticate_qualify = aor->authenticate_qualify; if (path_info && aor->support_path) { ast_string_field_set(contact, path, path_info); } if (!ast_strlen_zero(aor->outbound_proxy)) { 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); }
struct ast_mwi_mailbox_object *ast_mwi_mailbox_alloc(const char *mailbox_id) { if (ast_strlen_zero(mailbox_id)) { return NULL; } return ast_sorcery_alloc(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id); }
int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, const char *via_addr, int via_port, const char *call_id, struct ast_sip_endpoint *endpoint) { struct ast_sip_contact *contact; int res; char name[MAX_OBJECT_FIELD * 2 + 3]; char hash[33]; ast_md5_hash(hash, uri); snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name); if (!contact) { return -1; } ast_string_field_set(contact, uri, uri); contact->expiration_time = expiration_time; contact->qualify_frequency = aor->qualify_frequency; contact->qualify_timeout = aor->qualify_timeout; contact->authenticate_qualify = aor->authenticate_qualify; if (path_info && aor->support_path) { ast_string_field_set(contact, path, path_info); } if (!ast_strlen_zero(aor->outbound_proxy)) { 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); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME); } if (!ast_strlen_zero(via_addr)) { ast_string_field_set(contact, via_addr, via_addr); } contact->via_port = via_port; if (!ast_strlen_zero(call_id)) { ast_string_field_set(contact, call_id, call_id); } contact->endpoint = ao2_bump(endpoint); if (endpoint) { ast_string_field_set(contact, endpoint_name, ast_sorcery_object_get_id(endpoint)); } res = ast_sorcery_create(ast_sip_get_sorcery(), contact); ao2_ref(contact, -1); return res; }
/*! \brief Custom handler for permanent URIs */ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_aor *aor = obj; const char *aor_id = ast_sorcery_object_get_id(aor); char *contacts; char *contact_uri; if (ast_strlen_zero(var->value)) { return 0; } contacts = ast_strdupa(var->value); while ((contact_uri = ast_strip(strsep(&contacts, ",")))) { struct ast_sip_contact *contact; struct ast_sip_contact_status *status; char hash[33]; char contact_id[strlen(aor_id) + sizeof(hash) + 2]; if (ast_strlen_zero(contact_uri)) { continue; } if (ast_sip_validate_uri_length(contact_uri)) { ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit: %s\n", contact_uri); return -1; } if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); if (!aor->permanent_contacts) { return -1; } } ast_md5_hash(hash, contact_uri); snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id); if (!contact) { return -1; } ast_string_field_set(contact, uri, contact_uri); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ao2_ref(contact, -1); return -1; } ao2_ref(status, -1); ao2_link(aor->permanent_contacts, contact); ao2_ref(contact, -1); } return 0; }
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; char tree[strlen(regex) + 1]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); regex_t expression; struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (regex[0] == '^') { /* * For performance reasons, try to create an astDB prefix * pattern from the regex to reduce the number of entries * retrieved from astDB for regex to then match. */ if (make_astdb_prefix_pattern(tree, regex)) { return; } } else { tree[0] = '\0'; } if (!(entries = ast_db_gettree(family, tree)) || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) { return; } for (entry = entries; entry; entry = entry->next) { /* The key in the entry includes the family, so we need to strip it out for regex purposes */ const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(void *, object, NULL, ao2_cleanup); RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); if (regexec(&expression, key, 0, NULL, 0)) { continue; } else if (!(json = ast_json_load_string(entry->data, &error)) || (ast_json_to_ast_variables(json, &objset) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { regfree(&expression); return; } ao2_link(objects, object); } regfree(&expression); }
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (!(entries = ast_db_gettree(family, NULL))) { return NULL; } for (entry = entries; entry; entry = entry->next) { const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy); void *object = NULL; if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } if (ast_json_to_ast_variables(json, &existing) != AST_JSON_TO_AST_VARS_CODE_SUCCESS) { return NULL; } existing = sorcery_astdb_filter_objectset(existing, sorcery, type); if (fields && !ast_variable_lists_match(existing, fields, 0)) { continue; } if (!(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, existing)) { ao2_cleanup(object); return NULL; } if (!objects) { return object; } ao2_link(objects, object); ao2_cleanup(object); } return NULL; }
static int create_artificial_endpoint(void) { artificial_endpoint = ast_sorcery_alloc(ast_sip_get_sorcery(), "endpoint", NULL); if (!artificial_endpoint) { return -1; } AST_VECTOR_INIT(&artificial_endpoint->inbound_auths, 1); /* Pushing a bogus value into the vector will ensure that * the proper size of the vector is returned. This value is * not actually used anywhere */ AST_VECTOR_APPEND(&artificial_endpoint->inbound_auths, ast_strdup("artificial-auth")); return 0; }
/*! * \brief Retrieve a ast_sip_contact_status object from sorcery creating * one if not found. */ struct ast_sip_contact_status *ast_res_pjsip_find_or_create_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status; SCOPED_MUTEX(lock, &creation_lock); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (status) { return status; } status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n", contact->aor, contact->uri); return NULL; } ast_string_field_set(status, uri, contact->uri); status->rtt_start = ast_tv(0, 0); status->rtt = 0; if (ast_sorcery_create(ast_sip_get_sorcery(), status)) { ast_log(LOG_ERROR, "Unable to persist ast_sip_contact_status for contact %s\n", contact->uri); ao2_ref(status, -1); return NULL; } /* The permanent contact added after asterisk start should be qualified. */ if (ast_test_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED) && ast_tvzero(contact->expiration_time)) { /* * The FULLY_BOOTED to filter out contacts that already existed when asterisk started. * The zero expiration_time to select only permanent contacts. */ ao2_ref((struct ast_sip_contact *) contact, +1); if (ast_sip_push_task(NULL, qualify_and_schedule_aor_contact, (struct ast_sip_contact *) contact)) { ao2_ref((struct ast_sip_contact *) contact, -1); } } ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, "+1", 1.0, ast_sip_get_contact_status_label(status->status)); return status; }
/*! * \internal * \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) { struct ast_sip_contact_status *status; struct ast_sip_contact_status *update; status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n", contact->uri); return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status for contact %s\n", contact->uri); return; } 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", contact->uri); } ao2_ref(status, -1); ao2_ref(update, -1); }
static struct ast_sip_auth *alloc_artificial_auth(char *default_realm) { struct ast_sip_auth *fake_auth; fake_auth = ast_sorcery_alloc(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, "artificial"); if (!fake_auth) { return NULL; } ast_string_field_set(fake_auth, realm, default_realm); ast_string_field_set(fake_auth, auth_user, ""); ast_string_field_set(fake_auth, auth_pass, ""); fake_auth->type = AST_SIP_AUTH_TYPE_ARTIFICIAL; return fake_auth; }
/*! \brief Custom handler for permanent URIs */ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_aor *aor = obj; const char *aor_id = ast_sorcery_object_get_id(aor); char *contacts; char *contact_uri; if (ast_strlen_zero(var->value)) { return 0; } contacts = ast_strdupa(var->value); while ((contact_uri = strsep(&contacts, ","))) { struct ast_sip_contact *contact; char contact_id[strlen(aor_id) + strlen(contact_uri) + 2 + 1]; if (ast_sip_push_task_synchronous(NULL, permanent_contact_validate, contact_uri)) { ast_log(LOG_ERROR, "Permanent URI on aor '%s' with contact '%s' failed to parse\n", ast_sorcery_object_get_id(aor), contact_uri); return -1; } if (!aor->permanent_contacts) { aor->permanent_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL); if (!aor->permanent_contacts) { return -1; } } snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, contact_uri); contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id); if (!contact) { return -1; } ast_string_field_set(contact, uri, contact_uri); ao2_link(aor->permanent_contacts, contact); ao2_ref(contact, -1); } return 0; }
/*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */ static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree); RAII_VAR(struct ast_json *, criteria, NULL, ast_json_unref); struct ast_db_entry *entry; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (!(entries = ast_db_gettree(family, NULL)) || (fields && !(criteria = sorcery_objectset_to_json(fields)))) { return NULL; } for (entry = entries; entry; entry = entry->next) { const char *key = entry->key + strlen(family) + 2; RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); void *object = NULL; if (!(json = ast_json_load_string(entry->data, &error))) { return NULL; } else if (criteria && !sorcery_json_equal(json, criteria)) { continue; } else if (!(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, key)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ao2_cleanup(object); return NULL; } if (!objects) { return object; } ao2_link(objects, object); ao2_cleanup(object); } return NULL; }
static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields) { const char *family = data; RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy); RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy); void *object = NULL; if (!(objectset = ast_load_realtime_fields(family, fields))) { return NULL; } objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type); if (!id || !(object = ast_sorcery_alloc(sorcery, type, id->value)) || ast_sorcery_objectset_apply(sorcery, object, objectset)) { return NULL; } return object; }
static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id) { const char *prefix = data; char family[strlen(prefix) + strlen(type) + 2]; RAII_VAR(char *, value, NULL, ast_free_ptr); RAII_VAR(struct ast_json *, json, NULL, ast_json_unref); struct ast_json_error error; RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy); void *object = NULL; snprintf(family, sizeof(family), "%s/%s", prefix, type); if (ast_db_get_allocated(family, id, &value) || !(json = ast_json_load_string(value, &error)) || !(objset = sorcery_json_to_objectset(json)) || !(object = ast_sorcery_alloc(sorcery, type, id)) || ast_sorcery_objectset_apply(sorcery, object, objset)) { ao2_cleanup(object); return NULL; } return object; }
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields) { const char *family = data; RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy); RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy); struct ast_category *row = NULL; if (!fields) { char field[strlen(UUID_FIELD) + 6], value[2]; /* If no fields have been specified we want all rows, so trick realtime into doing it */ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD); snprintf(value, sizeof(value), "%%"); if (!(all = ast_variable_new(field, value, ""))) { return; } fields = all; } if (!(rows = ast_load_realtime_multientry_fields(family, fields))) { return; } while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) { struct ast_variable *objectset = ast_category_detach_variables(row); RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy); RAII_VAR(void *, object, NULL, ao2_cleanup); objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type); if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) { ao2_link(objects, object); } ast_variables_destroy(objectset); } }
/*! * \internal * \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) { struct ast_sip_contact_status *status; struct ast_sip_contact_status *update; status = find_or_create_contact_status(contact); if (!status) { return; } update = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(status)); if (!update) { ast_log(LOG_ERROR, "Unable to create update ast_sip_contact_status for contact %s\n", contact->uri); ao2_ref(status, -1); return; } 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 ? ast_tvdiff_us(ast_tvnow(), status->rtt_start) : 0; update->rtt_start = ast_tv(0, 0); if (ast_sorcery_update(ast_sip_get_sorcery(), update)) { ast_log(LOG_ERROR, "Unable to update ast_sip_contact_status for contact %s\n", contact->uri); } ao2_ref(update, -1); ao2_ref(status, -1); }
/*! * \internal * \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, 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); status = ast_res_pjsip_find_or_create_contact_status(contact); if (!status) { ast_log(LOG_ERROR, "Unable to find ast_sip_contact_status for contact %s\n", contact->uri); 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) { ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status for contact %s\n", contact->uri); return; } ast_string_field_set(update, uri, contact->uri); 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", contact->uri); } }
void ast_ari_asterisk_update_object(struct ast_variable *headers, struct ast_ari_asterisk_update_object_args *args, struct ast_ari_response *response) { RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref); RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup); RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup); struct ast_json *fields; struct ast_variable *update_set = NULL; int created = 0; sorcery = ast_sorcery_retrieve_by_module_name(args->config_class); if (!sorcery) { ast_ari_response_error( response, 404, "Not Found", "configClass '%s' not found", args->config_class); return; } object_type = ast_sorcery_get_object_type(sorcery, args->object_type); if (!object_type) { ast_ari_response_error( response, 404, "Not Found", "objectType '%s' not found", args->object_type); return; } sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args->object_type, args->id); if (!sorcery_obj) { ast_debug(5, "Sorcery object '%s' does not exist; creating it\n", args->id); sorcery_obj = ast_sorcery_alloc(sorcery, args->object_type, args->id); if (!sorcery_obj) { ast_ari_response_alloc_failed(response); return; } created = 1; } else { void *copy; copy = ast_sorcery_copy(sorcery, sorcery_obj); if (!copy) { ast_ari_response_alloc_failed(response); return; } ao2_ref(sorcery_obj, -1); sorcery_obj = copy; } fields = ast_json_object_get(args->fields, "fields"); if (!fields && !created) { /* Whoops. We need data. */ ast_ari_response_error( response, 400, "Bad request", "Fields must be provided to update object '%s'", args->id); return; } else if (fields) { size_t i; for (i = 0; i < ast_json_array_size(fields); i++) { struct ast_variable *new_var; struct ast_json *json_value = ast_json_array_get(fields, i); if (!json_value) { continue; } new_var = ast_variable_new( ast_json_string_get(ast_json_object_get(json_value, "attribute")), ast_json_string_get(ast_json_object_get(json_value, "value")), ""); if (!new_var) { ast_variables_destroy(update_set); ast_ari_response_alloc_failed(response); return; } ast_variable_list_append(&update_set, new_var); } } /* APPLY! Note that a NULL update_set is fine (and necessary), as it * will force validation on a newly created object. */ if (ast_sorcery_objectset_apply(sorcery, sorcery_obj, update_set)) { ast_variables_destroy(update_set); ast_ari_response_error( response, 400, "Bad request", "%s of object '%s' failed field value validation", created ? "Creation" : "Update", args->id); return; } ast_variables_destroy(update_set); if (created) { if (ast_sorcery_create(sorcery, sorcery_obj)) { ast_ari_response_error( response, 403, "Forbidden", "Cannot create sorcery objects of type '%s'", args->object_type); return; } } else { if (ast_sorcery_update(sorcery, sorcery_obj)) { ast_ari_response_error( response, 403, "Forbidden", "Cannot update sorcery objects of type '%s'", args->object_type); return; } } return_sorcery_object(sorcery, sorcery_obj, response); }