/*!
 * \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 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_fromto_hdr *base, pjsip_tx_data *tdata, const struct ast_party_id *id)
{
	pjsip_fromto_hdr *id_hdr;
	pjsip_name_addr *id_name_addr;
	pjsip_sip_uri *id_uri;

	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);
	} else {
		/*
		 * We need to clear the remnants of the clone or it'll be left set.
		 * pj_strdup2 is safe to call with a NULL src and it resets both slen and ptr.
		 */
		pj_strdup2(tdata->pool, &id_name_addr->display, NULL);
	}

	pj_strdup2(tdata->pool, &id_uri->user, id->number.str);

	id_hdr->uri = (pjsip_uri *) id_name_addr;
	return id_hdr;
}
Beispiel #4
0
/// Mangelwurzel receives an initial request. It will Record-Route itself,
/// strip off all the Via headers and send the request on. It can also change
/// the request in various ways depending on the configuration in its Route
/// header.
/// - It can mangle the dialog identifiers using its mangalgorithm.
/// - It can mangle the Request URI and Contact URI using its mangalgorithm.
/// - It can mangle the To URI using its mangalgorithm.
/// - It can edit the S-CSCF Route header to turn the request into either an
///   originating or terminating request.
/// - It can edit the S-CSCF Route header to turn the request into an out of
///   the blue request.
/// - It can mangle the Record-Route headers URIs.
void MangelwurzelTsx::on_rx_initial_request(pjsip_msg* req)
{
  // Store off the unmodified request.
  _unmodified_request = original_request();

  // If Mangelwurzel receives a REGISTER, we need to respond with a 200 OK
  // rather than mangling the request and forwarding it on.
  if (req->line.req.method.id == PJSIP_REGISTER_METHOD)
  {
    pjsip_msg* rsp = create_response(req, PJSIP_SC_OK);
    send_response(rsp);
    free_msg(req);
    return;
  }

  pj_pool_t* pool = get_pool(req);

  // Get Mangelwurzel's route header and clone the URI. We use this in the SAS
  // event logging that we've received a request, and then we use it to
  // Record-Route ourselves.
  const pjsip_route_hdr* mangelwurzel_route_hdr = route_hdr();
  pjsip_uri* mangelwurzel_uri =
    (pjsip_uri*)pjsip_uri_clone(pool, mangelwurzel_route_hdr->name_addr.uri);

  SAS::Event event(trail(), SASEvent::MANGELWURZEL_INITIAL_REQ, 0);
  event.add_var_param(PJUtils::uri_to_string(PJSIP_URI_IN_ROUTING_HDR,
                                             mangelwurzel_uri));
  SAS::report_event(event);

  if (_config.dialog)
  {
    mangle_dialog_identifiers(req, pool);
  }

  if (_config.req_uri)
  {
    mangle_req_uri(req, pool);
    mangle_contact(req, pool);
  }

  if (_config.to)
  {
    mangle_to(req, pool);
  }

  edit_scscf_route_hdr(req, pool);

  if (_config.routes)
  {
    mangle_record_routes(req, pool);
  }

  strip_via_hdrs(req);

  record_route(req, pool, mangelwurzel_uri);

  send_request(req);
}
/// Route the request to the BGCF.
void ICSCFSproutletTsx::route_to_bgcf(pjsip_msg* req)
{
  TRC_INFO("Routing to BGCF %s",
           PJUtils::uri_to_string(PJSIP_URI_IN_ROUTING_HDR,
                                  _icscf->bgcf_uri()).c_str());
  PJUtils::add_route_header(req,
                            (pjsip_sip_uri*)pjsip_uri_clone(get_pool(req),
                                                            _icscf->bgcf_uri()),
                            get_pool(req));
  send_request(req);
  _routed_to_bgcf = true;
}
/*!
 * \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);
}
Beispiel #7
0
PJ_DEF(void) pjsip_name_addr_assign(pj_pool_t *pool, pjsip_name_addr *dst,
                                    const pjsip_name_addr *src)
{
    pj_strdup( pool, &dst->display, &src->display);
    dst->uri = (pjsip_uri*) pjsip_uri_clone(pool, src->uri);
}
Beispiel #8
0
/*
 * Create PRACK request for the incoming reliable provisional response.
 */
