Esempio n. 1
0
File: uac.c Progetto: halan/kamailio
/*
 * Send an initial request that will start a dialog
 * WARNING: writes uac_r->dialog
 */
int req_outside(uac_req_t *uac_r, str* ruri, str* to, str* from, str *next_hop)
{
	str callid, fromtag;

	if (check_params(uac_r, to, from) < 0) goto err;
	
	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &uac_r->dialog) < 0) {
		LOG(L_ERR, "req_outside(): Error while creating new dialog\n");
		goto err;
	}

	if (ruri) {
		uac_r->dialog->rem_target.s = ruri->s;
		uac_r->dialog->rem_target.len = ruri->len;
		/* hooks will be set from w_calculate_hooks */
	}

	if (next_hop) uac_r->dialog->dst_uri = *next_hop;
	w_calculate_hooks(uac_r->dialog);

	return t_uac(uac_r);

 err:
	/* callback parameter must be freed outside of tm module
	if (cbp) shm_free(cbp); */
	return -1;
}
Esempio n. 2
0
/*
 * Send a transactional request, no dialogs involved
 */
int request(str* m, str* ruri, str* to, str* from, str* h, str* b, transaction_cb c, void* cp)
{
	str callid, fromtag;
	dlg_t* dialog;
	int res;

	if (check_params(m, to, from, &dialog) < 0) goto err;

	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
		LOG(L_ERR, "req_outside(): Error while creating temorary dialog\n");
		goto err;
	}

	if (ruri) {
		dialog->rem_target.s = ruri->s;
		dialog->rem_target.len = ruri->len;
		dialog->hooks.request_uri = &dialog->rem_target;
	}

	res = t_uac(m, h, b, dialog, c, cp);
	dialog->rem_target.s = 0;
	free_dlg(dialog);
	return res;

 err:
	if (cp) shm_free(cp);
	return -1;
}
Esempio n. 3
0
/*
 * Send a transactional request, no dialogs involved
 */
int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *oburi,
				transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	str callid, fromtag;
	dlg_t* dialog;
	int res;

	if (check_params(m, to, from, &dialog) < 0) goto err;

	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
		LM_ERR("failed to create temporary dialog\n");
		goto err;
	}

	if (ruri) {
		dialog->rem_target.s = ruri->s;
		dialog->rem_target.len = ruri->len;
		dialog->hooks.request_uri = &dialog->rem_target;
	}

	if (oburi && oburi->s) dialog->hooks.next_hop = oburi;

	w_calculate_hooks(dialog);

	res = t_uac(m, h, b, dialog, cb, cbp, release_func);
	dialog->rem_target.s = 0;
	free_dlg(dialog);
	return res;

err:
	return -1;
}
Esempio n. 4
0
/*
 * Send a transactional request, no dialogs involved
 * WARNING: writes uac_r->dialog
 */
int request(uac_req_t *uac_r, str* ruri, str* to, str* from, str *next_hop)
{
	str callid, fromtag;
	dlg_t* dialog;
	int res;

	if (check_params(uac_r, to, from) < 0) goto err;

	if (uac_r->callid == NULL || uac_r->callid->len <= 0)
	    generate_callid(&callid);
	else
	    callid = *uac_r->callid;
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
		LOG(L_ERR, "request(): Error while creating temporary dialog\n");
		goto err;
	}

	if (ruri) {
		dialog->rem_target.s = ruri->s;
		dialog->rem_target.len = ruri->len;
		/* hooks will be set from w_calculate_hooks */
	}

	if (next_hop) dialog->dst_uri = *next_hop;
	w_calculate_hooks(dialog);

	/* WARNING:
	 * to be clean it should be called 
	 *   set_dlg_target(dialog, ruri, next_hop);
	 * which sets both uris if given [but it duplicates them in shm!]
	 *
	 * but in this case the _ruri parameter in set_dlg_target
	 * must be optional (it is needed now) and following hacks
	 *   dialog->rem_target.s = 0;
	 *   dialog->dst_uri.s = 0;
	 * before freeing dialog here must be removed
	 */
	uac_r->dialog = dialog;

	if(uac_r->ssock!=NULL && uac_r->ssock->len>0
			&& uac_r->dialog->send_sock==NULL) {
		/* set local send socket */
		uac_r->dialog->send_sock = lookup_local_socket(uac_r->ssock);
	}

	res = t_uac(uac_r);
	dialog->rem_target.s = 0;
	dialog->dst_uri.s = 0;
	free_dlg(dialog);
	uac_r->dialog = 0;
	return res;

 err:
	/* callback parameter must be freed outside of tm module
	if (cp) shm_free(cp); */
	return -1;
}
Esempio n. 5
0
/*
 * Create a new dialog
 */
