receive.c
7de8a92f
 /*
53c7e0f1
  * Copyright (C) 2001-2003 FhG Fokus
7dd0b342
  *
6a0f4382
  * This file is part of Kamailio, a free SIP server.
7dd0b342
  *
6a0f4382
  * Kamailio is free software; you can redistribute it and/or modify
7dd0b342
  * 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
  *
6a0f4382
  * Kamailio is distributed in the hope that it will be useful,
7dd0b342
  * 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.
  *
7de8a92f
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
9e1ff448
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
049f64c2
  *
888ca09d
  */
 
1d0661db
 /*!
  * \file
7de8a92f
  * \brief Kamailio core ::
1d0661db
  * \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"
ab2ca4c9
 #include "kemi.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
 
072c8865
 /**
  *
  */
 int sip_check_fline(char* buf, unsigned int len)
 {
 	char *p;
 	int m;
 
 	m = 0;
 	for(p=buf; p<buf+len; p++) {
 		/* first check if is a reply - starts with SIP/2.0 */
 		if(m==0) {
 			if(*p==' ' || *p=='\t' || *p=='\r' || *p=='\n') continue;
 			if(buf+len-p<10) return -1;
 			if(strncmp(p, "SIP/2.0 ", 8)==0) {
 				LM_DBG("first line indicates a SIP reply\n");
 				return 0;
 			}
 			m=1;
 		} else {
 			/* check if a request - before end of first line is SIP/2.0 */
 			if(*p!='\r' && *p!='\n') continue;
 			if(p-10>=buf) {
 				if(strncmp(p-8, " SIP/2.0", 8)==0) {
 					LM_DBG("first line indicates a SIP request\n");
 					return 0;
 				}
 			}
 			return -1;
 		}
 	}
 	return -1;
 }
8fc80c33
 
6a0f4382
 /** Receive message
7de8a92f
  *  WARNING: buf must be 0 terminated (buf[len]=0) or some things might
8fc80c33
  * break (e.g.: modules/textops)
  */
7de8a92f
 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;
daf7aa39
 	struct run_act_ctx *bctx;
6b6642f4
 	int ret;
985f6f0f
 #ifdef STATS
 	int skipped = 1;
e80c2473
 	int stats_on = 1;
 #else
 	int stats_on = 0;
 #endif
7de8a92f
 	struct timeval tvb, tve;
4f3faaaf
 	struct timezone tz;
e80c2473
 	unsigned int diff = 0;
88b792e4
 	str inb;
4fc96976
 	sr_net_info_t netinfo;
ab2ca4c9
 	sr_kemi_eng_t *keng = NULL;
88b792e4
 
072c8865
 	if(sr_event_enabled(SREV_NET_DATA_RECV)) {
 		if(sip_check_fline(buf, len)==0) {
 			memset(&netinfo, 0, sizeof(sr_net_info_t));
 			netinfo.data.s = buf;
 			netinfo.data.len = len;
 			netinfo.rcv = rcv_info;
 			sr_event_exec(SREV_NET_DATA_RECV, (void*)&netinfo);
 		}
 	}
 
88b792e4
 	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) {
6e62abb8
 		LM_ERR("no mem for sip_msg\n");
caf80ae6
 		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
7de8a92f
 	 * 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;
76f7847f
 	msg->pid=my_pid();
6bfaa042
 	msg->set_global_address=default_global_address;
 	msg->set_global_port=default_global_port;
7de8a92f
 
d4ed4771
 	if(likely(sr_msg_time==1)) msg_set_time(msg);
 
22d4aa5d
 	if (parse_msg(buf,len, msg)!=0){
6291db55
 		if((ret=sr_event_exec(SREV_RCV_NOSIP, (void*)msg))<NONSIP_MSG_DROP) {
6284b608
 			LOG(cfg_get(core, core_cfg, corelog),
3ccf4b43
 				"core parsing of SIP message failed (%s:%d/%d)\n",
 				ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
 				(int)msg->rcv.proto);
6284b608
 			sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
004b9d53
 		}
6291db55
 		else if(ret == NONSIP_MSG_DROP) goto error02;
888ca09d
 	}
0965c904
 
 	parse_headers(msg, HDR_FROM_F|HDR_TO_F|HDR_CALLID_F|HDR_CSEQ_F, 0);
004b9d53
 	LM_DBG("--- received sip message - %s - call-id: [%.*s] - cseq: [%.*s]\n",
 			(msg->first_line.type==SIP_REQUEST)?"request":"reply",
 			(msg->callid && msg->callid->body.s)?msg->callid->body.len:0,
 			(msg->callid && msg->callid->body.s)?msg->callid->body.s:"",
 			(msg->cseq && msg->cseq->body.s)?msg->cseq->body.len:0,
 			(msg->cseq && msg->cseq->body.s)?msg->cseq->body.s:"");
caf80ae6
 
35e94c97
 	/* set log prefix */
 	log_prefix_set(msg);
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 ? */
6e62abb8
 			LM_ERR("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
7de8a92f
 		if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) &&
9349870a
 				(((rcv_info->proto==PROTO_TCP) && !tcp_disable)
59653eb8
 #ifdef USE_TLS
9349870a
 					|| ((rcv_info->proto==PROTO_TLS) && !tls_disable)
59653eb8
 #endif
 				)
 			){
 			if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
 									rcv_info->proto)!=0){
6e62abb8
 				LM_ERR("tcp alias failed\n");
59653eb8
 				/* continue */
 			}
 		}
 #endif
