示例#1
0
/*!
 * get the To-tag for stateless reply
 */
int sl_get_reply_totag(struct sip_msg *msg, str *totag)
{
    if(msg==NULL || totag==NULL)
        return -1;
    calc_crc_suffix(msg, tag_suffix);
    *totag = sl_tag;
    return 1;
}
示例#2
0
/*
 * Establishing a new dialog, UAS side
 */
int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d)
{
	dlg_t* res;
	str tag;

	if (!_req || /*!_tag ||*/ !_d) {
		LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n");
		return -1;
	}

	if (_code > 299) {
		DBG("new_dlg_uas(): Status code >= 300, no dialog created\n");
	}

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

	if (request2dlg(_req, res) < 0) {
		LOG(L_ERR, "new_dlg_uas(): Error while converting request to dialog\n");
		free_dlg(res);
		return -4;
	}

	if (_code > 100) {
		tag.s = tm_tags;
		tag.len = TOTAG_VALUE_LEN;
		calc_crc_suffix(_req, tm_tag_suffix);
		if (str_duplicate(&res->id.loc_tag, &tag) < 0) {
			free_dlg(res);
			return -5;
		}
	}
	
	*_d = res;

	if (_code < 100)
		(*_d)->state = DLG_NEW;
	else if (_code < 200)
		(*_d)->state = DLG_EARLY;
	else
		(*_d)->state = DLG_CONFIRMED;

	if (calculate_hooks(*_d) < 0) {
		LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n");
		free_dlg(res);
		return -6;
	}
#ifdef DIALOG_CALLBACKS
	run_new_dlg_callbacks(DLG_CB_UAS, res, _req);
#endif

	return 0;
}
示例#3
0
/* Returns:
    0  : ACK to a local reply
    -1 : error
    1  : is not an ACK  or a non-local ACK
*/
int sl_filter_ACK(struct sip_msg *msg, unsigned int flags, void *bar )
{
    str *tag_str;

    if (msg->first_line.u.request.method_value!=METHOD_ACK)
        goto pass_it;

    /*check the timeout value*/
    if ( *(sl_timeout)<= get_ticks() )
    {
        DBG("DEBUG : sl_filter_ACK: to late to be a local ACK!\n");
        goto pass_it;
    }

    /*force to parse to header -> we need it for tag param*/
    if (parse_headers( msg, HDR_TO_F, 0 )==-1)
    {
        LOG(L_ERR,"ERROR : SL_FILTER_ACK: unable to parse To header\n");
        return -1;
    }

    if (msg->to) {
        tag_str = &(get_to(msg)->tag_value);
        if ( tag_str->len==TOTAG_VALUE_LEN )
        {
            /* calculate the variable part of to-tag */
            calc_crc_suffix(msg, tag_suffix);
            /* test whether to-tag equal now */
            if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) {
                LM_DBG("SL local ACK found -> dropping it!\n" );
                update_sl_filtered_acks();
                sl_run_callbacks(SLCB_ACK_FILTERED, msg, 0, 0, 0, 0);
                if(unlikely(_sl_filtered_ack_route>=0)) {
                    run_top_route(event_rt.rlist[_sl_filtered_ack_route],
                                  msg, 0);
                }
                return 0;
            }
        }
    }

pass_it:
    return 1;
}
示例#4
0
/* Returns:
    0  : ACK to a local reply
    -1 : error
    1  : is not an ACK  or a non-local ACK
*/
int sl_filter_ACK(struct sip_msg *msg, void *bar )
{
	str *tag_str;

	if (msg->first_line.u.request.method_value!=METHOD_ACK)
		goto pass_it;

	/*check the timeout value*/
	if ( *(sl_timeout)<= get_ticks() )
	{
		LM_DBG("to late to be a local ACK!\n");
		goto pass_it;
	}

	/*force to parse to header -> we need it for tag param*/
	if (parse_headers( msg, HDR_TO_F, 0 )==-1)
	{
		LM_ERR("unable to parse To header\n");
		return -1;
	}

	if (msg->to) {
		tag_str = &(get_to(msg)->tag_value);
		if ( tag_str->len==TOTAG_VALUE_LEN )
		{
			/* calculate the variable part of to-tag */	
			calc_crc_suffix(msg, tag_suffix);
			/* test whether to-tag equal now */
			if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) {
				LM_DBG("local ACK found -> dropping it!\n");
				if_update_stat( sl_enable_stats, rcv_acks, 1);
				run_sl_callbacks( SLCB_ACK_IN, msg, 0, 0, 0, 0 );
				return 0;
			}
		}
	}