int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d)
{
	dlg_t* res;
	str generated_cid;
	str generated_ltag;

	if (!_cid) { /* if not given, compute new one */
		generate_callid(&generated_cid);
		_cid = &generated_cid;
	}
	if (_cid && (!_ltag)) { /* if not given, compute new one */
		generate_fromtag(&generated_ltag, _cid);
		_ltag = &generated_ltag;
	}
	if (_lseq == 0) _lseq = DEFAULT_CSEQ;

	if (!_cid || !_ltag || !_luri || !_ruri || !_d) {
		LOG(L_ERR, "new_dlg_uac(): Invalid parameter value\n");
		return -1;
	}

	res = (dlg_t*)shm_malloc(sizeof(dlg_t));
	if (res == 0) {
		LOG(L_ERR, "new_dlg_uac(): No memory left\n");
		return -2;
	}

	     /* Clear everything */	
	memset(res, 0, sizeof(dlg_t));
	
	     /* Make a copy of Call-ID */
	if (str_duplicate(&res->id.call_id, _cid) < 0) return -3;
	     /* Make a copy of local tag (usually From tag) */
	if (str_duplicate(&res->id.loc_tag, _ltag) < 0) return -4;
	     /* Make a copy of local URI (usually From) */
	if (str_duplicate(&res->loc_uri, _luri) < 0) return -5;
	     /* Make a copy of remote URI (usually To) */
	if (str_duplicate(&res->rem_uri, _ruri) < 0) return -6;
	     /* Make a copy of local sequence (usually CSeq) */
	res->loc_seq.value = _lseq;
	     /* And mark it as set */
	res->loc_seq.is_set = 1;

	*_d = res;

	if (calculate_hooks(*_d) < 0) {
		LOG(L_ERR, "new_dlg_uac(): Error while calculating hooks\n");
		/* FIXME: free everything here */
		shm_free(res);
		return -2;
	}
#ifdef DIALOG_CALLBACKS
	run_new_dlg_callbacks(DLG_CB_UAC, res, 0);
#endif
	
	return 0;
}
Esempio n. 6
0
/*
 * Send a transactional request, no dialogs involved
 */
int request(str* m, str* ruri, str* to, str* from, str* h, str* b, str *next_hop, transaction_cb c, void* cp)
{
	str callid, fromtag;
	dlg_t* dialog;
	int res;

	if (check_params(m, to, from, &dialog) < 0) goto err;

	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, &dialog) < 0) {
		LOG(L_ERR, "request(): Error while creating temporary dialog\n");
		goto err;
	}

	if (ruri) {
		dialog->rem_target.s = ruri->s;
		dialog->rem_target.len = ruri->len;
		/* hooks will be set from w_calculate_hooks */
	}

	if (next_hop) dialog->dst_uri = *next_hop;
	w_calculate_hooks(dialog);

	/* WARNING:
	 * to be clean it should be called 
	 *   set_dlg_target(dialog, ruri, next_hop);
	 * which sets both uris if given [but it duplicates them in shm!]
	 *
	 * but in this case the _ruri parameter in set_dlg_target
	 * must be optional (it is needed now) and following hacks
	 *   dialog->rem_target.s = 0;
	 *   dialog->dst_uri.s = 0;
	 * before freeing dialog here must be removed
	 */

	res = t_uac(m, h, b, dialog, c, cp);
	dialog->rem_target.s = 0;
	dialog->dst_uri.s = 0;
	free_dlg(dialog);
	return res;

 err:
	if (cp) shm_free(cp);
	return -1;
}
Esempio n. 7
0
/*
 * Send an initial request that will start a dialog
 */
int req_outside(str* method, str* to, str* from, str* headers, str* body, dlg_t** dialog, transaction_cb cb, void* cbp)
{
	str callid, fromtag;

	if (check_params(method, to, from, dialog) < 0) goto err;
	
	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
		LOG(L_ERR, "req_outside(): Error while creating new dialog\n");
		goto err;
	}

	return t_uac(method, headers, body, *dialog, cb, cbp);

 err:
	if (cbp) shm_free(cbp);
	return -1;
}
Esempio n. 8
0
/*
 * Send an initial request that will start a dialog
 */
