receive.c
888ca09d
 /* 
  *$Id$
7dd0b342
  *
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
  * This file is part of ser, a free SIP server.
  *
  * ser is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version
  *
  * For a license to use the ser software under conditions
  * other than those described here, or to purchase support for this
  * software, please contact iptel.org by e-mail at the following addresses:
  *    info@iptel.org
  *
  * ser is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License 
  * along with this program; if not, write to the Free Software 
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
049f64c2
  *
  * History:
  * ---------
18dbc018
  * 2003-02-28 scratchpad compatibility abandoned (jiri)
049f64c2
  * 2003-01-29 transport-independent message zero-termination in
  *            receive_msg (jiri)
ab130758
  * 2003-02-07 undoed jiri's zero term. changes (they break tcp) (andrei)
8fc80c33
  * 2003-02-10 moved zero-term in the calling functions (udp_receive &
  *            tcp_read_req)
4776dc11
  * 2003-08-13 fixed exec_pre_cb returning 0 (backported from stable) (andrei)
1580c821
  * 2004-02-06 added user preferences support - destroy_avps() (bogdan)
fa128269
  * 2004-04-30 exec_pre_cb is called after basic sanity checks (at least one
  *            via present & parsed ok)  (andrei)
2be21e31
  * 2004-08-23 avp core changed - destroy_avp-> reset_avps (bogdan)
ac34f9f4
  * 2006-11-29 nonsip_msg hooks called for non-sip msg (e.g HTTP) (andrei)
888ca09d
  */
 
1d0661db
 /*!
  * \file
  * \brief SIP-router core :: 
  * \ingroup core
  * Module: \ref core
  */
 
7dd0b342
 
888ca09d
 #include <string.h>
3e429f5c
 #include <stdlib.h>
4f3faaaf
 #include <sys/time.h>
888ca09d
 
 #include "receive.h"
4e2fdd79
 #include "globals.h"
888ca09d
 #include "dprint.h"
 #include "route.h"
3881f12c
 #include "parser/msg_parser.h"
888ca09d
 #include "forward.h"
3e429f5c
 #include "action.h"
dda9dab1
 #include "mem/mem.h"
 #include "stats.h"
4e2fdd79
 #include "ip_addr.h"
caf80ae6
 #include "script_cb.h"
ac34f9f4
 #include "nonsip_hooks.h"
caf80ae6
 #include "dset.h"
1580c821
 #include "usr_avp.h"
4075c49e
 #ifdef WITH_XAVP
 #include "xavp.h"
 #endif
8c5e4afe
 #include "select_buf.h"
2be21e31
 
59653eb8
 #include "tcp_server.h" /* for tcpconn_add_alias */
3dc4f620
 #include "tcp_options.h" /* for access to tcp_accept_aliases*/
 #include "cfg/cfg.h"
6b109fa2
 #include "core_stats.h"
5b253cc6
 
03150098
 #ifdef DEBUG_DMALLOC
dda9dab1
 #include <mem/dmalloc.h>
0a974a1d
 #endif
5b253cc6
 
e72b5b50
 unsigned int msg_no=0;
6bfaa042
 /* address preset vars */
 str default_global_address={0,0};
 str default_global_port={0,0};
 str default_via_address={0,0};
 str default_via_port={0,0};
 
61f86410
 /**
  * increment msg_no and return the new value
  */
 unsigned int inc_msg_no(void)
 {
 	return ++msg_no;
 }
e72b5b50
 
8fc80c33
 
 /* WARNING: buf must be 0 terminated (buf[len]=0) or some things might 
  * break (e.g.: modules/textops)
  */
f2f969dd
 int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) 