pass_it:
	return 1;
}
示例#5
0
文件: t_reply.c 项目: iamroger/voip
/* send a UAS reply
 * returns 1 if everything was OK or -1 for error
 */
static int _reply( struct cell *trans, struct sip_msg* p_msg, 
									unsigned int code, str *text, int lock )
{
	unsigned int len;
	char * buf, *dset;
	struct bookmark bm;
	int dset_len;

	if (code>=200) set_kr(REQ_RPLD);
	/* compute the buffer in private memory prior to entering lock;
	 * create to-tag if needed */

	/* if that is a redirection message, dump current message set to it */
	if (code>=300 && code<400) {
		dset=print_dset(p_msg, &dset_len);
		if (dset) {
			add_lump_rpl(p_msg, dset, dset_len, LUMP_RPL_HDR);
		}
	}

	/* check if the UAS retranmission port needs to be updated */
	if ( (p_msg->msg_flags ^ trans->uas.request->msg_flags) & FL_FORCE_RPORT )
		su_setport( &trans->uas.response.dst.to, p_msg->rcv.src_port );

	if (code>=180 && p_msg->to 
				&& (get_to(p_msg)->tag_value.s==0 
			    || get_to(p_msg)->tag_value.len==0)) {
		calc_crc_suffix( p_msg, tm_tag_suffix );
		buf = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg, &len, &bm);
		return _reply_light( trans, buf, len, code,
			tm_tag.s, TOTAG_VALUE_LEN, lock, &bm);
	} else {
		buf = build_res_buf_from_sip_req(code,text, 0 /*no to-tag*/,
			p_msg, &len, &bm);

		return _reply_light(trans,buf,len,code, 0, 0 /* no to-tag */,
			lock, &bm);
	}
}
示例#6
0
/* Returns:
    0  : ACK to a local reply
    -1 : error
    1  : is not an ACK  or a non-local ACK
*/
int sl_filter_ACK(struct sip_msg *msg, void *bar )
{
	str *tag_str;

	if (msg->first_line.u.request.method_value!=METHOD_ACK)
		goto pass_it;

	/*check the timeout value*/
	if ( *(sl_timeout)<= get_ticks() )
	{
		DBG("DEBUG : sl_filter_ACK: to late to be a local ACK!\n");
		goto pass_it;
	}

	/*force to parse to header -> we need it for tag param*/
	if (parse_headers( msg, HDR_TO_F, 0 )==-1)
	{
		LOG(L_ERR,"ERROR : SL_FILTER_ACK: unable to parse To header\n");
		return -1;
	}

	if (msg->to) {
		tag_str = &(get_to(msg)->tag_value);
		if ( tag_str->len==TOTAG_VALUE_LEN )
		{
			/* calculate the variable part of to-tag */	
			calc_crc_suffix(msg, tag_suffix);
			/* test whether to-tag equal now */
			if (memcmp(tag_str->s,sl_tag.s,sl_tag.len)==0) {
				DBG("DEBUG: sl_filter_ACK : local ACK found -> dropping it! \n" );
				return 0;
			}
		}
	}

pass_it:
	return 1;
}
示例#7
0
文件: t_reply.c 项目: iamroger/voip
int t_reply_with_body( struct cell *trans, unsigned int code, str *text,
									str *body, str *new_header, str *to_tag )
{
	struct lump_rpl *hdr_lump;
	struct lump_rpl *body_lump;
	str  rpl;
	int  ret;
	struct bookmark bm;
	struct sip_msg* p_msg = trans->uas.request;
	str to_tag_rpl= {0, 0};

	/* add the lumps for new_header and for body (by bogdan) */
	if (new_header && new_header->len) {
		hdr_lump = add_lump_rpl( p_msg, new_header->s,
			new_header->len, LUMP_RPL_HDR );
		if ( !hdr_lump ) {
			LM_ERR("failed to add hdr lump\n");
			goto error;
		}
	} else {
		hdr_lump = 0;
	}

	/* body lump */
	if(body && body->len) {
		body_lump = add_lump_rpl( p_msg, body->s, body->len,
			LUMP_RPL_BODY );
		if (body_lump==0) {
			LM_ERR("failed add body lump\n");
			goto error_1;
		}
	} else {
		body_lump = 0;
	}

	if(to_tag && to_tag->len) {
		rpl.s = build_res_buf_from_sip_req(code, text, to_tag, p_msg,
		 	(unsigned int*)&rpl.len, &bm);
		to_tag_rpl = *to_tag;
	}
	else
	if (code>=180 && p_msg->to && (get_to(p_msg)->tag_value.s==0 
			|| get_to(p_msg)->tag_value.len==0)) {
		calc_crc_suffix( p_msg, tm_tag_suffix );
		rpl.s = build_res_buf_from_sip_req(code,text, &tm_tag, p_msg,
				(unsigned int*)&rpl.len, &bm);
		to_tag_rpl.s = tm_tag.s;
		to_tag_rpl.len = TOTAG_VALUE_LEN;
	} else {
		rpl.s = build_res_buf_from_sip_req(code,text, 0 /*no to-tag*/,
			p_msg, (unsigned int*)&rpl.len, &bm);
	}

	/* since the msg (trans->uas.request) is a clone into shm memory, to avoid
	 * memory leak or crashing (lumps are create in private memory) I will
	 * remove the lumps by myself here (bogdan) */
	if ( hdr_lump ) {
		unlink_lump_rpl( p_msg, hdr_lump);
		free_lump_rpl( hdr_lump );
	}
	if( body_lump ) {
		unlink_lump_rpl( p_msg, body_lump);
		free_lump_rpl( body_lump );
	}

	if (rpl.s==0) {
		LM_ERR("failed in doing build_res_buf_from_sip_req()\n");
		goto error;
	}
	ret=_reply_light( trans, rpl.s, rpl.len, code, to_tag_rpl.s, to_tag_rpl.len,
			1 /* lock replies */, &bm );

	/* mark the transaction as replied */
	if (code>=200) set_kr(REQ_RPLD);

	return ret;
error_1:
	if ( hdr_lump ) {
		unlink_lump_rpl( p_msg, hdr_lump);
		free_lump_rpl( hdr_lump );
	}
error:
	return -1;
}
示例#8
0
文件: t_reply.c 项目: iamroger/voip
/* this is the code which decides what and when shall be relayed
   upstream; note well -- it assumes it is entered locked with 
   REPLY_LOCK and it returns unlocked!
*/
enum rps relay_reply( struct cell *t, struct sip_msg *p_msg, int branch, 
	unsigned int msg_status, branch_bm_t *cancel_bitmap )
{
	int relay;
	int save_clone;
	char *buf;
	/* length of outbound reply */
	unsigned int res_len;
	int relayed_code;
	struct sip_msg *relayed_msg;
	struct bookmark bm;
	int totag_retr;
	enum rps reply_status;
	/* retransmission structure of outbound reply and request */
	struct retr_buf *uas_rb;
	str cb_s;
	str text;

	/* keep compiler warnings about use of uninit vars silent */
	res_len=0;
	buf=0;
	relayed_msg=0;
	relayed_code=0;
	totag_retr=0;


	/* remember, what was sent upstream to know whether we are
	 * forwarding a first final reply or not */

	/* *** store and relay message as needed *** */
	reply_status = t_should_relay_response(t, msg_status, branch, 
		&save_clone, &relay, cancel_bitmap, p_msg );
	LM_DBG("branch=%d, save=%d, relay=%d\n",
		branch, save_clone, relay );

	/* store the message if needed */
	if (save_clone) /* save for later use, typically branch picking */
	{
		if (!store_reply( t, branch, p_msg ))
			goto error01;
	}

	uas_rb = & t->uas.response;
	if (relay >= 0 ) {
		/* initialize sockets for outbound reply */
		uas_rb->activ_type=msg_status;

		t->relaied_reply_branch = relay;

		/* try building the outbound reply from either the current
		 * or a stored message */
		relayed_msg = branch==relay ? p_msg :  t->uac[relay].reply;
		if (relayed_msg==FAKED_REPLY) {
			relayed_code = branch==relay
				? msg_status : t->uac[relay].last_received;

			text.s = error_text(relayed_code);
			text.len = strlen(text.s); /* FIXME - bogdan*/

			if (relayed_code>=180 && t->uas.request->to 
					&& (get_to(t->uas.request)->tag_value.s==0 
					|| get_to(t->uas.request)->tag_value.len==0)) {
				calc_crc_suffix( t->uas.request, tm_tag_suffix );
				buf = build_res_buf_from_sip_req(
						relayed_code,
						&text,
						&tm_tag,
						t->uas.request, &res_len, &bm );
			} else {
				buf = build_res_buf_from_sip_req( relayed_code,
					&text, 0/* no to-tag */,
					t->uas.request, &res_len, &bm );
			}

		} else {
			/* run callbacks for all types of responses -
			 * even if they are shmem-ed or not */
			if (has_tran_tmcbs(t,TMCB_RESPONSE_FWDED) ) {
				run_trans_callbacks( TMCB_RESPONSE_FWDED, t, t->uas.request,
					relayed_msg, msg_status );
			}
			relayed_code=relayed_msg->REPLY_STATUS;
			buf = build_res_buf_from_sip_res( relayed_msg, &res_len,
							uas_rb->dst.send_sock);
			/* remove all lumps which are not in shm 
			 * added either by build_res_buf_from_sip_res, or by
			 * the callbacks that have been called with shmem-ed messages - vlad */
			if (branch!=relay) {
				del_notflaged_lumps( &(relayed_msg->add_rm), LUMPFLAG_SHMEM);
				del_notflaged_lumps( &(relayed_msg->body_lumps), LUMPFLAG_SHMEM);
			}
		}
		if (!buf) {
			LM_ERR("no mem for outbound reply buffer\n");
			goto error02;
		}

		/* attempt to copy the message to UAS's shmem:
		   - copy to-tag for ACK matching as well
		   -  allocate little a bit more for provisional as
		      larger messages are likely to follow and we will be 
		      able to reuse the memory frag 
		*/
		uas_rb->buffer.s = (char*)shm_resize( uas_rb->buffer.s, res_len +
			(msg_status<200 ?  REPLY_OVERBUFFER_LEN : 0));
		if (!uas_rb->buffer.s) {
			LM_ERR("no more share memory\n");
			goto error03;
		}
		uas_rb->buffer.len = res_len;
		memcpy( uas_rb->buffer.s, buf, res_len );
		if (relayed_msg==FAKED_REPLY) { /* to-tags for local replies */
			update_local_tags(t, &bm, uas_rb->buffer.s, buf);
		}
		stats_trans_rpl( relayed_code, (relayed_msg==FAKED_REPLY)?1:0 );

		/* update the status ... */
		t->uas.status = relayed_code;

		if (is_invite(t) && relayed_msg!=FAKED_REPLY
		&& relayed_code>=200 && relayed_code < 300
		&& has_tran_tmcbs( t,
		TMCB_RESPONSE_OUT|TMCB_RESPONSE_PRE_OUT)) {
			totag_retr=update_totag_set(t, relayed_msg);
		}
	}; /* if relay ... */

	UNLOCK_REPLIES( t );

	/* Setup retransmission timer _before_ the reply is sent
	 * to avoid race conditions
	 */
	if (reply_status == RPS_COMPLETED) {
		/* for auth related replies, we do not do retransmission 
		   (via set_final_timer()), but only wait for a final 
		   reply (put_on_wait() ) - see RFC 3261 (26.3.2.4 DoS Protection) */
		if ((relayed_code != 401) && (relayed_code != 407))
			set_final_timer(t);
		else
			put_on_wait(t);
	}

	/* send it now (from the private buffer) */
	if (relay >= 0) {
		/* run the PRE sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_PRE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked(TMCB_RESPONSE_PRE_OUT,t,t->uas.request,
				relayed_msg, relayed_code);
		}
		SEND_PR_BUFFER( uas_rb, buf, res_len );
		LM_DBG("sent buf=%p: %.9s..., shmem=%p: %.9s\n", 
			buf, buf, uas_rb->buffer.s, uas_rb->buffer.s );
		/* run the POST sending out callback */
		if (!totag_retr && has_tran_tmcbs(t, TMCB_RESPONSE_OUT) ) {
			cb_s.s = buf;
			cb_s.len = res_len;
			set_extra_tmcb_params( &cb_s, &uas_rb->dst);
			run_trans_callbacks_locked( TMCB_RESPONSE_OUT, t, t->uas.request,
				relayed_msg, relayed_code);
		}
		pkg_free( buf );
	}

	/* success */
	return reply_status;

error03:
	pkg_free( buf );
error02:
	if (save_clone) {
		if (t->uac[branch].reply!=FAKED_REPLY)
			sip_msg_free( t->uac[branch].reply );
		t->uac[branch].reply = NULL;
	}
error01:
	text.s = "Reply processing error";
	text.len = sizeof("Reply processing error")-1;
	t_reply_unsafe( t, t->uas.request, 500, &text );
	UNLOCK_REPLIES(t);
	if (is_invite(t)) cancel_uacs( t, *cancel_bitmap );
	/* a serious error occurred -- attempt to send an error reply;
	   it will take care of clean-ups  */

	/* failure */
	return RPS_ERROR;
}
示例#9
0
int sl_send_reply_helper(struct sip_msg *msg ,int code, str *text)
{
	str buf;
	union sockaddr_union to;
	char *dset;
	int dset_len;
	struct bookmark dummy_bm;
	int backup_mhomed;
	int ret;

	if ( msg->REQ_METHOD==METHOD_ACK)
		return 0;

	update_sock_struct_from_ip( &to, msg );

	/* if that is a redirection message, dump current message set to it */
	if (code>=300 && code<400) {
		dset=print_dset(msg, &dset_len);
		if (dset) {
			add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR);
		}
	}

	/* add a to-tag if there is a To header field without it */
	if ( code>=180 &&
		(msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to))
		&& (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) 
	{
		calc_crc_suffix( msg, tag_suffix );
		buf.s = build_res_buf_from_sip_req( code, text, &sl_tag, msg,
			(unsigned int*)&buf.len, &dummy_bm);
	} else {
		buf.s = build_res_buf_from_sip_req( code, text, 0, msg,
			(unsigned int*)&buf.len, &dummy_bm);
	}
	if (!buf.s) {
		LM_ERR("response building failed\n");
		goto error;
	}

	run_sl_callbacks( SLCB_REPLY_OUT, msg, &buf, code, text, &to );

	/* supress multhoming support when sending a reply back -- that makes sure
	   that replies will come from where requests came in; good for NATs
	   (there is no known use for mhomed for locally generated replies;
	    note: forwarded cross-interface replies do benefit of mhomed!
	*/
	backup_mhomed=mhomed;
	mhomed=0;
	/* use for sending the received interface -bogdan*/
	ret = msg_send( msg->rcv.bind_address, msg->rcv.proto, &to,
			msg->rcv.proto_reserved1, buf.s, buf.len);
	mhomed=backup_mhomed;
	pkg_free(buf.s);

	if (ret<0)
		goto error;

	*(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;

	update_sl_reply_stat(code);

	return 1;

error:
	return -1;
}
示例#10
0
int sl_send_reply(struct sip_msg *msg , int code, char* reason)
{
	char *buf, *dset;
	unsigned int len;
	struct dest_info dst;
	struct bookmark dummy_bm;
	int backup_mhomed, ret, dset_len;


	if ( msg->first_line.u.request.method_value==METHOD_ACK)
	{
		LOG(L_WARN, "Warning: sl_send_reply: I won't send a reply for ACK!!\n");
		goto error;
	}
	init_dest_info(&dst);
	if (reply_to_via) {
		if (update_sock_struct_from_via(  &dst.to, msg, msg->via1 )==-1)
		{
			LOG(L_ERR, "ERROR: sl_send_reply: "
				"cannot lookup reply dst: %s\n",
				msg->via1->host.s );
			goto error;
		}
	} else update_sock_struct_from_ip( &dst.to, msg );

	/* if that is a redirection message, dump current message set to it */
	if (code>=300 && code<400) {
		dset=print_dset(msg, &dset_len);
		if (dset) {
			add_lump_rpl(msg, dset, dset_len, LUMP_RPL_HDR);
		}
	}

	/* add a to-tag if there is a To header field without it */
	if ( 	/* since RFC3261, we append to-tags anywhere we can, except
		 * 100 replies */
       		/* msg->first_line.u.request.method_value==METHOD_INVITE && */
		code>=180 &&
		(msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to))
		&& (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) ) 
	{
		calc_crc_suffix( msg, tag_suffix );
		buf = build_res_buf_from_sip_req(code,reason,&sl_tag,msg,&len,&dummy_bm);
	} else {
		buf = build_res_buf_from_sip_req(code,reason,0,msg,&len,&dummy_bm);
	}
	if (!buf)
	{
		DBG("DEBUG: sl_send_reply: response building failed\n");
		goto error;
	}
	

	/* supress multhoming support when sending a reply back -- that makes sure
	   that replies will come from where requests came in; good for NATs
	   (there is no known use for mhomed for locally generated replies;
	    note: forwarded cross-interface replies do benefit of mhomed!
	*/
	backup_mhomed=mhomed;
	mhomed=0;
	/* use for sending the received interface -bogdan*/
	dst.proto=msg->rcv.proto;
	dst.send_sock=msg->rcv.bind_address;
	dst.id=msg->rcv.proto_reserved1;
