/*! * \internal * \brief Create an identity header for an outgoing message * \param hdr_name The name of the header to create * \param tdata The message to place the header on * \param id The identification information for the new header * \return newly-created header */ static pjsip_fromto_hdr *create_new_id_hdr(const pj_str_t *hdr_name, pjsip_tx_data *tdata, const struct ast_party_id *id) { pjsip_fromto_hdr *id_hdr; pjsip_fromto_hdr *base; pjsip_name_addr *id_name_addr; pjsip_sip_uri *id_uri; base = tdata->msg->type == PJSIP_REQUEST_MSG ? PJSIP_MSG_FROM_HDR(tdata->msg) : PJSIP_MSG_TO_HDR(tdata->msg); id_hdr = pjsip_from_hdr_create(tdata->pool); id_hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &id_hdr->name, hdr_name); id_hdr->sname.slen = 0; id_name_addr = pjsip_uri_clone(tdata->pool, base->uri); id_uri = pjsip_uri_get_uri(id_name_addr->uri); if (id->name.valid) { int name_buf_len = strlen(id->name.str) * 2 + 1; char *name_buf = ast_alloca(name_buf_len); ast_escape_quoted(id->name.str, name_buf, name_buf_len); pj_strdup2(tdata->pool, &id_name_addr->display, name_buf); } pj_strdup2(tdata->pool, &id_uri->user, id->number.str); id_hdr->uri = (pjsip_uri *) id_name_addr; return id_hdr; }
/*! * \internal * \brief Adds diversion header information to an outbound SIP message * * \param tdata The outbound message * \param data The redirecting data used to fill parts of the diversion header */ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data) { pjsip_fromto_hdr *hdr; pjsip_name_addr *name_addr; pjsip_sip_uri *uri; pjsip_param *param; pjsip_fromto_hdr *old_hdr; const char *reason_str; const char *quote_str; char *reason_buf; struct ast_party_id *id = &data->from; pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri; if (!id->number.valid || ast_strlen_zero(id->number.str)) { return; } hdr = pjsip_from_hdr_create(tdata->pool); hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &hdr->name, &diversion_name); hdr->sname = hdr->name; name_addr = pjsip_uri_clone(tdata->pool, base); uri = pjsip_uri_get_uri(name_addr->uri); pj_strdup2(tdata->pool, &name_addr->display, id->name.str); pj_strdup2(tdata->pool, &uri->user, id->number.str); param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param); param->name = pj_str("reason"); reason_str = reason_code_to_str(&data->reason); /* Reason is either already quoted or it is a token to not need quotes added. */ quote_str = *reason_str == '\"' || sip_is_token(reason_str) ? "" : "\""; reason_buf = pj_pool_alloc(tdata->pool, strlen(reason_str) + 3); sprintf(reason_buf, "%s%s%s", quote_str, reason_str, quote_str);/* Safe */ param->value = pj_str(reason_buf); pj_list_insert_before(&hdr->other_param, param); hdr->uri = (pjsip_uri *) name_addr; old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL); if (old_hdr) { pj_list_erase(old_hdr); } pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr); }
/*! * \internal * \brief Overwrite fields in the outbound 'From' header * * The outbound 'From' header is created/added in ast_sip_create_request with * default data. If available that data may be info specified in the 'from_user' * and 'from_domain' options found on the endpoint. That information will be * overwritten with data in the given 'from' parameter. * * \param tdata the outbound message data structure * \param from info to copy into the header */ static void update_from(pjsip_tx_data *tdata, char *from) { pjsip_name_addr *name_addr = (pjsip_name_addr *) PJSIP_MSG_FROM_HDR(tdata->msg)->uri; pjsip_sip_uri *uri = pjsip_uri_get_uri(name_addr); pjsip_uri *parsed; if (ast_strlen_zero(from)) { return; } if ((parsed = pjsip_parse_uri(tdata->pool, from, strlen(from), PJSIP_PARSE_URI_AS_NAMEADDR))) { pjsip_name_addr *parsed_name_addr = (pjsip_name_addr *)parsed; pjsip_sip_uri *parsed_uri = pjsip_uri_get_uri(parsed_name_addr->uri); if (pj_strlen(&parsed_name_addr->display)) { pj_strdup(tdata->pool, &name_addr->display, &parsed_name_addr->display); } pj_strdup(tdata->pool, &uri->user, &parsed_uri->user); pj_strdup(tdata->pool, &uri->host, &parsed_uri->host); uri->port = parsed_uri->port; } else { /* assume it is 'user[@domain]' format */ char *domain = strchr(from, '@'); if (domain) { *domain++ = '\0'; pj_strdup2(tdata->pool, &uri->host, domain); } pj_strdup2(tdata->pool, &uri->user, from); } }
/// Determine the served user for originating requests. pjsip_uri* PJUtils::orig_served_user(pjsip_msg* msg) { // The served user for originating requests is determined from the // P-Served-User or P-Asserted-Identity headers. For extra compatibility, // we will also look at the From header if neither of the IMS headers is // present. pjsip_uri* uri = NULL; pjsip_routing_hdr* served_user = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(msg, &STR_P_SERVED_USER, NULL); if (served_user != NULL) { uri = (pjsip_uri*)pjsip_uri_get_uri(&served_user->name_addr); LOG_DEBUG("Served user from P-Served-User header"); } if (uri == NULL) { // No P-Served-User header present, so check for P-Asserted-Identity // header. pjsip_routing_hdr* asserted_id = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(msg, &STR_P_ASSERTED_IDENTITY, NULL); if (asserted_id != NULL) { uri = (pjsip_uri*)pjsip_uri_get_uri(&asserted_id->name_addr); LOG_DEBUG("Served user from P-Asserted-Identity header"); } } if (uri == NULL) { // Neither IMS header is present, so use the From header. This isn't // strictly speaking IMS compliant. LOG_DEBUG("From header %p", PJSIP_MSG_FROM_HDR(msg)); uri = (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_FROM_HDR(msg)->uri); LOG_DEBUG("Served user from From header (%p)", uri); } return uri; }
/// Apply the mangalgorithm to the From tag, To tag (if present) and call ID of /// req. void MangelwurzelTsx::mangle_dialog_identifiers(pjsip_msg* req, pj_pool_t* pool) { pjsip_from_hdr* from_hdr = PJSIP_MSG_FROM_HDR(req); if (from_hdr != NULL) { std::string from_tag = PJUtils::pj_str_to_string(&from_hdr->tag); mangle_string(from_tag); TRC_DEBUG("From tag mangled to %s", from_tag.c_str()); from_hdr->tag = pj_strdup3(pool, from_tag.c_str()); } pjsip_to_hdr* to_hdr = PJSIP_MSG_TO_HDR(req); if (to_hdr != NULL) { std::string to_tag = PJUtils::pj_str_to_string(&to_hdr->tag); mangle_string(to_tag); TRC_DEBUG("To tag mangled to %s", to_tag.c_str()); to_hdr->tag = pj_strdup3(pool, to_tag.c_str()); } pjsip_cid_hdr* cid_hdr = (pjsip_cid_hdr*)pjsip_msg_find_hdr(req, PJSIP_H_CALL_ID, NULL); if (cid_hdr != NULL) { std::string call_id = PJUtils::pj_str_to_string(&cid_hdr->id); mangle_string(call_id); TRC_DEBUG("Call ID manged to %s", call_id.c_str()); cid_hdr->id = pj_strdup3(pool, call_id.c_str()); // Report a SAS marker for the new call ID so that the two dialogs can be // correlated in SAS. TRC_DEBUG("Logging SAS Call-ID marker, Call-ID %.*s", cid_hdr->id.slen, cid_hdr->id.ptr); SAS::Marker cid_marker(trail(), MARKER_ID_SIP_CALL_ID, 1u); cid_marker.add_var_param(cid_hdr->id.slen, cid_hdr->id.ptr); SAS::report_marker(cid_marker, SAS::Marker::Scope::Trace); } }
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) { char local_buf[256]; char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg); to_hdr = PJSIP_MSG_TO_HDR(tdata->msg); uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag); if (!uuid) { ao2_ref(capture_info, -1); return PJ_SUCCESS; } ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE); capture_info->capture_time = ast_tvnow(); capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; capture_info->uuid = uuid; capture_info->zipped = 0; hepv3_send_packet(capture_info); return PJ_SUCCESS; }
/*! * \internal * \brief Adds diversion header information to an outbound SIP message * * \param tdata The outbound message * \param data The redirecting data used to fill parts of the diversion header */ static void add_diversion_header(pjsip_tx_data *tdata, struct ast_party_redirecting *data) { pjsip_fromto_hdr *hdr; pjsip_name_addr *name_addr; pjsip_sip_uri *uri; pjsip_param *param; pjsip_fromto_hdr *old_hdr; struct ast_party_id *id = &data->from; pjsip_uri *base = PJSIP_MSG_FROM_HDR(tdata->msg)->uri; if (!id->number.valid || ast_strlen_zero(id->number.str)) { return; } hdr = pjsip_from_hdr_create(tdata->pool); hdr->type = PJSIP_H_OTHER; pj_strdup(tdata->pool, &hdr->name, &diversion_name); hdr->sname.slen = 0; name_addr = pjsip_uri_clone(tdata->pool, base); uri = pjsip_uri_get_uri(name_addr->uri); pj_strdup2(tdata->pool, &name_addr->display, id->name.str); pj_strdup2(tdata->pool, &uri->user, id->number.str); param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param); param->name = pj_str("reason"); param->value = pj_str((char*)reason_code_to_str(&data->reason)); pj_list_insert_before(&hdr->other_param, param); hdr->uri = (pjsip_uri *) name_addr; old_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &diversion_name, NULL); if (old_hdr) { pj_list_erase(old_hdr); } pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr); }
static void diversion_incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata) { static const pj_str_t contact_name = { "Contact", 7 }; pjsip_status_line status = rdata->msg_info.msg->line.status; pjsip_fromto_hdr *div_hdr; pjsip_contact_hdr *contact_hdr; if ((status.code != 302) && (status.code != 181)) { return; } /* use the diversion header info if there is one. if not one then use the session caller id info. if that doesn't exist use info from the To hdr*/ if (!(div_hdr = get_diversion_header(rdata)) && !session->id.number.valid) { div_hdr = PJSIP_MSG_TO_HDR(rdata->msg_info.msg); } contact_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &contact_name, NULL); set_redirecting(session, div_hdr, contact_hdr ? (pjsip_name_addr*)contact_hdr->uri : (pjsip_name_addr*)PJSIP_MSG_FROM_HDR(rdata->msg_info.msg)->uri); }
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata) { char local_buf[256]; char remote_buf[256]; char *uuid; struct hepv3_capture_info *capture_info; pjsip_cid_hdr *cid_hdr; pjsip_from_hdr *from_hdr; pjsip_to_hdr *to_hdr; capture_info = hepv3_create_capture_info(tdata->buf.start, (size_t)(tdata->buf.cur - tdata->buf.start)); if (!capture_info) { return PJ_SUCCESS; } if (!(tdata->tp_info.transport->flag & PJSIP_TRANSPORT_RELIABLE)) { pjsip_tpmgr_fla2_param prm; /* Attempt to determine what IP address will we send this packet out of */ pjsip_tpmgr_fla2_param_default(&prm); prm.tp_type = tdata->tp_info.transport->key.type; pj_strset2(&prm.dst_host, tdata->tp_info.dst_name); prm.local_if = PJ_TRUE; /* If we can't get the local address use what we have already */ if (pjsip_tpmgr_find_local_addr2(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()), tdata->pool, &prm) != PJ_SUCCESS) { pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } else { if (prm.tp_type & PJSIP_TRANSPORT_IPV6) { snprintf(local_buf, sizeof(local_buf), "[%.*s]:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } else { snprintf(local_buf, sizeof(local_buf), "%.*s:%hu", (int)pj_strlen(&prm.ret_addr), pj_strbuf(&prm.ret_addr), prm.ret_port); } } } else { /* For reliable transports they can only ever come from the transport * local address. */ pj_sockaddr_print(&tdata->tp_info.transport->local_addr, local_buf, sizeof(local_buf), 3); } pj_sockaddr_print(&tdata->tp_info.dst_addr, remote_buf, sizeof(remote_buf), 3); cid_hdr = PJSIP_MSG_CID_HDR(tdata->msg); from_hdr = PJSIP_MSG_FROM_HDR(tdata->msg); to_hdr = PJSIP_MSG_TO_HDR(tdata->msg); uuid = assign_uuid(&cid_hdr->id, &to_hdr->tag, &from_hdr->tag); if (!uuid) { ao2_ref(capture_info, -1); return PJ_SUCCESS; } ast_sockaddr_parse(&capture_info->src_addr, local_buf, PARSE_PORT_REQUIRE); ast_sockaddr_parse(&capture_info->dst_addr, remote_buf, PARSE_PORT_REQUIRE); capture_info->protocol_id = transport_to_protocol_id(tdata->tp_info.transport); capture_info->capture_time = ast_tvnow(); capture_info->capture_type = HEPV3_CAPTURE_TYPE_SIP; capture_info->uuid = uuid; capture_info->zipped = 0; hepv3_send_packet(capture_info); return PJ_SUCCESS; }
void MementoAppServerTsx::on_initial_request(pjsip_msg* req) { TRC_DEBUG("Memento processing an initial request of type %s", (req->line.req.method.id == PJSIP_INVITE_METHOD) ? "INVITE" : "BYE"); // Get the current time time_t rawtime; time(&rawtime); tm* start_time = localtime(&rawtime); _start_time_xml = create_formatted_timestamp(start_time, XML_PATTERN); _start_time_cassandra = create_formatted_timestamp(start_time, TIMESTAMP_PATTERN); // Is the call originating or terminating? std::string served_user; pjsip_routing_hdr* psu_hdr = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(req, &P_SERVED_USER, NULL); if (psu_hdr != NULL) { pjsip_uri* uri = (pjsip_uri*)pjsip_uri_get_uri(&psu_hdr->name_addr); served_user = uri_to_string(PJSIP_URI_IN_ROUTING_HDR, uri); pjsip_param* sescase = pjsip_param_find(&psu_hdr->other_param, &SESCASE); if ((sescase != NULL) && (pj_stricmp(&sescase->value, &ORIG) == 0)) { TRC_DEBUG("Request is originating"); _outgoing = true; } } // Get the caller, callee and impu values if (_outgoing) { // Get the callee's URI amd name from the To header. _callee_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_TO_HDR(req)->uri)); _callee_name = pj_str_to_string(&((pjsip_name_addr*) (PJSIP_MSG_TO_HDR(req)->uri))->display); // Get the caller's URI and name from the P-Asserted Identity header. If // this is missing, use the From header. pjsip_routing_hdr* asserted_id = (pjsip_routing_hdr*) pjsip_msg_find_hdr_by_name(req, &P_ASSERTED_IDENTITY, NULL); if (asserted_id != NULL) { _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(&asserted_id->name_addr)); _caller_name = pj_str_to_string(&asserted_id->name_addr.display); } else { TRC_WARNING("INVITE missing P-Asserted-Identity"); send_request(req); return; } // Set the IMPU equal to the caller's URI _impu = _caller_uri; } else { // Get the callee's URI from the request URI. There can be no name value. _callee_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, req->line.req.uri); // Get the caller's URI and name from the From header. _caller_uri = uri_to_string(PJSIP_URI_IN_FROMTO_HDR, (pjsip_uri*)pjsip_uri_get_uri(PJSIP_MSG_FROM_HDR(req)->uri)); _caller_name = pj_str_to_string(&((pjsip_name_addr*) (PJSIP_MSG_FROM_HDR(req)->uri))->display); // Set the IMPU equal to the callee's URI _impu = _callee_uri; } // Add a unique ID containing the IMPU to the record route header. // This has the format: // <YYYYMMDDHHMMSS>_<unique_id>_<base64 encoded impu>.memento.<home domain> _unique_id = std::to_string(Utils::generate_unique_integer(0,0)); std::string encoded_impu = base64_encode(reinterpret_cast<const unsigned char*>(_impu.c_str()), _impu.length()); std::string dialog_id = std::string(_start_time_cassandra). append("_"). append(_unique_id). append("_"). append(encoded_impu); add_to_dialog(dialog_id); send_request(req); }