PJ_DEF(pj_status_t) pjsip_100rel_create_prack( pjsip_inv_session *inv,
					       pjsip_rx_data *rdata,
					       pjsip_tx_data **p_tdata)
{
    dlg_data *dd;
    uac_state_t *uac_state = NULL;
    const pj_str_t *to_tag = &rdata->msg_info.to->tag;
    pjsip_transaction *tsx;
    pjsip_msg *msg;
    pjsip_generic_string_hdr *rseq_hdr;
    pjsip_generic_string_hdr *rack_hdr;
    unsigned rseq;
    pj_str_t rack;
    char rack_buf[80];
    pjsip_tx_data *tdata;
    pj_status_t status;

    *p_tdata = NULL;

    dd = (dlg_data*) inv->dlg->mod_data[mod_100rel.mod.id];
    PJ_ASSERT_RETURN(dd != NULL, PJSIP_ENOTINITIALIZED);

    tsx = pjsip_rdata_get_tsx(rdata);
    msg = rdata->msg_info.msg;

    /* Check our assumptions */
    pj_assert( tsx->role == PJSIP_ROLE_UAC &&
	       tsx->method.id == PJSIP_INVITE_METHOD &&
	       msg->line.status.code > 100 &&
	       msg->line.status.code < 200);


    /* Get the RSeq header */
    rseq_hdr = (pjsip_generic_string_hdr*)
	       pjsip_msg_find_hdr_by_name(msg, &RSEQ, NULL);
    if (rseq_hdr == NULL) {
	PJ_LOG(4,(dd->inv->dlg->obj_name, 
		 "Ignoring 100rel response with no RSeq header"));
	return PJSIP_EMISSINGHDR;
    }
    rseq = (pj_uint32_t) pj_strtoul(&rseq_hdr->hvalue);

    /* Find UAC state for the specified call leg */
    uac_state = dd->uac_state_list;
    while (uac_state) {
	if (pj_stricmp(&uac_state->tag, to_tag)==0)
	    break;
	uac_state = uac_state->next;
    }

    /* Create new UAC state if we don't have one */
    if (uac_state == NULL) {
	uac_state = PJ_POOL_ZALLOC_T(dd->inv->dlg->pool, uac_state_t);
	uac_state->cseq = rdata->msg_info.cseq->cseq;
	uac_state->rseq = rseq - 1;
	pj_strdup(dd->inv->dlg->pool, &uac_state->tag, to_tag);
	uac_state->next = dd->uac_state_list;
	dd->uac_state_list = uac_state;
    }

    /* If this is from new INVITE transaction, reset UAC state. */
    if (rdata->msg_info.cseq->cseq != uac_state->cseq) {
	uac_state->cseq = rdata->msg_info.cseq->cseq;
	uac_state->rseq = rseq - 1;
    }

    /* Ignore provisional response retransmission */
    if (rseq <= uac_state->rseq) {
	/* This should have been handled before */
	return PJ_EIGNORED;

    /* Ignore provisional response with out-of-order RSeq */
    } else if (rseq != uac_state->rseq + 1) {
	PJ_LOG(4,(dd->inv->dlg->obj_name, 
		 "Ignoring 100rel response because RSeq jump "
		 "(expecting %u, got %u)",
		 uac_state->rseq+1, rseq));
	return PJ_EIGNORED;
    }

    /* Update our RSeq */
    uac_state->rseq = rseq;

    /* Create PRACK */
    status = pjsip_dlg_create_request(dd->inv->dlg, &pjsip_prack_method,
				      -1, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* If this response is a forked response from a different call-leg,
     * update the req URI (https://trac.pjsip.org/repos/ticket/1364)
     */
    if (pj_stricmp(&uac_state->tag, &dd->inv->dlg->remote.info->tag)) {
	const pjsip_contact_hdr *mhdr;

	mhdr = (const pjsip_contact_hdr*)
	       pjsip_msg_find_hdr(rdata->msg_info.msg,
	                          PJSIP_H_CONTACT, NULL);
	if (!mhdr || !mhdr->uri) {
	    PJ_LOG(4,(dd->inv->dlg->obj_name,
		     "Ignoring 100rel response with no or "
		     "invalid Contact header"));
	    pjsip_tx_data_dec_ref(tdata);
	    return PJ_EIGNORED;
	}
	tdata->msg->line.req.uri = (pjsip_uri*)
				   pjsip_uri_clone(tdata->pool, mhdr->uri);
    }

    /* Create RAck header */
    rack.ptr = rack_buf;
    rack.slen = pj_ansi_snprintf(rack.ptr, sizeof(rack_buf),
				 "%u %u %.*s",
				 rseq, rdata->msg_info.cseq->cseq,
				 (int)tsx->method.name.slen,
				 tsx->method.name.ptr);
    if (rack.slen < 1 || rack.slen >= (int)sizeof(rack_buf)) {
	return PJ_ETOOSMALL;
    }
    rack_hdr = pjsip_generic_string_hdr_create(tdata->pool, &RACK, &rack);
    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) rack_hdr);

    /* Done */
    *p_tdata = tdata;

    return PJ_SUCCESS;
}
Beispiel #9
0
/*
 * Create new request message to be forwarded upstream to new destination URI 
 * in uri. 
 */