#ifdef USE_COMP
	dst.comp=msg->via1->comp_no;
#endif
	ret = msg_send(&dst, buf, len);
	mhomed=backup_mhomed;
	pkg_free(buf);

	if (ret<0) {
		goto error;
	}
	
	*(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;

	update_sl_stats(code);
	return 1;

error:
	update_sl_failures();
	return -1;
}
示例#11
0
/*!
 * helper function for stateless reply
 */
int sl_reply_helper(struct sip_msg *msg, int code, char *reason, str *tag)
{
    str buf = {0, 0};
    str dset = {0, 0};
    struct dest_info dst;
    struct bookmark dummy_bm;
    int backup_mhomed, ret;
    str text;

    int rt, backup_rt;
    struct run_act_ctx ctx;
    struct sip_msg pmsg;

    if (msg->first_line.u.request.method_value==METHOD_ACK)
        goto error;

    init_dest_info(&dst);
    if (reply_to_via) {
        if (update_sock_struct_from_via(&dst.to, msg, msg->via1 )==-1)
        {
            LOG(L_ERR, "ERROR: sl_reply_helper: cannot lookup reply dst: %s\n",
                msg->via1->host.s);
            goto error;
        }
    } else update_sock_struct_from_ip(&dst.to, msg);

    /* if that is a redirection message, dump current message set to it */
    if (code>=300 && code<400) {
        dset.s=print_dset(msg, &dset.len);
        if (dset.s) {
            add_lump_rpl(msg, dset.s, dset.len, LUMP_RPL_HDR);
        }
    }

    text.s = reason;
    text.len = strlen(reason);

    /* add a to-tag if there is a To header field without it */
    if ( 	/* since RFC3261, we append to-tags anywhere we can, except
		 * 100 replies */
        /* msg->first_line.u.request.method_value==METHOD_INVITE && */
        code>=180 &&
        (msg->to || (parse_headers(msg,HDR_TO_F, 0)!=-1 && msg->to))
        && (get_to(msg)->tag_value.s==0 || get_to(msg)->tag_value.len==0) )
    {
        if(tag!=NULL && tag->s!=NULL) {
            buf.s = build_res_buf_from_sip_req(code, &text, tag,
                                               msg, (unsigned int*)&buf.len, &dummy_bm);
        } else {
            calc_crc_suffix( msg, tag_suffix );
            buf.s = build_res_buf_from_sip_req(code, &text, &sl_tag, msg,
                                               (unsigned int*)&buf.len, &dummy_bm);
        }
    } else {
        buf.s = build_res_buf_from_sip_req(code, &text, 0, msg,
                                           (unsigned int*)&buf.len, &dummy_bm);
    }
    if (!buf.s)
    {
        DBG("DEBUG: sl_reply_helper: response building failed\n");
        goto error;
    }

    sl_run_callbacks(SLCB_REPLY_READY, msg, code, reason, &buf, &dst);

    /* supress multhoming support when sending a reply back -- that makes sure
       that replies will come from where requests came in; good for NATs
       (there is no known use for mhomed for locally generated replies;
        note: forwarded cross-interface replies do benefit of mhomed!
    */
    backup_mhomed=mhomed;
    mhomed=0;
    /* use for sending the received interface -bogdan*/
    dst.proto=msg->rcv.proto;
    dst.send_sock=msg->rcv.bind_address;
    dst.id=msg->rcv.proto_reserved1;
#ifdef USE_COMP
    dst.comp=msg->via1->comp_no;
#endif
    dst.send_flags=msg->rpl_send_flags;
    ret = msg_send(&dst, buf.s, buf.len);
    mhomed=backup_mhomed;

    rt = route_lookup(&event_rt, "sl:local-response");
    if (unlikely(rt >= 0 && event_rt.rlist[rt] != NULL))
    {
        if (likely(build_sip_msg_from_buf(&pmsg, buf.s, buf.len,
                                          inc_msg_no()) == 0))
        {
            char *tmp = NULL;
            struct onsend_info onsnd_info;

            onsnd_info.to=&dst.to;
            onsnd_info.send_sock=dst.send_sock;
            onsnd_info.buf=buf.s;
            onsnd_info.len=buf.len;
            p_onsend=&onsnd_info;

            if (unlikely(!IS_SIP(msg)))
            {
                /* This is an HTTP reply...  So fudge in a CSeq into the parsed message
                   message structure so that $rm will work in the route */
                struct hdr_field *hf;
                struct cseq_body *cseqb;
                char *tmp2;
                int len;

                if ((hf = (struct hdr_field *) pkg_malloc(sizeof(struct hdr_field))) == NULL)
                {
                    LM_ERR("out of package memory\n");
                    goto event_route_error;
                }

                if ((cseqb = (struct cseq_body *) pkg_malloc(sizeof(struct cseq_body))) == NULL)
                {
                    LM_ERR("out of package memory\n");
                    pkg_free(hf);
                    goto event_route_error;
                }

                if ((tmp = (char *) pkg_malloc(sizeof(char) * (msg->first_line.u.request.method.len + 5))) == NULL)
                {
                    LM_ERR("out of package memory\n");
                    pkg_free(cseqb);
                    pkg_free(hf);
                    goto event_route_error;
                }

                memset(hf, 0, sizeof(struct hdr_field));
                memset(cseqb, 0, sizeof(struct cseq_body));

                len = sprintf(tmp, "0 %.*s\r\n", msg->first_line.u.request.method.len, msg->first_line.u.request.method.s);
                tmp2 = parse_cseq(tmp, &tmp[len], cseqb);

                hf->type = HDR_CSEQ_T;
                hf->body.s = tmp;
                hf->body.len = tmp2 - tmp;
                hf->parsed = cseqb;

                pmsg.parsed_flag|=HDR_CSEQ_F;
                pmsg.cseq = hf;
                if (pmsg.last_header==0) {
                    pmsg.headers=hf;
                    pmsg.last_header=hf;
                } else {
                    pmsg.last_header->next=hf;
                    pmsg.last_header=hf;
                }
            }

            backup_rt = get_route_type();
            set_route_type(LOCAL_ROUTE);
            init_run_actions_ctx(&ctx);
            run_top_route(event_rt.rlist[rt], &pmsg, 0);
            set_route_type(backup_rt);
            p_onsend=0;

            if (tmp != NULL)
                pkg_free(tmp);

event_route_error:
            free_sip_msg(&pmsg);
        }
    }

    pkg_free(buf.s);

    if (ret<0) {
        goto error;
    }

    *(sl_timeout) = get_ticks() + SL_RPL_WAIT_TIME;

    update_sl_stats(code);
    return 1;

error:
    update_sl_failures();
    return -1;
}