/*! * \internal * \brief Copies any other msg vars over to the request headers. * * \param msg The msg structure to copy headers from * \param tdata The SIP transmission data */ static enum pjsip_status_code vars_to_headers(const struct ast_msg *msg, pjsip_tx_data *tdata) { const char *name; const char *value; int max_forwards; struct ast_msg_var_iterator *iter; for (iter = ast_msg_var_iterator_init(msg); ast_msg_var_iterator_next(msg, iter, &name, &value); ast_msg_var_unref_current(iter)) { if (!strcasecmp(name, "Max-Forwards")) { /* Decrement Max-Forwards for SIP loop prevention. */ if (sscanf(value, "%30d", &max_forwards) != 1 || --max_forwards == 0) { ast_msg_var_iterator_destroy(iter); ast_log(LOG_NOTICE, "MESSAGE(Max-Forwards) reached zero. MESSAGE not sent.\n"); return -1; } sprintf((char *) value, "%d", max_forwards); ast_sip_add_header(tdata, name, value); } else if (!is_msg_var_blocked(name)) { ast_sip_add_header(tdata, name, value); } } ast_msg_var_iterator_destroy(iter); return PJSIP_SC_OK; }
static void rfc3326_add_reason_header(struct ast_sip_session *session, struct pjsip_tx_data *tdata) { char buf[20]; snprintf(buf, sizeof(buf), "Q.850;cause=%i", ast_channel_hangupcause(session->channel) & 0x7f); ast_sip_add_header(tdata, "Reason", buf); if (ast_channel_hangupcause(session->channel) == AST_CAUSE_ANSWERED_ELSEWHERE) { ast_sip_add_header(tdata, "Reason", "SIP;cause=200;text=\"Call completed elsewhere\""); } }
static pj_status_t send_options_response(pjsip_rx_data *rdata, int code) { pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); pjsip_dialog *dlg = pjsip_rdata_get_dlg(rdata); pjsip_transaction *trans = pjsip_rdata_get_tsx(rdata); pjsip_tx_data *tdata; const pjsip_hdr *hdr; pj_status_t status; /* Make the response object */ status = ast_sip_create_response(rdata, code, NULL, &tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } /* Add appropriate headers */ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } /* * XXX TODO: pjsip doesn't care a lot about either of these headers - * while it provides specific methods to create them, they are defined * to be the standard string header creation. We never did add them * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here. */ ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING); ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE); if (dlg && trans) { status = pjsip_dlg_send_response(dlg, trans, tdata); } else { struct ast_sip_endpoint *endpoint; endpoint = ast_pjsip_rdata_get_endpoint(rdata); status = ast_sip_send_stateful_response(rdata, tdata, endpoint); ao2_cleanup(endpoint); } if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; }
/*! * \internal * \brief Build the NOTIFY request adding content or header info. */ static void build_notify(pjsip_tx_data *tdata, const char *name, const char *value, struct ast_str **content_type, struct ast_str **content) { if (not_allowed(name)) { ast_log(LOG_WARNING, "Cannot specify %s header, " "ignoring\n", name); return; } if (!strcasecmp(name, "Content-type")) { if (!(*content_type)) { *content_type = ast_str_create(CONTENT_TYPE_SIZE); } ast_str_set(content_type, 0,"%s", value); } else if (!strcasecmp(name, "Content")) { if (!(*content)) { *content = ast_str_create(CONTENT_SIZE); } if (ast_str_strlen(*content)) { ast_str_append(content, 0, "\r\n"); } ast_str_append(content, 0, "%s", value); } else { ast_sip_add_header(tdata, name, value); } }
/*! \brief Helper function which adds a Date header to a response */ static void registrar_add_date_header(pjsip_tx_data *tdata) { char date[256]; struct tm tm; time_t t = time(NULL); gmtime_r(&t, &tm); strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm); ast_sip_add_header(tdata, "Date", date); }
static int options_incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata) { pjsip_tx_data *tdata; pj_status_t status; const pjsip_hdr *hdr; pjsip_endpoint *endpt = ast_sip_get_pjsip_endpoint(); status = pjsip_dlg_create_response(session->inv_session->dlg, rdata, 200, NULL,&tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to create response (%d)\n", status); return status; } /* Add appropriate headers */ if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ACCEPT, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_ALLOW, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } if ((hdr = pjsip_endpt_get_capability(endpt, PJSIP_H_SUPPORTED, NULL))) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)pjsip_hdr_clone(tdata->pool, hdr)); } /* * XXX TODO: pjsip doesn't care a lot about either of these headers - * while it provides specific methods to create them, they are defined * to be the standard string header creation. We never did add them * in chan_sip, although RFC 3261 says they SHOULD. Hard coded here. */ ast_sip_add_header(tdata, "Accept-Encoding", DEFAULT_ENCODING); ast_sip_add_header(tdata, "Accept-Language", DEFAULT_LANGUAGE); status = pjsip_dlg_send_response(session->inv_session->dlg, pjsip_rdata_get_tsx(rdata), tdata); if (status != PJ_SUCCESS) { ast_log(LOG_ERROR, "Unable to send response (%d)\n", status); } return status; }
/*! * \internal * \brief Send a notify request to the URI. */ static int notify_uri(void *obj) { RAII_VAR(struct notify_uri_data *, data, obj, ao2_cleanup); RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sip_default_outbound_endpoint(), ao2_cleanup); pjsip_tx_data *tdata; if (!endpoint) { ast_log(LOG_WARNING, "No default outbound endpoint set, can not send " "NOTIFY requests to arbitrary URIs.\n"); return -1; } if (ast_strlen_zero(data->uri)) { ast_log(LOG_WARNING, "Unable to NOTIFY - URI is blank.\n"); return -1; } if (ast_sip_create_request("NOTIFY", NULL, endpoint, data->uri, NULL, &tdata)) { ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for " "uri %s\n", data->uri); return -1; } ast_sip_add_header(tdata, "Subscription-State", "terminated"); data->build_notify(tdata, data->info); if (ast_sip_send_request(tdata, NULL, endpoint, NULL, NULL)) { ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for " "uri %s\n", data->uri); return -1; } return 0; }
/*! * \internal * \brief Build and send a NOTIFY request to a contact. */ static int notify_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; struct notify_data *data = arg; pjsip_tx_data *tdata; if (ast_sip_create_request("NOTIFY", NULL, data->endpoint, NULL, contact, &tdata)) { ast_log(LOG_WARNING, "SIP NOTIFY - Unable to create request for " "contact %s\n", contact->uri); return -1; } ast_sip_add_header(tdata, "Subscription-State", "terminated"); data->build_notify(tdata, data->info); if (ast_sip_send_request(tdata, NULL, data->endpoint, NULL, NULL)) { ast_log(LOG_ERROR, "SIP NOTIFY - Unable to send request for " "contact %s\n", contact->uri); return -1; } return 0; }
/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */ static int registrar_validate_contacts(const pjsip_rx_data *rdata, struct ao2_container *contacts, struct ast_sip_aor *aor, int *added, int *updated, int *deleted) { pjsip_contact_hdr *previous = NULL, *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr; struct registrar_contact_details details = { .pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256), }; if (!details.pool) { return -1; } while ((contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next))) { int expiration = registrar_get_expiration(aor, contact, rdata); RAII_VAR(struct ast_sip_contact *, existing, NULL, ao2_cleanup); if (contact->star) { /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */ if ((expiration != 0) || previous) { pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } continue; } else if (previous && previous->star) { /* If there is a previous contact and it is a '*' this is a deal breaker */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return -1; } previous = contact; if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) { continue; } details.uri = pjsip_uri_get_uri(contact->uri); /* Determine if this is an add, update, or delete for policy enforcement purposes */ if (!(existing = ao2_callback(contacts, 0, registrar_find_contact, &details))) { if (expiration) { (*added)++; } } else if (expiration) { (*updated)++; } else { (*deleted)++; } } /* The provided contacts are acceptable, huzzah! */ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); return 0; } /*! \brief Callback function which prunes static contacts */ static int registrar_prune_static(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; return ast_tvzero(contact->expiration_time) ? CMP_MATCH : 0; } /*! \brief Internal function used to delete all contacts from an AOR */ static int registrar_delete_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; const char *aor_name = arg; ast_sip_location_delete_contact(contact); if (!ast_strlen_zero(aor_name)) { 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", contact->uri, aor_name); } return 0; } /*! \brief Internal function which adds a contact to a response */ static int registrar_add_contact(void *obj, void *arg, int flags) { struct ast_sip_contact *contact = obj; pjsip_tx_data *tdata = arg; pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool); pj_str_t uri; pj_strdup2_with_null(tdata->pool, &uri, contact->uri); hdr->uri = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR); hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr); return 0; } /*! \brief Helper function which adds a Date header to a response */ static void registrar_add_date_header(pjsip_tx_data *tdata) { char date[256]; struct tm tm; time_t t = time(NULL); gmtime_r(&t, &tm); strftime(date, sizeof(date), "%a, %d %b %Y %T GMT", &tm); ast_sip_add_header(tdata, "Date", date); }