static struct ast_sip_endpoint *username_identify(pjsip_rx_data *rdata) { char endpoint_name[64], domain_name[64], id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (get_endpoint_details(rdata, endpoint_name, sizeof(endpoint_name), domain_name, sizeof(domain_name))) { return NULL; } /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } /* See if an alias exists for the domain provided */ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } } /* See if the transport this came in on has a provided domain */ if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) && (transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "%s@%s", endpoint_name, transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } } /* Fall back to no domain */ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name); done: if (endpoint) { if (!(endpoint->ident_method & AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME)) { ao2_ref(endpoint, -1); return NULL; } ast_debug(3, "Retrieved endpoint %s\n", ast_sorcery_object_get_id(endpoint)); } else { ast_debug(3, "Could not identify endpoint by username '%s'\n", endpoint_name); } return endpoint; }
static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami) { RAII_VAR(struct ast_str *, buf, NULL, ast_free); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (ast_strlen_zero(endpoint->transport)) { return 0; } buf = ast_sip_create_ami_event("TransportDetail", ami); if (!buf) { return -1; } transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", endpoint->transport); if (!transport) { astman_send_error_va(ami->s, ami->m, "Unable to retrieve " "transport %s\n", endpoint->transport); return -1; } sip_transport_to_ami(transport, &buf); ast_str_append(&buf, 0, "EndpointName: %s\r\n", ast_sorcery_object_get_id(endpoint)); astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; 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; 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; }
static int format_contact_status(void *obj, void *arg, int flags) { struct ast_sip_contact_wrapper *wrapper = obj; struct ast_sip_contact *contact = wrapper->contact; struct ast_sip_ami *ami = arg; struct ast_sip_contact_status *status; struct ast_str *buf; const struct ast_sip_endpoint *endpoint = ami->arg; buf = ast_sip_create_ami_event("ContactStatusDetail", ami); if (!buf) { return -1; } status = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id); ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); if (status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); } else { ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); } ast_str_append(&buf, 0, "EndpointName: %s\r\n", ast_sorcery_object_get_id(endpoint)); astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; ast_free(buf); ao2_cleanup(status); return 0; }
static int cli_contact_print_body(void *obj, void *arg, int flags) { struct ast_sip_contact_wrapper *wrapper = obj; struct ast_sip_contact *contact = wrapper->contact; struct ast_sip_cli_context *context = arg; int indent; int flexwidth; const char *contact_id = ast_sorcery_object_get_id(contact); const char *hash_start = contact_id + strlen(contact->aor) + 2; struct ast_sip_contact_status *status; ast_assert(contact->uri != NULL); ast_assert(context->output_buffer != NULL); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, contact_id); indent = CLI_INDENT_TO_SPACES(context->indent_level); flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1; ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-10.10s %-7.7s %11.3f\n", indent, "Contact", contact->aor, flexwidth, flexwidth, contact->uri, hash_start, ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN), (status && (status->status != UNKNOWN) ? ((long long) status->rtt) / 1000.0 : NAN)); ao2_cleanup(status); return 0; }
static int get_write_timeout(void) { int write_timeout = -1; struct ao2_container *transport_states; transport_states = ast_sip_get_transport_states(); if (transport_states) { struct ao2_iterator it_transport_states = ao2_iterator_init(transport_states, 0); struct ast_sip_transport_state *transport_state; for (; (transport_state = ao2_iterator_next(&it_transport_states)); ao2_cleanup(transport_state)) { struct ast_sip_transport *transport; if (transport_state->type != AST_TRANSPORT_WS && transport_state->type != AST_TRANSPORT_WSS) { continue; } transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id); ast_debug(5, "Found %s transport with write timeout: %d\n", transport->type == AST_TRANSPORT_WS ? "WS" : "WSS", transport->write_timeout); write_timeout = MAX(write_timeout, transport->write_timeout); } ao2_iterator_destroy(&it_transport_states); ao2_cleanup(transport_states); } if (write_timeout < 0) { write_timeout = AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT; } ast_debug(1, "Write timeout for WS/WSS transports: %d\n", write_timeout); return write_timeout; }
/*! * \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; }
const struct ast_mwi_mailbox_object *ast_mwi_mailbox_get(const char *mailbox_id) { if (ast_strlen_zero(mailbox_id)) { return NULL; } return ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id); }
static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) { char domain_name[64], id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transports, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) { return NULL; } /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "anonymous@%s", domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } /* See if an alias exists for the domain provided */ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { snprintf(id, sizeof(id), "anonymous@%s", alias->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } } /* See if the transport this came in on has a provided domain */ if ((transports = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "transport", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL)) && (transport = ao2_callback(transports, 0, find_transport_in_use, rdata)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { goto done; } } /* Fall back to no domain */ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous"); done: if (endpoint) { ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint)); } return endpoint; }
int ast_sip_format_contact_ami(void *obj, void *arg, int flags) { struct ast_sip_contact_wrapper *wrapper = obj; struct ast_sip_contact *contact = wrapper->contact; struct ast_sip_ami *ami = arg; struct ast_sip_contact_status *status; struct ast_str *buf; const struct ast_sip_endpoint *endpoint = ami->arg; buf = ast_sip_create_ami_event("ContactStatusDetail", ami); if (!buf) { return -1; } status = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); ast_str_append(&buf, 0, "AOR: %s\r\n", wrapper->aor_id); ast_str_append(&buf, 0, "URI: %s\r\n", contact->uri); ast_str_append(&buf, 0, "UserAgent: %s\r\n", contact->user_agent); ast_str_append(&buf, 0, "RegExpire: %ld\r\n", contact->expiration_time.tv_sec); if (!ast_strlen_zero(contact->via_addr)) { ast_str_append(&buf, 0, "ViaAddress: %s", contact->via_addr); if (contact->via_port) { ast_str_append(&buf, 0, ":%d", contact->via_port); } ast_str_append(&buf, 0, "\r\n"); } if (!ast_strlen_zero(contact->call_id)) { ast_str_append(&buf, 0, "CallID: %s\r\n", contact->call_id); } ast_str_append(&buf, 0, "Status: %s\r\n", ast_sip_get_contact_status_label(status->status)); if (status->status == UNKNOWN) { ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); } else { ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); } ast_str_append(&buf, 0, "EndpointName: %s\r\n", endpoint ? ast_sorcery_object_get_id(endpoint) : S_OR(contact->endpoint_name, "")); ast_str_append(&buf, 0, "ID: %s\r\n", ast_sorcery_object_get_id(contact)); ast_str_append(&buf, 0, "AuthenticateQualify: %d\r\n", contact->authenticate_qualify); ast_str_append(&buf, 0, "OutboundProxy: %s\r\n", contact->outbound_proxy); ast_str_append(&buf, 0, "Path: %s\r\n", contact->path); ast_str_append(&buf, 0, "QualifyFrequency: %u\r\n", contact->qualify_frequency); ast_str_append(&buf, 0, "QualifyTimeout: %.3f\r\n", contact->qualify_timeout); astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); ami->count++; ast_free(buf); ao2_cleanup(status); return 0; }
int ast_sip_location_delete_contact(struct ast_sip_contact *contact) { void *contact_status_obj; contact_status_obj = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (contact_status_obj) { ast_sorcery_delete(ast_sip_get_sorcery(), contact_status_obj); ao2_ref(contact_status_obj, -1); } return ast_sorcery_delete(ast_sip_get_sorcery(), contact); }
static void delete_contact_status(const struct ast_sip_contact *contact) { struct ast_sip_contact_status *status = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { return; } ast_sorcery_delete(ast_sip_get_sorcery(), status); ao2_ref(status, -1); }
static struct ast_sip_endpoint *anonymous_identify(pjsip_rx_data *rdata) { char domain_name[DOMAIN_NAME_LEN + 1]; struct ast_sip_endpoint *endpoint; if (get_endpoint_details(rdata, domain_name, sizeof(domain_name))) { return NULL; } if (!ast_sip_get_disable_multi_domain()) { struct ast_sip_domain_alias *alias; struct ao2_container *transport_states; struct ast_sip_transport_state *transport_state = NULL; struct ast_sip_transport *transport = NULL; char id[sizeof("anonymous@") + DOMAIN_NAME_LEN]; /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "anonymous@%s", domain_name); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); if (endpoint) { goto done; } /* See if an alias exists for the domain provided */ alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name); if (alias) { snprintf(id, sizeof(id), "anonymous@%s", alias->domain); ao2_ref(alias, -1); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); if (endpoint) { goto done; } } /* See if the transport this came in on has a provided domain */ if ((transport_states = ast_sip_get_transport_states()) && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id); } ao2_cleanup(transport); ao2_cleanup(transport_state); ao2_cleanup(transport_states); if (endpoint) { goto done; } } /* Fall back to no domain */ endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", "anonymous"); done: if (endpoint) { ast_debug(3, "Retrieved anonymous endpoint '%s'\n", ast_sorcery_object_get_id(endpoint)); } return endpoint; }
static char *find_aor_name(const char *username, const char *domain, const char *aors) { char *configured_aors; char *aors_buf; char *aor_name; char *id_domain; struct ast_sip_domain_alias *alias; id_domain = ast_alloca(strlen(username) + strlen(domain) + 2); sprintf(id_domain, "%s@%s", username, domain); aors_buf = ast_strdupa(aors); /* Look for exact match on username@domain */ configured_aors = aors_buf; while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, id_domain)) { return ast_strdup(aor_name); } } /* If there's a domain alias, look for exact match on username@domain_alias */ alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain); if (alias) { char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2); sprintf(id_domain, "%s@%s", username, alias->domain); ao2_cleanup(alias); configured_aors = strcpy(aors_buf, aors);/* Safe */ while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, id_domain_alias)) { return ast_strdup(aor_name); } } } if (ast_strlen_zero(username)) { /* No username, no match */ return NULL; } /* Look for exact match on username only */ configured_aors = strcpy(aors_buf, aors);/* Safe */ while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) { if (match_aor(aor_name, username)) { return ast_strdup(aor_name); } } return NULL; }
/*! * \internal * \brief Attempt to qualify the contact * * \details Sends a SIP OPTIONS request to the given contact in order to make * sure that contact is available. */ static int qualify_contact(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact) { pjsip_tx_data *tdata; RAII_VAR(struct ast_sip_endpoint *, endpoint_local, NULL, ao2_cleanup); if (endpoint) { endpoint_local = ao2_bump(endpoint); } else { 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_WARNING, "Unable to find an endpoint to qualify contact %s. Deleting this contact\n", contact->uri); contact_deleted(contact); return -1; } } if (ast_sip_create_request("OPTIONS", NULL, endpoint_local, NULL, contact, &tdata)) { ast_log(LOG_ERROR, "Unable to create request to qualify contact %s\n", contact->uri); return -1; } /* If an outbound proxy is specified set it on this request */ if (!ast_strlen_zero(contact->outbound_proxy) && ast_sip_set_outbound_proxy(tdata, contact->outbound_proxy)) { pjsip_tx_data_dec_ref(tdata); ast_log(LOG_ERROR, "Unable to apply outbound proxy on request to qualify contact %s\n", contact->uri); return -1; } init_start_time(contact); ao2_ref(contact, +1); if (ast_sip_send_out_of_dialog_request(tdata, endpoint_local, (int)(contact->qualify_timeout * 1000), contact, qualify_contact_cb) != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send request to qualify contact %s\n", contact->uri); update_contact_status(contact, UNAVAILABLE, 0); ao2_ref(contact, -1); return -1; } return 0; }
static struct ast_sip_aor *find_aor(struct ast_sip_endpoint *endpoint, pjsip_uri *uri) { char *configured_aors, *aor_name; pjsip_sip_uri *sip_uri; char *domain_name; RAII_VAR(struct ast_str *, id, NULL, ast_free); if (ast_strlen_zero(endpoint->aors)) { return NULL; } sip_uri = pjsip_uri_get_uri(uri); domain_name = ast_alloca(sip_uri->host.slen + 1); ast_copy_pj_str(domain_name, &sip_uri->host, sip_uri->host.slen + 1); configured_aors = ast_strdupa(endpoint->aors); /* Iterate the configured AORs to see if the user or the user+domain match */ while ((aor_name = strsep(&configured_aors, ","))) { struct ast_sip_domain_alias *alias = NULL; if (!pj_strcmp2(&sip_uri->user, aor_name)) { break; } if (!id && !(id = ast_str_create(sip_uri->user.slen + sip_uri->host.slen + 2))) { return NULL; } ast_str_set(&id, 0, "%.*s@", (int)sip_uri->user.slen, sip_uri->user.ptr); if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { ast_str_append(&id, 0, "%s", alias->domain); ao2_cleanup(alias); } else { ast_str_append(&id, 0, "%s", domain_name); } if (!strcmp(aor_name, ast_str_buffer(id))) { ast_free(id); break; } } if (ast_strlen_zero(aor_name)) { return NULL; } return ast_sip_location_retrieve_aor(aor_name); }
int ast_mwi_mailbox_update(struct ast_mwi_mailbox_object *mailbox) { const struct ast_mwi_mailbox_object *exists; int res; exists = ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE, ast_sorcery_object_get_id(mailbox)); if (exists) { res = ast_sorcery_update(mwi_sorcery, mailbox); ast_mwi_mailbox_unref(exists); } else { res = ast_sorcery_create(mwi_sorcery, mailbox); } return res; }
/*! * \internal * \brief Retrieves an endpoint if specified in the given 'to' * * Expects the given 'to' to be in one of the following formats: * sip[s]:endpoint[/aor] * sip[s]:endpoint[/uri] * sip[s]:uri <-- will use default outbound endpoint * * If an optional aor is given it will try to find an associated uri * to return. If an optional uri is given then that will be returned, * otherwise uri will be NULL. * * \param to 'From' or 'To' field with possible endpoint * \param uri Optional uri to return */ static struct ast_sip_endpoint* get_outbound_endpoint( const char *to, char **uri) { char *name, *aor_uri; struct ast_sip_endpoint* endpoint; RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); name = ast_strdupa(skip_sip(to)); /* attempt to extract the endpoint name */ if ((aor_uri = strchr(name, '/'))) { /* format was 'endpoint/' */ *aor_uri++ = '\0'; } else if ((aor_uri = strchr(name, '@'))) { /* format was 'endpoint@' - don't use the rest */ *aor_uri = '\0'; } /* at this point, if name is not empty then it might be an endpoint, so try to retrieve it */ if (ast_strlen_zero(name) || !(endpoint = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), "endpoint", name))) { /* an endpoint was not found, so assume sending directly to a uri and use the default outbound endpoint */ *uri = ast_strdup(to); return ast_sip_default_outbound_endpoint(); } *uri = aor_uri; if (*uri) { char *end = strchr(*uri, '>'); if (end) { *end++ = '\0'; } /* if what's in 'uri' is a retrievable aor use the uri on it instead, otherwise assume what's there is already a uri*/ if ((aor = ast_sip_location_retrieve_aor(*uri)) && (contact = ast_sip_location_retrieve_first_aor_contact(aor))) { *uri = (char*)contact->uri; } /* need to copy because underlying uri goes away */ *uri = ast_strdup(*uri); } return endpoint; }
static int ami_sip_qualify(struct mansession *s, const struct message *m) { const char *endpoint_name = astman_get_header(m, "Endpoint"); RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); char *aors; char *aor_name; if (ast_strlen_zero(endpoint_name)) { astman_send_error(s, m, "Endpoint parameter missing."); return 0; } endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name); if (!endpoint) { astman_send_error(s, m, "Unable to retrieve endpoint\n"); return 0; } /* send a qualify for all contacts registered with the endpoint */ if (ast_strlen_zero(endpoint->aors)) { astman_send_error(s, m, "No AoRs configured for endpoint\n"); return 0; } aors = ast_strdupa(endpoint->aors); while ((aor_name = strsep(&aors, ","))) { struct ast_sip_aor *aor; struct ao2_container *contacts; aor = ast_sip_location_retrieve_aor(aor_name); if (!aor) { continue; } contacts = ast_sip_location_retrieve_aor_contacts(aor); if (contacts) { ao2_callback(contacts, OBJ_NODATA, ami_contact_cb, NULL); ao2_ref(contacts, -1); } ao2_ref(aor, -1); } astman_send_ack(s, m, "Endpoint found, will qualify"); 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; }
void ast_ari_asterisk_delete_object(struct ast_variable *headers, struct ast_ari_asterisk_delete_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); 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_ari_response_error( response, 404, "Not Found", "Object with id '%s' not found", args->id); return; } if (ast_sorcery_delete(sorcery, sorcery_obj)) { ast_ari_response_error( response, 403, "Forbidden", "Could not delete object with id '%s'", args->id); return; } ast_ari_response_no_content(response); }
/*! * \internal * \brief A contact has been deleted remove status tracking. */ static void contact_deleted(const void *obj) { struct ast_sip_contact *contact = (struct ast_sip_contact *) obj; struct ast_sip_contact_status *status; unschedule_qualify(contact); status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)); if (!status) { return; } if (ast_sorcery_delete(ast_sip_get_sorcery(), status)) { ast_log(LOG_ERROR, "Unable to delete ast_sip_contact_status for contact %s\n", contact->uri); } ao2_ref(status, -1); }
static char *cli_qualify(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); const char *endpoint_name; struct qualify_data *qual_data; switch (cmd) { case CLI_INIT: e->command = "pjsip qualify"; e->usage = "Usage: pjsip qualify <endpoint>\n" " Send a SIP OPTIONS request to all contacts on the endpoint.\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != 3) { return CLI_SHOWUSAGE; } endpoint_name = a->argv[2]; if (!(endpoint = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), "endpoint", endpoint_name))) { ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name); return CLI_FAILURE; } qual_data = qualify_data_alloc(endpoint, a->fd); if (!qual_data) { return CLI_FAILURE; } if (ast_sip_push_task(NULL, cli_qualify_contacts, qual_data)) { qualify_data_destroy(qual_data); return CLI_FAILURE; } return CLI_SUCCESS; }
/*! * \internal * \brief Send a NOTIFY request to the endpoint within a threaded task. */ static enum notify_result push_notify(const char *endpoint_name, void *info, task_data_create data_create) { RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); struct notify_data *data; if (!(endpoint = ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), "endpoint", endpoint_name))) { return INVALID_ENDPOINT; } if (!(data = data_create(endpoint, info))) { return ALLOC_ERROR; } if (ast_sip_push_task(NULL, notify_endpoint, data)) { ao2_cleanup(data); return TASK_PUSH_ERROR; } return SUCCESS; }
static struct ast_sip_endpoint *find_endpoint(pjsip_rx_data *rdata, char *endpoint_name, char *domain_name) { char id[AST_UUID_STR_LEN]; struct ast_sip_endpoint *endpoint; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); RAII_VAR(struct ao2_container *, transport_states, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport_state *, transport_state, NULL, ao2_cleanup); RAII_VAR(struct ast_sip_transport *, transport, NULL, ao2_cleanup); if (!ast_sip_get_disable_multi_domain()) { /* Attempt to find the endpoint given the name and domain provided */ snprintf(id, sizeof(id), "%s@%s", endpoint_name, domain_name); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { return endpoint; } /* See if an alias exists for the domain provided */ if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { snprintf(id, sizeof(id), "%s@%s", endpoint_name, alias->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { return endpoint; } } /* See if the transport this came in on has a provided domain */ if ((transport_states = ast_sip_get_transport_states()) && (transport_state = ao2_callback(transport_states, 0, find_transport_state_in_use, rdata)) && (transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", transport_state->id)) && !ast_strlen_zero(transport->domain)) { snprintf(id, sizeof(id), "anonymous@%s", transport->domain); if ((endpoint = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id))) { return endpoint; } } } /* Fall back to no domain */ return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", endpoint_name); }
static void *cli_aor_retrieve_by_id(const char *id) { return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id); }
struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name) { return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name); }
struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name) { return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name); }
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata) { RAII_VAR(struct serializer *, ser, NULL, ao2_cleanup); struct rx_task_data *task_data; RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup); pjsip_sip_uri *uri; char user_name[64], domain_name[64]; char *configured_aors, *aor_name; if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) { return PJ_FALSE; } if (ast_strlen_zero(endpoint->aors)) { /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors"); ast_log(LOG_WARNING, "Endpoint '%s' has no configured AORs\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL); ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received"); ast_log(LOG_WARNING, "Endpoint '%s' attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } uri = pjsip_uri_get_uri(rdata->msg_info.to->uri); ast_copy_pj_str(user_name, &uri->user, sizeof(user_name)); ast_copy_pj_str(domain_name, &uri->host, sizeof(domain_name)); configured_aors = ast_strdupa(endpoint->aors); /* Iterate the configured AORs to see if the user or the user+domain match */ while ((aor_name = strsep(&configured_aors, ","))) { char id[AST_UUID_STR_LEN]; RAII_VAR(struct ast_sip_domain_alias *, alias, NULL, ao2_cleanup); snprintf(id, sizeof(id), "%s@%s", user_name, domain_name); if (!strcmp(aor_name, id)) { break; } if ((alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain_name))) { snprintf(id, sizeof(id), "%s@%s", user_name, alias->domain); if (!strcmp(aor_name, id)) { break; } } if (!strcmp(aor_name, user_name)) { break; } } if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) { /* The provided AOR name was not found (be it within the configuration or sorcery itself) */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL); ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found"); ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s'\n", user_name, ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } if (!aor->max_contacts) { /* Registration is not permitted for this AOR */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted"); ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' unable to register\n", ast_sorcery_object_get_id(aor), ast_sorcery_object_get_id(endpoint)); return PJ_TRUE; } if (!(ser = serializer_find_or_create(aor_name))) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_mem_limit(endpoint, rdata); ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not get serializer\n", ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); return PJ_TRUE; } if (!(task_data = rx_task_data_create(rdata, endpoint, aor))) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_mem_limit(endpoint, rdata); ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not create rx_task_data\n", ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); return PJ_TRUE; } if (ast_sip_push_task(ser->serializer, rx_task, task_data)) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL); ast_sip_report_mem_limit(endpoint, rdata); ast_log(LOG_WARNING, "Endpoint '%s' unable to register on AOR '%s' - could not serialize task\n", ast_sorcery_object_get_id(endpoint), ast_sorcery_object_get_id(aor)); ao2_ref(task_data, -1); } return PJ_TRUE; }
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); }