888ca09d
 {
22d4aa5d
 	struct sip_msg* msg;
05589c01
 	struct run_act_ctx ctx;
6b6642f4
 	int ret;
985f6f0f
 #ifdef STATS
 	int skipped = 1;
4f3faaaf
 	struct timeval tvb, tve;	
 	struct timezone tz;
 	unsigned int diff;
985f6f0f
 #endif
88b792e4
 	str inb;
 
 	inb.s = buf;
 	inb.len = len;
 	sr_event_exec(SREV_NET_DATA_IN, (void*)&inb);
 	len = inb.len;
e72b5b50
 
6fa79282
 	msg=pkg_malloc(sizeof(struct sip_msg));
caf80ae6
 	if (msg==0) {
 		LOG(L_ERR, "ERROR: receive_msg: no mem for sip_msg\n");
 		goto error00;
 	}
e72b5b50
 	msg_no++;
caf80ae6
 	/* number of vias parsed -- good for diagnostic info in replies */
 	via_cnt=0;
5b253cc6
 
22d4aa5d
 	memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
4ac74c03
 	/* fill in msg */
22d4aa5d
 	msg->buf=buf;
 	msg->len=len;
9b47a45c
 	/* zero termination (termination of orig message bellow not that
53c7e0f1
 	   useful as most of the work is done with scratch-pad; -jiri  */
6ee62314
 	/* buf[len]=0; */ /* WARNING: zero term removed! */
f2f969dd
 	msg->rcv=*rcv_info;
22d4aa5d
 	msg->id=msg_no;
6bfaa042
 	msg->set_global_address=default_global_address;
 	msg->set_global_port=default_global_port;
888ca09d
 	
22d4aa5d
 	if (parse_msg(buf,len, msg)!=0){
caf80ae6
 		LOG(L_ERR, "ERROR: receive_msg: parse_msg failed\n");
 		goto error02;
888ca09d
 	}
e72b5b50
 	DBG("After parse_msg...\n");
caf80ae6
 
a50f3f89
 
fa128269
 	/* ... clear branches from previous message */
caf80ae6
 	clear_branches();
 
22d4aa5d
 	if (msg->first_line.type==SIP_REQUEST){
914a4c04
 		ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
ac34f9f4
 		if (!IS_SIP(msg)){
471589c5
 			if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){
 				if (unlikely(ret==NONSIP_MSG_ERROR))
 					goto error03;
ac34f9f4
 				goto end; /* drop the message */
471589c5
 			}
ac34f9f4
 		}
888ca09d
 		/* sanity checks */
34af87af
 		if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
888ca09d
 			/* no via, send back error ? */
e72b5b50
 			LOG(L_ERR, "ERROR: receive_msg: no via found in request\n");
6b109fa2
 			STATS_BAD_MSG();
2e89dc92
 			goto error02;
888ca09d
 		}
53c7e0f1
 		/* check if necessary to add receive?->moved to forward_req */
59653eb8
 		/* check for the alias stuff */
 #ifdef USE_TCP
3dc4f620
 		if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) && 
59653eb8
 				(((rcv_info->proto==PROTO_TCP) && !tcp_disable)
 #ifdef USE_TLS
 					|| ((rcv_info->proto==PROTO_TLS) && !tls_disable)
 #endif
 				)
 			){
 			if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
 									rcv_info->proto)!=0){
 				LOG(L_ERR, " ERROR: receive_msg: tcp alias failed\n");
 				/* continue */
 			}
 		}
 #endif
e345b6b1
 			
ac34f9f4
 	/*	skip: */
f8d46776
 		DBG("preparing to run routing scripts...\n");
4f3faaaf
 #ifdef  STATS
 		gettimeofday( & tvb, &tz );
 #endif
fa128269
 		/* execute pre-script callbacks, if any; -jiri */
 		/* if some of the callbacks said not to continue with
 		   script processing, don't do so
 		   if we are here basic sanity checks are already done
 		   (like presence of at least one via), so you can count
 		   on via1 being parsed in a pre-script callback --andrei
 		*/
8216129f
 		if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
45a368cb
 		{
6b109fa2
 			STATS_REQ_FWD_DROP();
2e89dc92
 			goto end; /* drop the request */
45a368cb
 		}
2e89dc92
 
29e00cb9
 		set_route_type(REQUEST_ROUTE);
fa128269
 		/* exec the routing script */
4ce1715d
 		if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){
4ac74c03
 			LOG(L_WARN, "WARNING: receive_msg: "
f20a56a2
 					"error while trying script\n");
2e89dc92
 			goto error_req;
4ac74c03
 		}
caf80ae6
 
4f3faaaf
 #ifdef STATS
 		gettimeofday( & tve, &tz );
 		diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
 		stats->processed_requests++;
 		stats->acc_req_time += diff;
53c7e0f1
 		DBG("successfully ran routing scripts...(%d usec)\n", diff);
dda9dab1
 		STATS_RX_REQUEST( msg->first_line.u.request.method_value );
4f3faaaf
 #endif
2e89dc92
 
 		/* execute post request-script callbacks */
8216129f
 		exec_post_script_cb(msg, REQUEST_CB_TYPE);