242920ec
 
ac34f9f4
 	/*	skip: */
c9dca9b4
 		LM_DBG("preparing to run routing scripts...\n");
e80c2473
 		if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
 				|| stats_on==1) {
 			gettimeofday( & tvb, &tz );
 		}
fa128269
 		/* execute pre-script callbacks, if any; -jiri */
 		/* if some of the callbacks said not to continue with
7de8a92f
 		 * 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
fa128269
 		*/
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 */
ab2ca4c9
 		if(unlikely(main_rt.rlist[DEFAULT_RT]==NULL)) {
 			keng = sr_kemi_eng_get();
 			if(keng==NULL) {
 				LM_ERR("no config routing engine registered\n");
 				goto error_req;
 			}
 			if(keng->froute(msg, REQUEST_ROUTE, NULL)<0) {
 				LM_NOTICE("negative return code from engine function\n");
 			}
 		} else {
 			if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){
 				LM_WARN("error while trying script\n");
 				goto error_req;
 			}
4ac74c03
 		}
caf80ae6
 
e80c2473
 		if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
 				|| stats_on==1) {
 			gettimeofday( & tve, &tz );
 			diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
 			LOG(cfg_get(core, core_cfg, latency_cfg_log),
 					"request-route executed in: %d usec\n", diff);
4f3faaaf
 #ifdef STATS
e80c2473
 			stats->processed_requests++;
 			stats->acc_req_time += diff;
 			STATS_RX_REQUEST( msg->first_line.u.request.method_value );
4f3faaaf
 #endif
e80c2473
 		}
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 ? */
6e62abb8
 			LM_ERR("no via found in reply\n");
6b109fa2
 			STATS_BAD_RPL();
2e89dc92
 			goto error02;
e22bbdb8
 		}
5b253cc6
 
e80c2473
 		if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
 				|| stats_on==1) {
 			gettimeofday( & tvb, &tz );
 		}
4f3faaaf
 #ifdef STATS
9598488f
 		STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
4f3faaaf
 #endif
7de8a92f
 
fa128269
 		/* execute pre-script callbacks, if any; -jiri */
 		/* if some of the callbacks said not to continue with
7de8a92f
 		 * 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
fa128269
 		*/
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 */
daf7aa39
 		keng = sr_kemi_eng_get();
 		if (onreply_rt.rlist[DEFAULT_RT]!=NULL || keng!=NULL){
5e0e999a
 			set_route_type(CORE_ONREPLY_ROUTE);
ab2ca4c9
 			ret = 1;
daf7aa39
 			if(unlikely(keng!=NULL)) {
 				bctx = sr_kemi_act_ctx_get();
 				init_run_actions_ctx(&ctx);
 				sr_kemi_act_ctx_set(&ctx);
 				ret = keng->froute(msg, CORE_ONREPLY_ROUTE, NULL);
 				sr_kemi_act_ctx_set(bctx);
ab2ca4c9
 			} else {
 				ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
 			}
ae12edc4
 #ifndef NO_ONREPLY_ROUTE_ERROR
 			if (unlikely(ret<0)){
6e62abb8
 				LM_WARN("error while trying onreply script\n");
6b6642f4
 				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:
e80c2473
 		if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
 				|| stats_on==1) {
 			gettimeofday( & tve, &tz );
 			diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
 			LOG(cfg_get(core, core_cfg, latency_cfg_log),
 					"reply-route executed in: %d usec\n", diff);
4f3faaaf
 #ifdef STATS
e80c2473
 			stats->processed_responses++;
 			stats->acc_res_time+=diff;
4f3faaaf
 #endif
e80c2473
 		}
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
c9dca9b4
 	LM_DBG("cleaning up\n");
22d4aa5d
 	free_sip_msg(msg);
6fa79282
 	pkg_free(msg);
f571aa35
 #ifdef STATS
dda9dab1
 	if (skipped) STATS_RX_DROPS;
f571aa35
 #endif
35e94c97
 	/* reset log prefix */
 	log_prefix_set(NULL);
888ca09d
 	return 0;
35e94c97
 
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:
c9dca9b4
 	LM_DBG("error:...\n");
2e89dc92
 	/* 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;
35e94c97
 	/* reset log prefix */
 	log_prefix_set(NULL);
888ca09d
 	return -1;
 }