PJ_DEF(pj_status_t) pjsip_endpt_create_request_fwd(pjsip_endpoint *endpt,
						   pjsip_rx_data *rdata, 
						   const pjsip_uri *uri,
						   const pj_str_t *branch,
						   unsigned options,
						   pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pj_status_t status;
    PJ_USE_EXCEPTION;


    PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL);
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, 
		     PJSIP_ENOTREQUESTMSG);

    PJ_UNUSED_ARG(options);


    /* Request forwarding rule in RFC 3261 section 16.6:
     *
     * For each target, the proxy forwards the request following these
     * steps:
     * 
     * 1.  Make a copy of the received request
     * 2.  Update the Request-URI
     * 3.  Update the Max-Forwards header field
     * 4.  Optionally add a Record-route header field value
     * 5.  Optionally add additional header fields
     * 6.  Postprocess routing information
     * 7.  Determine the next-hop address, port, and transport
     * 8.  Add a Via header field value
     * 9.  Add a Content-Length header field if necessary
     * 10. Forward the new request
     *
     * Of these steps, we only do step 1-3, since the later will be
     * done by application.
     */

    status = pjsip_endpt_create_tdata(endpt, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Always increment ref counter to 1 */
    pjsip_tx_data_add_ref(tdata);

    /* Duplicate the request */
    PJ_TRY {
	pjsip_msg *dst;
	const pjsip_msg *src = rdata->msg_info.msg;
	const pjsip_hdr *hsrc;

	/* Create the request */
	tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);

	/* Duplicate request method */
	pjsip_method_copy(tdata->pool, &tdata->msg->line.req.method,
			  &src->line.req.method);

	/* Set request URI */
	if (uri) {
	    dst->line.req.uri = (pjsip_uri*) 
	    			pjsip_uri_clone(tdata->pool, uri);
	} else {
	    dst->line.req.uri= (pjsip_uri*)
	    		       pjsip_uri_clone(tdata->pool, src->line.req.uri);
	}

	/* Clone ALL headers */
	hsrc = src->hdr.next;
	while (hsrc != &src->hdr) {

	    pjsip_hdr *hdst;

	    /* If this is the top-most Via header, insert our own before
	     * cloning the header.
	     */
	    if (hsrc == (pjsip_hdr*)rdata->msg_info.via) {
		pjsip_via_hdr *hvia;
		hvia = pjsip_via_hdr_create(tdata->pool);
		if (branch)
		    pj_strdup(tdata->pool, &hvia->branch_param, branch);
		else {
		    pj_str_t new_branch = pjsip_calculate_branch_id(rdata);
		    pj_strdup(tdata->pool, &hvia->branch_param, &new_branch);
		}
		pjsip_msg_add_hdr(dst, (pjsip_hdr*)hvia);

	    }
	    /* Skip Content-Type and Content-Length as these would be 
	     * generated when the the message is printed.
	     */
	    else if (hsrc->type == PJSIP_H_CONTENT_LENGTH ||
		     hsrc->type == PJSIP_H_CONTENT_TYPE) {

		hsrc = hsrc->next;
		continue;

	    }
#if 0
	    /* If this is the top-most Route header and it indicates loose
	     * route, remove the header.
	     */
	    else if (hsrc == (pjsip_hdr*)rdata->msg_info.route) {

		const pjsip_route_hdr *hroute = (const pjsip_route_hdr*) hsrc;
		const pjsip_sip_uri *sip_uri;

		if (!PJSIP_URI_SCHEME_IS_SIP(hroute->name_addr.uri) &&
		    !PJSIP_URI_SCHEME_IS_SIPS(hroute->name_addr.uri))
		{
		    /* This is a bad request! */
		    status = PJSIP_EINVALIDHDR;
		    goto on_error;
		}

		sip_uri = (pjsip_sip_uri*) hroute->name_addr.uri;

		if (sip_uri->lr_param) {
		    /* Yes lr param is present, skip this Route header */
		    hsrc = hsrc->next;
		    continue;
		}
	    }
#endif

	    /* Clone the header */
	    hdst = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hsrc);

	    /* If this is Max-Forward header, decrement the value */
	    if (hdst->type == PJSIP_H_MAX_FORWARDS) {
		pjsip_max_fwd_hdr *hmaxfwd = (pjsip_max_fwd_hdr*)hdst;
		--hmaxfwd->ivalue;
	    }

	    /* Append header to new request */
	    pjsip_msg_add_hdr(dst, hdst);


	    hsrc = hsrc->next;
	}

	/* 16.6.3:
	 * If the copy does not contain a Max-Forwards header field, the
         * proxy MUST add one with a field value, which SHOULD be 70.
	 */
	if (rdata->msg_info.max_fwd == NULL) {
	    pjsip_max_fwd_hdr *hmaxfwd = 
		pjsip_max_fwd_hdr_create(tdata->pool, 70);
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hmaxfwd);
	}

	/* Clone request body */
	if (src->body) {
	    dst->body = pjsip_msg_body_clone(tdata->pool, src->body);
	}

    }
    PJ_CATCH_ANY {
	status = PJ_ENOMEM;
	goto on_error;
    }
    PJ_END


    /* Done */
    *p_tdata = tdata;
    return PJ_SUCCESS;

on_error:
    pjsip_tx_data_dec_ref(tdata);
    return status;
}