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); }
static inline int at_response_cops (pvt_t* pvt, char* str, size_t len) { char* provider_name = at_parse_cops (pvt, str, len); if (provider_name) { ast_string_field_set (pvt, provider_name, provider_name); return 0; } ast_string_field_set (pvt, provider_name, "NONE"); return -1; }
static inline int at_response_cnum (pvt_t* pvt, char* str, size_t len) { char* number = at_parse_cnum (pvt, str, len); if (number) { ast_string_field_set (pvt, number, number); return 0; } ast_string_field_set (pvt, number, "Unknown"); return -1; }
static int end_session(struct respoke_session *session, enum respoke_status status, const struct respoke_message *message) { const char *endpoint, *type, *app; if (!session->channel) { return 0; } endpoint = respoke_message_redirected_endpoint_get(message); type = respoke_message_redirected_type_get(message); app = respoke_message_redirected_app_get(message); if (!ast_strlen_zero(endpoint) && !ast_strlen_zero(app)) { if (session->endpoint->redirect == RESPOKE_REDIRECT_INTERNAL) { char id[AST_UUID_STR_LEN]; /* Since we are changing the session-id and because offer adds this session * to the sessions container we need to unlink it now, which bye does */ respoke_session_bye(session, RESPOKE_STATUS_REDIRECTING); session->terminated = 0; ast_string_field_set(session, remote, endpoint); ast_string_field_set(session, remote_type, S_OR(type, "web")); ast_string_field_set(session, remote_appid, app); ast_string_field_set(session, remote_connection, ""); ast_string_field_set(session, session_id, ast_uuid_generate_str(id, sizeof(id))); /* Send a new offer out to the new target, without the caller being any the wiser */ if (!respoke_session_offer(session)) { return 0; } session->terminated = 1; } else if (session->endpoint->redirect == RESPOKE_REDIRECT_CORE) { ast_channel_call_forward_build(session->channel, "Respoke/%s/%s@%s", ast_sorcery_object_get_id(session->endpoint), endpoint, app); } } ast_set_hangupsource(session->channel, ast_channel_name(session->channel), 0); if (!ast_channel_hangupcause(session->channel)) { int cause = hangup_reason_to_cause(status); ast_queue_hangup_with_cause(session->channel, cause); } else { ast_queue_hangup(session->channel); } return 0; }
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; }
/*! * \internal * \brief Create a ast_sip_contact_status object. */ static void *contact_status_alloc(const char *name) { struct ast_sip_contact_status *status = ast_sorcery_generic_alloc(sizeof(*status), contact_status_destroy); char *id = ast_strdupa(name); char *aor = id; char *aor_separator = NULL; if (!status) { ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status\n"); return NULL; } if (ast_string_field_init(status, 256)) { ast_log(LOG_ERROR, "Unable to allocate ast_sip_contact_status stringfields\n"); ao2_cleanup(status); return NULL; } /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { *aor_separator = '\0'; } ast_assert(aor_separator != NULL); ast_string_field_set(status, aor, aor); status->status = CREATED; return status; }
/*! \brief Allocator for contact */ static void *contact_alloc(const char *name) { struct ast_sip_contact *contact = ast_sorcery_generic_alloc(sizeof(*contact), contact_destroy); char *id = ast_strdupa(name); char *aor = id; char *aor_separator = NULL; if (!contact) { return NULL; } if (ast_string_field_init(contact, 256)) { ao2_cleanup(contact); return NULL; } /* Dynamic contacts are delimited with ";@" and static ones with "@@" */ if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) { *aor_separator = '\0'; } ast_assert(aor_separator != NULL); ast_string_field_set(contact, aor, aor); return contact; }
/*! * \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; }
/*! * \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); } }
static void bridge_config_set_limits_warning_values(struct ast_bridge_config *config, struct ast_bridge_features_limits *limits) { if (config->end_sound) { ast_string_field_set(limits, duration_sound, config->end_sound); } if (config->warning_sound) { ast_string_field_set(limits, warning_sound, config->warning_sound); } if (config->start_sound) { ast_string_field_set(limits, connect_sound, config->start_sound); } limits->frequency = config->warning_freq; limits->warning = config->play_warning; }
struct stasis_app_recording_options *stasis_app_recording_options_create( const char *name, const char *format) { RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup); options = ao2_alloc(sizeof(*options), recording_options_dtor); if (!options || ast_string_field_init(options, 128)) { return NULL; } ast_string_field_set(options, name, name); ast_string_field_set(options, format, format); ao2_ref(options, +1); return options; }
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; }
static struct stasis_subscription_change *subscription_change_alloc(struct stasis_topic *topic, const char *uniqueid, const char *description) { struct stasis_subscription_change *change; change = ao2_alloc(sizeof(struct stasis_subscription_change), subscription_change_dtor); if (!change || ast_string_field_init(change, 128)) { ao2_cleanup(change); return NULL; } ast_string_field_set(change, uniqueid, uniqueid); ast_string_field_set(change, description, description); ao2_ref(topic, +1); change->topic = topic; return change; }
/*! \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; }
/*! * \brief Check authentication using Digest scheme * * This function will check an incoming message against configured authentication * options. If \b any of the incoming Authorization headers result in successful * authentication, then authentication is considered successful. * * \see ast_sip_check_authentication */ static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata) { struct ast_sip_auth **auths; enum digest_verify_result *verify_res; enum ast_sip_check_auth_result res; int i; int failures = 0; size_t auth_size; RAII_VAR(struct ast_sip_endpoint *, artificial_endpoint, ast_sip_get_artificial_endpoint(), ao2_cleanup); auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths); auths = ast_alloca(auth_size * sizeof(*auths)); verify_res = ast_alloca(auth_size * sizeof(*verify_res)); if (!auths) { return AST_SIP_AUTHENTICATION_ERROR; } if (endpoint == artificial_endpoint) { auths[0] = ast_sip_get_artificial_auth(); } else if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) { res = AST_SIP_AUTHENTICATION_ERROR; goto cleanup; } for (i = 0; i < auth_size; ++i) { if (ast_strlen_zero(auths[i]->realm)) { ast_string_field_set(auths[i], realm, "asterisk"); } verify_res[i] = verify(auths[i], rdata, tdata->pool); if (verify_res[i] == AUTH_SUCCESS) { res = AST_SIP_AUTHENTICATION_SUCCESS; goto cleanup; } if (verify_res[i] == AUTH_FAIL) { failures++; } } for (i = 0; i < auth_size; ++i) { challenge(auths[i]->realm, tdata, rdata, verify_res[i] == AUTH_STALE); } if (failures == auth_size) { res = AST_SIP_AUTHENTICATION_FAILED; } else { res = AST_SIP_AUTHENTICATION_CHALLENGE; } cleanup: ast_sip_cleanup_auths(auths, auth_size); return res; }
static int moh_write(struct ast_channel *chan, char *cmd, char *data, const char *value) { if (!depwarning) { depwarning = 1; ast_log(LOG_WARNING, "MUSICCLASS() is deprecated; use CHANNEL(musicclass) instead.\n"); } ast_string_field_set(chan, musicclass, value); return 0; }
static inline int at_response_cgmm (pvt_t* pvt, char* str, attribute_unused size_t len) { ast_string_field_set (pvt, model, str); if (!strcmp (pvt->model, "E1550") || !strcmp (pvt->model, "E1750") || !strcmp (pvt->model, "E160X") || !strcmp (pvt->model, "E171") || !strcmp (pvt->model, "E153")) { pvt->ussd_use_7bit_encoding = 1; pvt->ussd_use_ucs2_decoding = 0; } return 0; }
static inline int at_response_creg (pvt_t* pvt, char* str, size_t len) { int d; char* lac; char* ci; if (at_send_cops (pvt) || at_fifo_queue_add (pvt, CMD_AT_COPS, RES_OK)) { ast_log (LOG_ERROR, "[%s] Error sending query for provider name\n", pvt->id); } if (at_parse_creg (pvt, str, len, &d, &pvt->gsm_reg_status, &lac, &ci)) { ast_verb (1, "[%s] Error parsing CREG: '%.*s'\n", pvt->id, (int) len, str); return 0; } if (d) { pvt->gsm_registered = 1; } else { pvt->gsm_registered = 0; } if (lac) { ast_string_field_set (pvt, location_area_code, lac); } if (ci) { ast_string_field_set (pvt, cell_id, ci); } return 0; }
struct ast_channel *__ast_channel_internal_alloc(void (*destructor)(void *obj), const char *linkedid, const char *file, int line, const char *function) { struct ast_channel *tmp; #if defined(REF_DEBUG) tmp = __ao2_alloc_debug(sizeof(*tmp), destructor, AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 1); #elif defined(__AST_DEBUG_MALLOC) tmp = __ao2_alloc_debug(sizeof(*tmp), destructor, AO2_ALLOC_OPT_LOCK_MUTEX, "", file, line, function, 0); #else tmp = ao2_alloc(sizeof(*tmp), destructor); #endif if ((ast_string_field_init(tmp, 128))) { return ast_channel_unref(tmp); } if (!(tmp->dialed_causes = ao2_container_alloc(DIALED_CAUSES_BUCKETS, pvt_cause_hash_fn, pvt_cause_cmp_fn))) { return ast_channel_unref(tmp); } if (ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_channel_uniqueid_build(tmp, "%li.%d", (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1)); } else { ast_channel_uniqueid_build(tmp, "%s-%li.%d", ast_config_AST_SYSTEM_NAME, (long)time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1)); } if (!ast_strlen_zero(linkedid)) { ast_string_field_set(tmp, linkedid, linkedid); } else { ast_string_field_set(tmp, linkedid, tmp->uniqueid); } return tmp; }
/*! \brief Custom handler for TLS method setting */ static int transport_tls_file_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_transport *transport = obj; RAII_VAR(struct ast_sip_transport_state *, state, find_or_create_temporary_state(transport), ao2_cleanup); if (!state) { return -1; } if (!ast_file_is_readable(var->value)) { ast_log(LOG_ERROR, "Transport: %s: %s %s is either missing or not readable\n", ast_sorcery_object_get_id(obj), var->name, var->value); return -1; } if (!strcasecmp(var->name, "ca_list_file")) { state->tls.ca_list_file = pj_str((char*)var->value); ast_string_field_set(transport, ca_list_file, var->value); } else if (!strcasecmp(var->name, "ca_list_path")) { #ifdef HAVE_PJ_SSL_CERT_LOAD_FROM_FILES2 state->tls.ca_list_path = pj_str((char*)var->value); ast_string_field_set(transport, ca_list_path, var->value); #else ast_log(LOG_WARNING, "Asterisk has been built against a version of pjproject that does not " "support the 'ca_list_path' option. Please upgrade to version 2.4 or later.\n"); #endif } else if (!strcasecmp(var->name, "cert_file")) { state->tls.cert_file = pj_str((char*)var->value); ast_string_field_set(transport, cert_file, var->value); } else if (!strcasecmp(var->name, "priv_key_file")) { state->tls.privkey_file = pj_str((char*)var->value); ast_string_field_set(transport, privkey_file, var->value); } 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) { 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 allocate ast_sip_contact_status for contact %s\n", contact->uri); return; } 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 (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); } }
/*! \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; }
static int register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name, struct ao2_container *contacts) { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; int added = 0, updated = 0, deleted = 0; pjsip_contact_hdr *contact_hdr = NULL; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; RAII_VAR(struct ast_str *, path_str, NULL, ast_free); struct ast_sip_contact *response_contact; char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; pjsip_via_hdr *via_hdr; pjsip_via_hdr *via_hdr_last; char *via_addr = NULL; int via_port = 0; pjsip_cid_hdr *call_id_hdr; char *call_id = NULL; size_t alloc_size; /* So we don't count static contacts against max_contacts we prune them out from the container */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL); if (registrar_validate_contacts(rdata, contacts, aor, &added, &updated, &deleted)) { /* The provided Contact headers do not conform to the specification */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 400, NULL, NULL, NULL); ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided"); ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } if (registrar_validate_path(rdata, aor, &path_str)) { /* Ensure that intervening proxies did not make invalid modifications to the request */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 420, NULL, NULL, NULL); ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } if ((MAX(added - deleted, 0) + (!aor->remove_existing ? ao2_container_count(contacts) : 0)) > aor->max_contacts) { /* Enforce the maximum number of contacts */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n", ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts); return PJ_TRUE; } if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size); } /* Find the first Via header */ via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL); if (via_hdr) { /* Find the last Via header */ while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, via_hdr->next)) != NULL) { via_hdr_last = via_hdr; } alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1; via_addr = ast_alloca(alloc_size); ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size); via_port=via_hdr_last->sent_by.port; } call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); if (call_id_hdr) { alloc_size = pj_strlen(&call_id_hdr->id) + 1; call_id = ast_alloca(alloc_size); ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size); } /* Iterate each provided Contact header and add, update, or delete */ while ((contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; char contact_uri[pjsip_max_url_size]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); if (contact_hdr->star) { /* A star means to unregister everything, so do so for the possible contacts */ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name); break; } if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) { /* This registrar only currently supports sip: and sips: URI schemes */ continue; } expiration = registrar_get_expiration(aor, contact_hdr, rdata); details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) { /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n", contact_uri, aor_name); continue; } if (ast_sip_location_add_contact_nolock(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, user_agent, via_addr, via_port, call_id, endpoint)) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue; } ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_ADDED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, user_agent); } else if (expiration) { struct ast_sip_contact *contact_update; contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact); if (!contact_update) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); continue; } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); contact_update->qualify_frequency = aor->qualify_frequency; contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } if (user_agent) { ast_string_field_set(contact_update, user_agent, user_agent); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME); } if (ast_sip_location_update_contact(contact_update)) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); ast_sip_location_delete_contact(contact); continue; } ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_REFRESHED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, contact_update->user_agent); ao2_cleanup(contact_update); } else { /* We want to report the user agent that was actually in the removed contact */ ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact_uri, aor_name, contact->user_agent); } } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER * do so */ if (aor->remove_existing) { ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL); } /* Re-retrieve contacts. Caller will clean up the original container. */ contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor); response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { ao2_cleanup(response_contact); ao2_cleanup(contacts); return PJ_TRUE; } ao2_cleanup(response_contact); /* Add the date header to the response, some UAs use this to set their date and time */ registrar_add_date_header(tdata); ao2_callback(contacts, 0, registrar_add_contact, tdata); ao2_cleanup(contacts); if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata)); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr); } ast_sip_send_stateful_response(rdata, tdata, endpoint); return PJ_TRUE; }
static void register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name, struct ao2_container *contacts, struct aor_core_response *response) { static const pj_str_t USER_AGENT = { "User-Agent", 10 }; int added = 0; int updated = 0; int deleted = 0; int permanent = 0; int contact_count; struct ao2_container *existing_contacts = NULL; pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; RAII_VAR(struct ast_str *, path_str, NULL, ast_free); struct ast_sip_contact *response_contact; char *user_agent = NULL; pjsip_user_agent_hdr *user_agent_hdr; pjsip_expires_hdr *expires_hdr; pjsip_via_hdr *via_hdr; pjsip_via_hdr *via_hdr_last; char *via_addr = NULL; int via_port = 0; pjsip_cid_hdr *call_id_hdr; char *call_id = NULL; size_t alloc_size; /* We create a single pool and use it throughout this function where we need one */ details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 1024, 256); if (!details.pool) { response->code = 500; return; } /* If there are any permanent contacts configured on the AOR we need to take them * into account when counting contacts. */ if (aor->permanent_contacts) { permanent = ao2_container_count(aor->permanent_contacts); } if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) { /* The provided Contact headers do not conform to the specification */ ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided"); ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n", ast_sorcery_object_get_id(endpoint)); response->code = 400; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } if (registrar_validate_path(rdata, aor, &path_str)) { /* Ensure that intervening proxies did not make invalid modifications to the request */ ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n", ast_sorcery_object_get_id(endpoint)); response->code = 420; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } if (aor->remove_existing) { /* Cumulative number of contacts affected by this registration */ contact_count = MAX(updated + added - deleted, 0); /* We need to keep track of only existing contacts so we can later * remove them if need be. */ existing_contacts = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, ast_sorcery_object_id_compare); if (!existing_contacts) { response->code = 500; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return; } ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts); } else { /* Total contacts after this registration */ contact_count = ao2_container_count(contacts) - permanent + added - deleted; } if (contact_count > aor->max_contacts) { /* Enforce the maximum number of contacts */ ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %u\n", ast_sorcery_object_get_id(endpoint), aor_name, aor->max_contacts); response->code = 403; pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); ao2_cleanup(existing_contacts); return; } user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL); if (user_agent_hdr) { alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1; user_agent = ast_alloca(alloc_size); ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size); } /* Find the first Via header */ via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL); if (via_hdr) { /* Find the last Via header */ while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, via_hdr->next)) != NULL) { via_hdr_last = via_hdr; } alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1; via_addr = ast_alloca(alloc_size); ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size); via_port=via_hdr_last->sent_by.port; } call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL); if (call_id_hdr) { alloc_size = pj_strlen(&call_id_hdr->id) + 1; call_id = ast_alloca(alloc_size); ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size); } /* Iterate each provided Contact header and add, update, or delete */ for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) { int expiration; char contact_uri[pjsip_max_url_size]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); if (contact_hdr->star) { /* A star means to unregister everything, so do so for the possible contacts */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name); /* If we are keeping track of existing contacts for removal then, well, there is * absolutely nothing left so no need to try to remove any. */ if (existing_contacts) { ao2_ref(existing_contacts, -1); existing_contacts = NULL; } break; } if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) { /* This registrar only currently supports sip: and sips: URI schemes */ continue; } expiration = registrar_get_expiration(aor, contact_hdr, rdata); details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details); /* If a contact was returned and we need to keep track of existing contacts then it * should be removed. */ if (contact && existing_contacts) { ao2_unlink(existing_contacts, contact); } if (!contact) { int prune_on_boot; /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n", contact_uri, aor_name); continue; } prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata); contact = ast_sip_location_create_contact(aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)), path_str ? ast_str_buffer(path_str) : NULL, user_agent, via_addr, via_port, call_id, prune_on_boot, endpoint); if (!contact) { ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n", contact_uri, aor_name); continue; } if (prune_on_boot) { const char *contact_name; struct contact_transport_monitor *monitor; /* * Monitor the transport in case it gets disconnected because * the contact won't be valid anymore if that happens. */ contact_name = ast_sorcery_object_get_id(contact); monitor = ao2_alloc_options(sizeof(*monitor) + 2 + strlen(aor_name) + strlen(contact_name), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK); if (monitor) { strcpy(monitor->aor_name, aor_name);/* Safe */ monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; strcpy(monitor->contact_name, contact_name);/* Safe */ ast_sip_transport_monitor_register(rdata->tp_info.transport, register_contact_transport_shutdown_cb, monitor); ao2_ref(monitor, -1); } } ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_ADDED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, user_agent); ao2_link(contacts, contact); } else if (expiration) { struct ast_sip_contact *contact_update; contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact); if (!contact_update) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); continue; } contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); contact_update->qualify_frequency = aor->qualify_frequency; contact_update->authenticate_qualify = aor->authenticate_qualify; if (path_str) { ast_string_field_set(contact_update, path, ast_str_buffer(path_str)); } if (user_agent) { ast_string_field_set(contact_update, user_agent, user_agent); } if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) { ast_string_field_set(contact_update, reg_server, ast_config_AST_SYSTEM_NAME); } if (ast_sip_location_update_contact(contact_update)) { ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n", contact->uri, expiration); ast_sip_location_delete_contact(contact); continue; } ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_REFRESHED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d\r\n" "UserAgent: %s", contact_uri, aor_name, expiration, contact_update->user_agent); ao2_link(contacts, contact_update); ao2_cleanup(contact_update); } else { if (contact->prune_on_boot) { struct contact_transport_monitor *monitor; const char *contact_name = ast_sorcery_object_get_id(contact); monitor = ast_alloca(sizeof(*monitor) + 2 + strlen(aor_name) + strlen(contact_name)); strcpy(monitor->aor_name, aor_name);/* Safe */ monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1; strcpy(monitor->contact_name, contact_name);/* Safe */ ast_sip_transport_monitor_unregister(rdata->tp_info.transport, register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher); } /* We want to report the user agent that was actually in the removed contact */ ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s\r\n" "UserAgent: %s", contact_uri, aor_name, contact->user_agent); } } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); /* * If the AOR is configured to remove any contacts over max_contacts * that have not been updated/added/deleted as a result of this * REGISTER do so. * * The existing contacts container holds all contacts that were not * involved in this REGISTER. * The contacts container holds the current contacts of the AOR. */ if (aor->remove_existing && existing_contacts) { /* Total contacts after this registration */ contact_count = ao2_container_count(existing_contacts) + updated + added; if (contact_count > aor->max_contacts) { /* Remove excess existing contacts that expire the soonest */ remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts); } ao2_ref(existing_contacts, -1); } response_contact = ao2_callback(contacts, 0, NULL, NULL); /* Send a response containing all of the contacts (including static) that are present on this AOR */ if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) { ao2_cleanup(response_contact); ao2_cleanup(contacts); response->code = 500; return; } ao2_cleanup(response_contact); /* Add the date header to the response, some UAs use this to set their date and time */ registrar_add_date_header(tdata); ao2_callback(contacts, 0, registrar_add_contact, tdata); if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) { expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata)); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr); } response->tdata = tdata; }
static inline int at_response_cimi (pvt_t* pvt, char* str, attribute_unused size_t len) { ast_string_field_set (pvt, imsi, str); return 0; }
static inline int at_response_cgmr (pvt_t* pvt, char* str, attribute_unused size_t len) { ast_string_field_set (pvt, firmware, str); return 0; }
struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan) { struct ast_channel_snapshot *snapshot; struct ast_bridge *bridge; char nativeformats[256]; struct ast_str *write_transpath = ast_str_alloca(256); struct ast_str *read_transpath = ast_str_alloca(256); struct ast_party_id effective_connected_id; struct ast_callid *callid; /* no snapshots for dummy channels */ if (!ast_channel_tech(chan)) { return NULL; } snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor); if (!snapshot || ast_string_field_init(snapshot, 1024)) { ao2_cleanup(snapshot); return NULL; } ast_string_field_set(snapshot, name, ast_channel_name(chan)); ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type); ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan)); ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan)); ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan)); ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan)); ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan)); ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan)); if (ast_channel_appl(chan)) { ast_string_field_set(snapshot, appl, ast_channel_appl(chan)); } if (ast_channel_data(chan)) { ast_string_field_set(snapshot, data, ast_channel_data(chan)); } ast_string_field_set(snapshot, context, ast_channel_context(chan)); ast_string_field_set(snapshot, exten, ast_channel_exten(chan)); ast_string_field_set(snapshot, caller_name, S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, "")); ast_string_field_set(snapshot, caller_number, S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, "")); ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); ast_string_field_set(snapshot, caller_subaddr, S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, "")); ast_string_field_set(snapshot, dialed_subaddr, S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, "")); ast_string_field_set(snapshot, caller_ani, S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, "")); ast_string_field_set(snapshot, caller_rdnis, S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, "")); ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, "")); ast_string_field_set(snapshot, connected_name, S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, "")); ast_string_field_set(snapshot, connected_number, S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, "")); ast_string_field_set(snapshot, language, ast_channel_language(chan)); if ((bridge = ast_channel_get_bridge(chan))) { ast_string_field_set(snapshot, bridgeid, bridge->uniqueid); ao2_cleanup(bridge); } ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats), ast_channel_nativeformats(chan))); ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan))); ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan))); ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath)); ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath)); effective_connected_id = ast_channel_connected_effective_id(chan); ast_string_field_set(snapshot, effective_name, S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, "")); ast_string_field_set(snapshot, effective_number, S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, "")); if ((callid = ast_channel_callid(chan))) { ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid); ast_callid_unref(callid); } snapshot->creationtime = ast_channel_creationtime(chan); snapshot->hanguptime = *(ast_channel_whentohangup(chan)); snapshot->state = ast_channel_state(chan); snapshot->priority = ast_channel_priority(chan); snapshot->amaflags = ast_channel_amaflags(chan); snapshot->hangupcause = ast_channel_hangupcause(chan); ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF); snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id); snapshot->callgroup = ast_channel_callgroup(chan); snapshot->pickupgroup = ast_channel_pickupgroup(chan); ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan)); snapshot->manager_vars = ast_channel_get_manager_vars(chan); snapshot->channel_vars = ast_channel_get_vars(chan); snapshot->tech_properties = ast_channel_tech(chan)->properties; return snapshot; }
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event) { struct varshead *headp; struct ast_var_t *newvariable; char timebuf[30]; struct ast_channel *tchan; struct ast_cel_event_record record = { .version = AST_CEL_EVENT_RECORD_VERSION, }; /* do not call ast_channel_alloc because this is not really a real channel */ if (!(tchan = ast_dummy_channel_alloc())) { return NULL; } headp = &tchan->varshead; /* first, get the variables from the event */ if (ast_cel_fill_record(event, &record)) { ast_channel_release(tchan); return NULL; } /* next, fill the channel with their data */ if ((newvariable = ast_var_assign("eventtype", record.event_name))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if (ast_strlen_zero(cel_dateformat)) { snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec, (long) record.event_time.tv_usec); } else { struct ast_tm tm; ast_localtime(&record.event_time, &tm, NULL); ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm); } if ((newvariable = ast_var_assign("eventtime", timebuf))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } if ((newvariable = ast_var_assign("eventextra", record.extra))) { AST_LIST_INSERT_HEAD(headp, newvariable, entries); } tchan->caller.id.name.valid = 1; tchan->caller.id.name.str = ast_strdup(record.caller_id_name); tchan->caller.id.number.valid = 1; tchan->caller.id.number.str = ast_strdup(record.caller_id_num); tchan->caller.ani.number.valid = 1; tchan->caller.ani.number.str = ast_strdup(record.caller_id_ani); tchan->redirecting.from.number.valid = 1; tchan->redirecting.from.number.str = ast_strdup(record.caller_id_rdnis); tchan->dialed.number.str = ast_strdup(record.caller_id_dnid); ast_copy_string(tchan->exten, record.extension, sizeof(tchan->exten)); ast_copy_string(tchan->context, record.context, sizeof(tchan->context)); ast_string_field_set(tchan, name, record.channel_name); ast_string_field_set(tchan, uniqueid, record.unique_id); ast_string_field_set(tchan, linkedid, record.linked_id); ast_string_field_set(tchan, accountcode, record.account_code); ast_string_field_set(tchan, peeraccount, record.peer_account); ast_string_field_set(tchan, userfield, record.user_field); pbx_builtin_setvar_helper(tchan, "BRIDGEPEER", record.peer); tchan->appl = ast_strdup(record.application_name); tchan->data = ast_strdup(record.application_data); tchan->amaflags = record.amaflag; return tchan; }
/*! * \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); } }