22d4aa5d
 	}else if (msg->first_line.type==SIP_REPLY){
888ca09d
 		/* sanity checks */
34af87af
 		if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
888ca09d
 			/* no via, send back error ? */
e72b5b50
 			LOG(L_ERR, "ERROR: receive_msg: no via found in reply\n");
6b109fa2
 			STATS_BAD_RPL();
2e89dc92
 			goto error02;
e22bbdb8
 		}
5b253cc6
 
4f3faaaf
 #ifdef STATS
 		gettimeofday( & tvb, &tz );
9598488f
 		STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
4f3faaaf
 #endif
888ca09d
 		
fa128269
 		/* execute pre-script callbacks, if any; -jiri */
 		/* if some of the callbacks said not to continue with
 		   script processing, don't do so
 		   if we are here basic sanity checks are already done
 		   (like presence of at least one via), so you can count
 		   on via1 being parsed in a pre-script callback --andrei
 		*/
8216129f
 		if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 )
c7ccd4a4
 		{
6b109fa2
 			STATS_RPL_FWD_DROP();
 			goto end; /* drop the reply */
c7ccd4a4
 		}
29e00cb9
 
6b6642f4
 		/* exec the onreply routing script */
93349b4e
 		if (onreply_rt.rlist[DEFAULT_RT]){
5e0e999a
 			set_route_type(CORE_ONREPLY_ROUTE);
05589c01
 			ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
ae12edc4
 #ifndef NO_ONREPLY_ROUTE_ERROR
 			if (unlikely(ret<0)){
6b6642f4
 				LOG(L_WARN, "WARNING: receive_msg: "
 						"error while trying onreply script\n");
 				goto error_rpl;
05589c01
 			}else
ae12edc4
 #endif /* NO_ONREPLY_ROUTE_ERROR */
 			if (unlikely(ret==0 || (ctx.run_flags&DROP_R_F))){
6b109fa2
 				STATS_RPL_FWD_DROP();
05589c01
 				goto skip_send_reply; /* drop the message, no error */
 			}
6b6642f4
 		}
888ca09d
 		/* send the msg */
b908cdeb
 		forward_reply(msg);
f9ac51fb
 	skip_send_reply:
4f3faaaf
 #ifdef STATS
 		gettimeofday( & tve, &tz );
 		diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
 		stats->processed_responses++;
 		stats->acc_res_time+=diff;
53c7e0f1
 		DBG("successfully ran reply processing...(%d usec)\n", diff);
4f3faaaf
 #endif
2e89dc92
 
 		/* execute post reply-script callbacks */
8216129f
 		exec_post_script_cb(msg, ONREPLY_CB_TYPE);
888ca09d
 	}
2e89dc92
 
4776dc11
 end:
f571aa35
 #ifdef STATS
 	skipped = 0;
 #endif
2be21e31
 	/* free possible loaded avps -bogdan */
fe1b043e
 	reset_avps();
4075c49e
 #ifdef WITH_XAVP
 	xavp_reset_list();
 #endif
7f858173
 	DBG("receive_msg: cleaning up\n");
22d4aa5d
 	free_sip_msg(msg);
6fa79282
 	pkg_free(msg);
f571aa35
 #ifdef STATS
dda9dab1
 	if (skipped) STATS_RX_DROPS;
f571aa35
 #endif
888ca09d
 	return 0;
ae12edc4
 #ifndef NO_ONREPLY_ROUTE_ERROR
6b6642f4
 error_rpl:
 	/* execute post reply-script callbacks */
8216129f
 	exec_post_script_cb(msg, ONREPLY_CB_TYPE);
fe1b043e
 	reset_avps();
4075c49e
 #ifdef WITH_XAVP
 	xavp_reset_list();
 #endif
6b6642f4
 	goto error02;
ae12edc4
 #endif /* NO_ONREPLY_ROUTE_ERROR */
2e89dc92
 error_req:
 	DBG("receive_msg: error:...\n");
 	/* execute post request-script callbacks */
8216129f
 	exec_post_script_cb(msg, REQUEST_CB_TYPE);
471589c5
 error03:
2be21e31
 	/* free possible loaded avps -bogdan */
fe1b043e
 	reset_avps();
4075c49e
 #ifdef WITH_XAVP
 	xavp_reset_list();
 #endif
caf80ae6
 error02:
22d4aa5d
 	free_sip_msg(msg);
6fa79282
 	pkg_free(msg);
caf80ae6
 error00:
dda9dab1
 	STATS_RX_DROPS;
888ca09d
 	return -1;
 }