int req_outside(str* method, str* to, str* from,
	str* headers, str* body, dlg_t** dialog,
	transaction_cb cb, void* cbp,release_tmcb_param release_func)
{
	str callid, fromtag;

	if (check_params(method, to, from, dialog) < 0) goto err;

	generate_callid(&callid);
	generate_fromtag(&fromtag, &callid);

	if (new_dlg_uac(&callid, &fromtag, DEFAULT_CSEQ, from, to, dialog) < 0) {
		LM_ERR("failed to create new dialog\n");
		goto err;
	}

	return t_uac(method, headers, body, *dialog, cb, cbp, release_func);
err:
	return -1;
}
Esempio n. 9
0
File: tm.c Progetto: Deni90/opensips
inline static int w_t_new_request(struct sip_msg* msg, char *p_method,
			char *p_ruri, char *p_from, char *p_to, char *p_body, char *p_ctx)
{
#define CONTENT_TYPE_HDR      "Content-Type: "
#define CONTENT_TYPE_HDR_LEN  (sizeof(CONTENT_TYPE_HDR)-1)
	static dlg_t dlg;
	struct usr_avp **avp_list;
	str ruri;
	str method;
	str body;
	str headers;
	str s;
	int_str ctx;
	char *p;

	memset( &dlg, 0, sizeof(dlg_t));

	/* evaluate the parameters */

	/* method */
	if ( fixup_get_svalue(msg, (gparam_p)p_method, &method)<0 ) {
		LM_ERR("failed to extract METHOD param\n");
		return -1;
	}
	LM_DBG("setting METHOD to <%.*s>\n", method.len, method.s);

	/* ruri - next hop is the same as RURI */
	dlg.hooks.next_hop = dlg.hooks.request_uri = &ruri;
	if ( fixup_get_svalue(msg, (gparam_p)p_ruri, &ruri)<0 ) {
		LM_ERR("failed to extract RURI param\n");
		return -1;
	}
	LM_DBG("setting RURI to <%.*s>\n",
		dlg.hooks.next_hop->len, dlg.hooks.next_hop->s);

	/* FROM URI + display */
	if ( fixup_get_svalue(msg, (gparam_p)p_from, &s)<0 ) {
		LM_ERR("failed to extract FROM param\n");
		return -1;
	}
	if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) {
		/* no display, only FROM URI */
		dlg.loc_uri = s;
		dlg.loc_dname.s = NULL;
		dlg.loc_dname.len = 0;
	} else {
		/* display + URI */
		dlg.loc_uri.s = p+1;
		dlg.loc_uri.len = s.s+s.len - dlg.loc_uri.s;
		dlg.loc_dname.s = s.s;
		dlg.loc_dname.len = p - s.s;
	}
	LM_DBG("setting FROM to <%.*s> + <%.*s>\n",
		dlg.loc_dname.len, dlg.loc_dname.s,
		dlg.loc_uri.len, dlg.loc_uri.s);

	/* TO URI + display */
	if ( fixup_get_svalue(msg, (gparam_p)p_to, &s)<0 ) {
		LM_ERR("failed to extract TO param\n");
		return -1;
	}
	if ( (p=q_memrchr(s.s, ' ', s.len))==NULL ) {
		/* no display, only TO URI */
		dlg.rem_uri = s;
		dlg.rem_dname.s = NULL;
		dlg.rem_dname.len = 0;
	} else {
		/* display + URI */
		dlg.rem_uri.s = p+1;
		dlg.rem_uri.len = s.s+s.len - dlg.rem_uri.s;
		dlg.rem_dname.s = s.s;
		dlg.rem_dname.len = p - s.s;
	}
	LM_DBG("setting TO to <%.*s> + <%.*s>\n",
		dlg.rem_dname.len, dlg.rem_dname.s,
		dlg.rem_uri.len, dlg.rem_uri.s);

	/* BODY and Content-Type */
	if (p_body!=NULL) {
		if ( fixup_get_svalue(msg, (gparam_p)p_body, &body)<0 ) {
			LM_ERR("failed to extract BODY param\n");
			return -1;
		}
		if ( (p=q_memchr(body.s, ' ', body.len))==NULL ) {
			LM_ERR("Content Type not found in the beginning of body <%.*s>\n",
				body.len, body.s);
			return -1;
		}
		/* build the Content-type header */
		headers.len = CONTENT_TYPE_HDR_LEN + (p-body.s) + CRLF_LEN;
		if ( (headers.s=(char*)pkg_malloc(headers.len))==NULL ) {
			LM_ERR("failed to get pkg mem (needed %d)\n",headers.len);
			return -1;
		}
		memcpy( headers.s, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN);
		memcpy( headers.s+CONTENT_TYPE_HDR_LEN, body.s, p-body.s);
		memcpy( headers.s+CONTENT_TYPE_HDR_LEN+(p-body.s), CRLF, CRLF_LEN);
		/* set the body */
		body.len = body.s + body.len - (p+1);
		body.s = p + 1;
		LM_DBG("setting BODY to <%.*s> <%.*s>\n",
			headers.len, headers.s,
			body.len, body.s );
	} else {
		body.s = NULL;
		body.len = 0;
		headers.s = NULL;
		headers.len = 0;
	}

	/* context value */
	if (p_ctx!=NULL) {
		if ( fixup_get_svalue(msg, (gparam_p)p_ctx, &ctx.s)<0 ) {
			LM_ERR("failed to extract BODY param\n");
			if (p_body) pkg_free(headers.s);
			return -1;
		}
		LM_DBG("setting CTX AVP to <%.*s>\n", ctx.s.len, ctx.s.s);
		avp_list = set_avp_list( &dlg.avps );
		if (!add_avp( AVP_VAL_STR, uac_ctx_avp_id, ctx))
			LM_ERR("failed to add ctx AVP, ignorring...\n");
		set_avp_list( avp_list );
	}

	/* add cseq */
	dlg.loc_seq.value = DEFAULT_CSEQ;
	dlg.loc_seq.is_set = 1;

	/* add callid */
	generate_callid(&dlg.id.call_id);

	/* add FROM tag */
	generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
	/* TO tag is empty as this is a initial request */
	dlg.id.rem_tag.s = NULL;
	dlg.id.rem_tag.len = 0;

	/* do the actual sending now */
	if ( t_uac( &method, headers.s?&headers:NULL, body.s?&body:NULL,
	&dlg, 0, 0, 0) <= 0 ) {
		LM_ERR("failed to send the request out\n");
		if (headers.s) pkg_free(headers.s);
		if (dlg.avps) destroy_avp_list(&dlg.avps);
		return -1;
	}

	/* success -> do cleanup */
	if (headers.s) pkg_free(headers.s);
	return 1;
}
Esempio n. 10
0
int t_uac_send(str *method, str *ruri, str *nexthop, str *send_socket,
		str *headers, str *body)
{
	str hfb, callid;
	struct sip_uri p_uri, pnexthop;
	struct sip_msg faked_msg;
	struct socket_info* ssock;
	str saddr;
	int sport, sproto;
	int ret, fromtag, cseq_is, cseq;
	dlg_t dlg;
	uac_req_t uac_req;

	ret = -1;

	/* check and parse parameters */
	if (method->len<=0){
		LM_ERR("Empty method");
		return -1;
	}
	if (parse_uri(ruri->s, ruri->len, &p_uri)<0){
		LM_ERR("Invalid request uri \"%s\"", ruri->s);
		return -1;
	}
	if (nexthop->len==1 && nexthop->s[0]=='.'){
		/* empty nextop */
		nexthop->len=0;
		nexthop->s=0;
	}else if (nexthop->len==0){
		nexthop->s=0;
	}else if (parse_uri(nexthop->s, nexthop->len, &pnexthop)<0){
		LM_ERR("Invalid next-hop uri \"%s\"", nexthop->s);
		return -1;
	}
	ssock=0;
	saddr.s=0;
	saddr.len=0;
	if (send_socket->len==1 && send_socket->s[0]=='.'){
		/* empty send socket */
		send_socket->len=0;
	}else if (send_socket->len &&
			(parse_phostport(send_socket->s, &saddr.s, &saddr.len,
							 &sport, &sproto)!=0 ||
			 /* check also if it's not a MH addr. */
			 saddr.len==0 || saddr.s[0]=='(')
			){
		LM_ERR("Invalid send socket \"%s\"", send_socket->s);
		return -1;
	}else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
		LM_ERR("No local socket for \"%s\"", send_socket->s);
		return -1;
	}
	/* check headers using the SIP parser to look in the header list */
	memset(&faked_msg, 0, sizeof(struct sip_msg));
	faked_msg.len=headers->len;
	faked_msg.buf=faked_msg.unparsed=headers->s;
	if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){
		LM_ERR("Invalid headers");
		return -1;
	}
	/* at this moment all the parameters are parsed => more sanity checks */
	if (t_uac_check_msg(&faked_msg, method, body, &fromtag,
				&cseq_is, &cseq, &callid)<0) {
		LM_ERR("checking values failed\n");
		goto error;
	}
	hfb.s=get_hfblock(nexthop->len? nexthop: ruri, faked_msg.headers,
			PROTO_NONE, ssock, &hfb.len);
	if (hfb.s==0){
		LM_ERR("out of memory");
		goto error;
	}
	/* proceed to transaction creation */
	memset(&dlg, 0, sizeof(dlg_t));
	/* fill call-id if call-id present or else generate a callid */
	if (callid.s && callid.len) dlg.id.call_id=callid;
	else generate_callid(&dlg.id.call_id);

	/* We will not fill in dlg->id.rem_tag because
	 * if present it will be printed within To HF
	 */

	/* Generate fromtag if not present */
	if (!fromtag) {
		generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
	}

	/* Fill in CSeq */
	if (cseq_is) dlg.loc_seq.value = cseq;
	else dlg.loc_seq.value = DEFAULT_CSEQ;
	dlg.loc_seq.is_set = 1;

	dlg.loc_uri = faked_msg.from->body;
	dlg.rem_uri = faked_msg.to->body;
	dlg.rem_target = *ruri;
	dlg.dst_uri = *nexthop;
	dlg.send_sock=ssock;

	memset(&uac_req, 0, sizeof(uac_req));
	uac_req.method=method;
	uac_req.headers=&hfb;
	uac_req.body=body->len?body:0;
	uac_req.dialog=&dlg;

	ret = t_uac(&uac_req);

	if (ret <= 0) {
		LM_ERR("UAC error");
		goto error01;
	}
