a9e1fc3c07545f219f007db1c67eed659c4c63ca
[sip-router] / receive.c
1 /* 
2  * Copyright (C) 2001-2003 FhG Fokus
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License 
17  * along with this program; if not, write to the Free Software 
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 /*!
23  * \file
24  * \brief Kamailio core :: 
25  * \ingroup core
26  * Module: \ref core
27  */
28
29
30 #include <string.h>
31 #include <stdlib.h>
32 #include <sys/time.h>
33
34 #include "receive.h"
35 #include "globals.h"
36 #include "dprint.h"
37 #include "route.h"
38 #include "parser/msg_parser.h"
39 #include "forward.h"
40 #include "action.h"
41 #include "mem/mem.h"
42 #include "stats.h"
43 #include "ip_addr.h"
44 #include "script_cb.h"
45 #include "nonsip_hooks.h"
46 #include "dset.h"
47 #include "usr_avp.h"
48 #ifdef WITH_XAVP
49 #include "xavp.h"
50 #endif
51 #include "select_buf.h"
52
53 #include "tcp_server.h" /* for tcpconn_add_alias */
54 #include "tcp_options.h" /* for access to tcp_accept_aliases*/
55 #include "cfg/cfg.h"
56 #include "core_stats.h"
57
58 #ifdef DEBUG_DMALLOC
59 #include <mem/dmalloc.h>
60 #endif
61
62 unsigned int msg_no=0;
63 /* address preset vars */
64 str default_global_address={0,0};
65 str default_global_port={0,0};
66 str default_via_address={0,0};
67 str default_via_port={0,0};
68
69 /**
70  * increment msg_no and return the new value
71  */
72 unsigned int inc_msg_no(void)
73 {
74         return ++msg_no;
75 }
76
77
78 /** Receive message
79  *  WARNING: buf must be 0 terminated (buf[len]=0) or some things might 
80  * break (e.g.: modules/textops)
81  */
82 int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) 
83 {
84         struct sip_msg* msg;
85         struct run_act_ctx ctx;
86         int ret;
87 #ifdef STATS
88         int skipped = 1;
89         struct timeval tvb, tve;        
90         struct timezone tz;
91         unsigned int diff;
92 #endif
93         str inb;
94         sr_net_info_t netinfo;
95
96         inb.s = buf;
97         inb.len = len;
98         sr_event_exec(SREV_NET_DATA_IN, (void*)&inb);
99         len = inb.len;
100
101         msg=pkg_malloc(sizeof(struct sip_msg));
102         if (msg==0) {
103                 LM_ERR("no mem for sip_msg\n");
104                 goto error00;
105         }
106         msg_no++;
107         /* number of vias parsed -- good for diagnostic info in replies */
108         via_cnt=0;
109
110         memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
111         /* fill in msg */
112         msg->buf=buf;
113         msg->len=len;
114         /* zero termination (termination of orig message bellow not that
115            useful as most of the work is done with scratch-pad; -jiri  */
116         /* buf[len]=0; */ /* WARNING: zero term removed! */
117         msg->rcv=*rcv_info;
118         msg->id=msg_no;
119         msg->pid=my_pid();
120         msg->set_global_address=default_global_address;
121         msg->set_global_port=default_global_port;
122         
123         if(likely(sr_msg_time==1)) msg_set_time(msg);
124
125         if (parse_msg(buf,len, msg)!=0){
126                 if(sr_event_exec(SREV_RCV_NOSIP, (void*)msg)!=0) {
127                         LOG(cfg_get(core, core_cfg, corelog),
128                                 "core parsing of SIP message failed (%s:%d/%d)\n",
129                                 ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
130                                 (int)msg->rcv.proto);
131                         sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
132                 }
133                 goto error02;
134         }
135         LM_DBG("After parse_msg...\n");
136
137         /* set log prefix */
138         log_prefix_set(msg);
139
140         /* ... clear branches from previous message */
141         clear_branches();
142
143         if(sr_event_enabled(SREV_NET_DATA_RECV)) {
144                 memset(&netinfo, 0, sizeof(sr_net_info_t));
145                 netinfo.data.s = msg->buf;
146                 netinfo.data.len = msg->len;
147                 netinfo.rcv = rcv_info;
148                 sr_event_exec(SREV_NET_DATA_RECV, (void*)&netinfo);
149         }
150
151         if (msg->first_line.type==SIP_REQUEST){
152                 ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
153                 if (!IS_SIP(msg)){
154                         if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){
155                                 if (unlikely(ret==NONSIP_MSG_ERROR))
156                                         goto error03;
157                                 goto end; /* drop the message */
158                         }
159                 }
160                 /* sanity checks */
161                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
162                         /* no via, send back error ? */
163                         LM_ERR("no via found in request\n");
164                         STATS_BAD_MSG();
165                         goto error02;
166                 }
167                 /* check if necessary to add receive?->moved to forward_req */
168                 /* check for the alias stuff */
169 #ifdef USE_TCP
170                 if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) && 
171                                 (((rcv_info->proto==PROTO_TCP) && !tcp_disable)
172 #ifdef USE_TLS
173                                         || ((rcv_info->proto==PROTO_TLS) && !tls_disable)
174 #endif
175                                 )
176                         ){
177                         if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
178                                                                         rcv_info->proto)!=0){
179                                 LM_ERR("tcp alias failed\n");
180                                 /* continue */
181                         }
182                 }
183 #endif
184
185         /*      skip: */
186                 LM_DBG("preparing to run routing scripts...\n");
187 #ifdef  STATS
188                 gettimeofday( & tvb, &tz );
189 #endif
190                 /* execute pre-script callbacks, if any; -jiri */
191                 /* if some of the callbacks said not to continue with
192                    script processing, don't do so
193                    if we are here basic sanity checks are already done
194                    (like presence of at least one via), so you can count
195                    on via1 being parsed in a pre-script callback --andrei
196                 */
197                 if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
198                 {
199                         STATS_REQ_FWD_DROP();
200                         goto end; /* drop the request */
201                 }
202
203                 set_route_type(REQUEST_ROUTE);
204                 /* exec the routing script */
205                 if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){
206                         LM_WARN("error while trying script\n");
207                         goto error_req;
208                 }
209
210 #ifdef STATS
211                 gettimeofday( & tve, &tz );
212                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
213                 stats->processed_requests++;
214                 stats->acc_req_time += diff;
215                 LM_DBG("successfully ran routing scripts...(%d usec)\n", diff);
216                 STATS_RX_REQUEST( msg->first_line.u.request.method_value );
217 #endif
218
219                 /* execute post request-script callbacks */
220                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
221         }else if (msg->first_line.type==SIP_REPLY){
222                 /* sanity checks */
223                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
224                         /* no via, send back error ? */
225                         LM_ERR("no via found in reply\n");
226                         STATS_BAD_RPL();
227                         goto error02;
228                 }
229
230 #ifdef STATS
231                 gettimeofday( & tvb, &tz );
232                 STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
233 #endif
234                 
235                 /* execute pre-script callbacks, if any; -jiri */
236                 /* if some of the callbacks said not to continue with
237                    script processing, don't do so
238                    if we are here basic sanity checks are already done
239                    (like presence of at least one via), so you can count
240                    on via1 being parsed in a pre-script callback --andrei
241                 */
242                 if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 )
243                 {
244                         STATS_RPL_FWD_DROP();
245                         goto end; /* drop the reply */
246                 }
247
248                 /* exec the onreply routing script */
249                 if (onreply_rt.rlist[DEFAULT_RT]){
250                         set_route_type(CORE_ONREPLY_ROUTE);
251                         ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
252 #ifndef NO_ONREPLY_ROUTE_ERROR
253                         if (unlikely(ret<0)){
254                                 LM_WARN("error while trying onreply script\n");
255                                 goto error_rpl;
256                         }else
257 #endif /* NO_ONREPLY_ROUTE_ERROR */
258                         if (unlikely(ret==0 || (ctx.run_flags&DROP_R_F))){
259                                 STATS_RPL_FWD_DROP();
260                                 goto skip_send_reply; /* drop the message, no error */
261                         }
262                 }
263                 /* send the msg */
264                 forward_reply(msg);
265         skip_send_reply:
266 #ifdef STATS
267                 gettimeofday( & tve, &tz );
268                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
269                 stats->processed_responses++;
270                 stats->acc_res_time+=diff;
271                 LM_DBG("successfully ran reply processing...(%d usec)\n", diff);
272 #endif
273
274                 /* execute post reply-script callbacks */
275                 exec_post_script_cb(msg, ONREPLY_CB_TYPE);
276         }
277
278 end:
279 #ifdef STATS
280         skipped = 0;
281 #endif
282         /* free possible loaded avps -bogdan */
283         reset_avps();
284 #ifdef WITH_XAVP
285         xavp_reset_list();
286 #endif
287         LM_DBG("cleaning up\n");
288         free_sip_msg(msg);
289         pkg_free(msg);
290 #ifdef STATS
291         if (skipped) STATS_RX_DROPS;
292 #endif
293         /* reset log prefix */
294         log_prefix_set(NULL);
295         return 0;
296
297 #ifndef NO_ONREPLY_ROUTE_ERROR
298 error_rpl:
299         /* execute post reply-script callbacks */
300         exec_post_script_cb(msg, ONREPLY_CB_TYPE);
301         reset_avps();
302 #ifdef WITH_XAVP
303         xavp_reset_list();
304 #endif
305         goto error02;
306 #endif /* NO_ONREPLY_ROUTE_ERROR */
307 error_req:
308         LM_DBG("error:...\n");
309         /* execute post request-script callbacks */
310         exec_post_script_cb(msg, REQUEST_CB_TYPE);
311 error03:
312         /* free possible loaded avps -bogdan */
313         reset_avps();
314 #ifdef WITH_XAVP
315         xavp_reset_list();
316 #endif
317 error02:
318         free_sip_msg(msg);
319         pkg_free(msg);
320 error00:
321         STATS_RX_DROPS;
322         /* reset log prefix */
323         log_prefix_set(NULL);
324         return -1;
325 }
326