error01:
	if (hfb.s) pkg_free(hfb.s);
error:
	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);

	return ret;
}
Esempio n. 11
0
/** rpc t_uac version-
 * It expects the following list of strings as parameters:
 *  method
 *  request_uri
 *  dst_uri (next hop) -- can be empty (either "" or ".", which is still
 *                        supported for backwards compatibility with fifo)
 *  send_socket (socket from which the message will be sent)
 *  headers (message headers separated by CRLF, at least From and To
 *           must be present)
 *  body (optional, might be null or completely missing)
 *
 * If all the parameters are ok it will call t_uac() using them.
 * Note: this version will  wait for the transaction final reply
 * only if reply_wait is set to 1. Otherwise the rpc reply will be sent
 * immediately and it will be success if the paremters were ok and t_uac did
 * not report any error.
 * Note: reply waiting (reply_wait==1) is not yet supported.
 * @param rpc - rpc handle
 * @param  c - rpc current context
 * @param reply_wait - if 1 do not generate a rpc reply until final response
 *                     for the transaction arrives, if 0 immediately send
 *                     an rpc reply (see above).
 */
static void rpc_t_uac(rpc_t* rpc, void* c, int reply_wait)
{
	/* rpc params */
	str method, ruri, nexthop, send_socket, headers, body;
	/* other internal vars.*/
	str hfb, callid;
	struct sip_uri p_uri, pnexthop;
	struct sip_msg faked_msg;
	struct socket_info* ssock;
	str saddr;
	int sport, sproto;
	int ret, sip_error, err_ret, fromtag, cseq_is, cseq;
	char err_buf[MAX_REASON_LEN];
	dlg_t dlg;
	uac_req_t uac_req;
	rpc_delayed_ctx_t* dctx;

	body.s=0;
	body.len=0;
	dctx=0;
	if (reply_wait && (rpc->capabilities == 0 ||
				!(rpc->capabilities(c) & RPC_DELAYED_REPLY))) {
		rpc->fault(c, 600, "Reply wait/async mode not supported"
				" by this rpc transport");
		return;
	}
	ret=rpc->scan(c, "SSSSS*S",
			&method, &ruri, &nexthop, &send_socket, &headers, &body);
	if (ret<5 && ! (-ret == 5)){
		rpc->fault(c, 400, "too few parameters (%d/5)", ret?ret:-ret);
		return;
	}
	/* check and parse parameters */
	if (method.len==0){
		rpc->fault(c, 400, "Empty method");
		return;
	}
	if (parse_uri(ruri.s, ruri.len, &p_uri)<0){
		rpc->fault(c, 400, "Invalid request uri \"%s\"", ruri.s);
		return;
	}
	/* old fifo & unixsock backwards compatibility for nexthop: '.' is still
	   allowed */
	if (nexthop.len==1 && nexthop.s[0]=='.'){
		/* empty nextop */
		nexthop.len=0;
		nexthop.s=0;
	}else if (nexthop.len==0){
		nexthop.s=0;
	}else if (parse_uri(nexthop.s, nexthop.len, &pnexthop)<0){
		rpc->fault(c, 400, "Invalid next-hop uri \"%s\"", nexthop.s);
		return;
	}
	/* kamailio backwards compatibility for send_socket: '.' is still
	   allowed for an empty socket */
	ssock=0;
	saddr.s=0;
	saddr.len=0;
	if (send_socket.len==1 && send_socket.s[0]=='.'){
		/* empty send socket */
		send_socket.len=0;
	}else if (send_socket.len &&
			(parse_phostport(send_socket.s, &saddr.s, &saddr.len,
							 &sport, &sproto)!=0 ||
			 /* check also if it's not a MH addr. */
			 saddr.len==0 || saddr.s[0]=='(')
			){
		rpc->fault(c, 400, "Invalid send socket \"%s\"", send_socket.s);
		return;
	}else if (saddr.len && (ssock=grep_sock_info(&saddr, sport, sproto))==0){
		rpc->fault(c, 400, "No local socket for \"%s\"", send_socket.s);
		return;
	}
	/* check headers using the SIP parser to look in the header list */
	memset(&faked_msg, 0, sizeof(struct sip_msg));
	faked_msg.len=headers.len;
	faked_msg.buf=faked_msg.unparsed=headers.s;
	if (parse_headers(&faked_msg, HDR_EOH_F, 0)==-1){
		rpc->fault(c, 400, "Invalid headers");
		return;
	}
	/* at this moment all the parameters are parsed => more sanity checks */
	if (rpc_uac_check_msg(rpc, c, &faked_msg, &method, &body, &fromtag,
				&cseq_is, &cseq, &callid)<0)
		goto error;
	hfb.s=get_hfblock(nexthop.len? &nexthop: &ruri, faked_msg.headers,
			PROTO_NONE, ssock, &hfb.len);
	if (hfb.s==0){
		rpc->fault(c, 500, "out of memory");
		goto error;
	}
	/* proceed to transaction creation */
	memset(&dlg, 0, sizeof(dlg_t));
	/* fill call-id if call-id present or else generate a callid */
	if (callid.s && callid.len) dlg.id.call_id=callid;
	else generate_callid(&dlg.id.call_id);

	/* We will not fill in dlg->id.rem_tag because
	 * if present it will be printed within To HF
	 */

	/* Generate fromtag if not present */
	if (!fromtag) {
		generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
	}

	/* Fill in CSeq */
	if (cseq_is) dlg.loc_seq.value = cseq;
	else dlg.loc_seq.value = DEFAULT_CSEQ;
	dlg.loc_seq.is_set = 1;

	dlg.loc_uri = faked_msg.from->body;
	dlg.rem_uri = faked_msg.to->body;
	dlg.rem_target = ruri;
	dlg.dst_uri = nexthop;
	dlg.send_sock=ssock;

	memset(&uac_req, 0, sizeof(uac_req));
	uac_req.method=&method;
	uac_req.headers=&hfb;
	uac_req.body=body.len?&body:0;
	uac_req.dialog=&dlg;
	if (reply_wait){
		dctx=rpc->delayed_ctx_new(c);
		if (dctx==0){
			rpc->fault(c, 500, "internal error: failed to create context");
			return;
		}
		uac_req.cb=rpc_uac_callback;
		uac_req.cbp=dctx;
		uac_req.cb_flags=TMCB_LOCAL_COMPLETED;
		/* switch to dctx, in case adding the callback fails and we
		   want to still send a reply */
		rpc=&dctx->rpc;
		c=dctx->reply_ctx;
	}
	ret = t_uac(&uac_req);

	if (ret <= 0) {
		err_ret = err2reason_phrase(ret, &sip_error, err_buf,
				sizeof(err_buf), "RPC/UAC") ;
		if (err_ret > 0 )
		{
			rpc->fault(c, sip_error, "%s", err_buf);
		} else {
			rpc->fault(c, 500, "RPC/UAC error");
		}
		if (dctx)
			rpc->delayed_ctx_close(dctx);
		goto error01;
	}
error01:
	if (hfb.s) pkg_free(hfb.s);
error:
	if (faked_msg.headers) free_hdr_field_lst(faked_msg.headers);
}