core: if nosip msg hooks skip handling the packet, stop sip routing processing
[sip-router] / src / core / 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 #include "kemi.h"
58
59 #ifdef DEBUG_DMALLOC
60 #include <mem/dmalloc.h>
61 #endif
62
63 int _sr_ip_free_bind = 0;
64
65 unsigned int msg_no = 0;
66 /* address preset vars */
67 str default_global_address = {0, 0};
68 str default_global_port = {0, 0};
69 str default_via_address = {0, 0};
70 str default_via_port = {0, 0};
71
72 int ksr_route_locks_size = 0;
73 static rec_lock_set_t* ksr_route_locks_set = NULL;
74
75 int ksr_route_locks_set_init(void)
76 {
77         if(ksr_route_locks_set!=NULL || ksr_route_locks_size<=0)
78                 return 0;
79
80         ksr_route_locks_set = rec_lock_set_alloc(ksr_route_locks_size);
81         if(ksr_route_locks_set) {
82                 LM_ERR("failed to allocate route locks set\n");
83                 return -1;
84         }
85         if(rec_lock_set_init(ksr_route_locks_set)==NULL) {
86                 LM_ERR("failed to init route locks set\n");
87                 return -1;
88         }
89         return 0;
90 }
91
92 void ksr_route_locks_set_destroy(void)
93 {
94         if(ksr_route_locks_set==NULL)
95                 return;
96
97         rec_lock_set_destroy(ksr_route_locks_set);
98         rec_lock_set_dealloc(ksr_route_locks_set);
99         ksr_route_locks_set = NULL;
100 }
101
102 /**
103  * increment msg_no and return the new value
104  */
105 unsigned int inc_msg_no(void)
106 {
107         return ++msg_no;
108 }
109
110 /**
111  *
112  */
113 int sip_check_fline(char *buf, unsigned int len)
114 {
115         char *p;
116         int m;
117
118         m = 0;
119         for(p = buf; p < buf + len; p++) {
120                 /* first check if is a reply - starts with SIP/2.0 */
121                 if(m == 0) {
122                         if(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
123                                 continue;
124                         if(buf + len - p < 10)
125                                 return -1;
126                         if(strncmp(p, "SIP/2.0 ", 8) == 0) {
127                                 LM_DBG("first line indicates a SIP reply\n");
128                                 return 0;
129                         }
130                         m = 1;
131                 } else {
132                         /* check if a request - before end of first line is SIP/2.0 */
133                         if(*p != '\r' && *p != '\n')
134                                 continue;
135                         if(p - 10 >= buf) {
136                                 if(strncmp(p - 8, " SIP/2.0", 8) == 0) {
137                                         LM_DBG("first line indicates a SIP request\n");
138                                         return 0;
139                                 }
140                         }
141                         return -1;
142                 }
143         }
144         return -1;
145 }
146
147 /** Receive message
148  *  WARNING: buf must be 0 terminated (buf[len]=0) or some things might
149  * break (e.g.: modules/textops)
150  */
151 int receive_msg(char *buf, unsigned int len, struct receive_info *rcv_info)
152 {
153         struct sip_msg *msg;
154         struct run_act_ctx ctx;
155         struct run_act_ctx *bctx;
156         int ret;
157 #ifdef STATS
158         int skipped = 1;
159         int stats_on = 1;
160 #else
161         int stats_on = 0;
162 #endif
163         struct timeval tvb, tve;
164         struct timezone tz;
165         unsigned int diff = 0;
166         str inb;
167         sr_net_info_t netinfo;
168         sr_kemi_eng_t *keng = NULL;
169         sr_event_param_t evp = {0};
170         unsigned int cidlockidx = 0;
171         unsigned int cidlockset = 0;
172         int errsipmsg = 0;
173
174         if(sr_event_enabled(SREV_NET_DATA_RECV)) {
175                 if(sip_check_fline(buf, len) == 0) {
176                         memset(&netinfo, 0, sizeof(sr_net_info_t));
177                         netinfo.data.s = buf;
178                         netinfo.data.len = len;
179                         netinfo.rcv = rcv_info;
180                         evp.data = (void *)&netinfo;
181                         sr_event_exec(SREV_NET_DATA_RECV, &evp);
182                 }
183         }
184
185         inb.s = buf;
186         inb.len = len;
187         evp.data = (void *)&inb;
188         evp.rcv = rcv_info;
189         sr_event_exec(SREV_NET_DATA_IN, &evp);
190         len = inb.len;
191
192         msg = pkg_malloc(sizeof(struct sip_msg));
193         if(unlikely(msg == 0)) {
194                 LM_ERR("no mem for sip_msg\n");
195                 goto error00;
196         }
197         msg_no++;
198         /* number of vias parsed -- good for diagnostic info in replies */
199         via_cnt = 0;
200
201         memset(msg, 0, sizeof(struct sip_msg)); /* init everything to 0 */
202         /* fill in msg */
203         msg->buf = buf;
204         msg->len = len;
205         /* zero termination (termination of orig message bellow not that
206          * useful as most of the work is done with scratch-pad; -jiri  */
207         /* buf[len]=0; */ /* WARNING: zero term removed! */
208         msg->rcv = *rcv_info;
209         msg->id = msg_no;
210         msg->pid = my_pid();
211         msg->set_global_address = default_global_address;
212         msg->set_global_port = default_global_port;
213
214         if(likely(sr_msg_time == 1))
215                 msg_set_time(msg);
216
217         if(parse_msg(buf, len, msg) != 0) {
218                 errsipmsg = 1;
219                 evp.data = (void *)msg;
220                 if((ret = sr_event_exec(SREV_RCV_NOSIP, &evp)) < NONSIP_MSG_DROP) {
221                         LM_DBG("attempt of nonsip message processing failed\n");
222                 } else if(ret == NONSIP_MSG_DROP) {
223                         LM_DBG("nonsip message processing completed\n");
224                         goto error02;
225                 }
226         }
227         if(errsipmsg==1) {
228                 LOG(cfg_get(core, core_cfg, corelog),
229                                 "core parsing of SIP message failed (%s:%d/%d)\n",
230                                 ip_addr2a(&msg->rcv.src_ip), (int)msg->rcv.src_port,
231                                 (int)msg->rcv.proto);
232                 sr_core_ert_run(msg, SR_CORE_ERT_RECEIVE_PARSE_ERROR);
233                 goto error02;
234         }
235
236         if(unlikely(parse_headers(msg, HDR_FROM_F | HDR_TO_F | HDR_CALLID_F | HDR_CSEQ_F, 0)
237                         < 0)) {
238                 LM_WARN("parsing relevant headers failed\n");
239         }
240         LM_DBG("--- received sip message - %s - call-id: [%.*s] - cseq: [%.*s]\n",
241                         (msg->first_line.type == SIP_REQUEST) ? "request" : "reply",
242                         (msg->callid && msg->callid->body.s) ? msg->callid->body.len : 0,
243                         (msg->callid && msg->callid->body.s) ? msg->callid->body.s : "",
244                         (msg->cseq && msg->cseq->body.s) ? msg->cseq->body.len : 0,
245                         (msg->cseq && msg->cseq->body.s) ? msg->cseq->body.s : "");
246
247         /* set log prefix */
248         log_prefix_set(msg);
249
250         /* ... clear branches from previous message */
251         clear_branches();
252
253         if(unlikely(ksr_route_locks_set!=NULL && msg->callid && msg->callid->body.s
254                         && msg->callid->body.len >0)) {
255                 cidlockidx = get_hash1_raw(msg->callid->body.s, msg->callid->body.len);
256                 cidlockidx = cidlockidx % ksr_route_locks_set->size;
257                 cidlockset = 1;
258         }
259
260         if(msg->first_line.type == SIP_REQUEST) {
261                 ruri_mark_new(); /* ruri is usable for forking (not consumed yet) */
262                 if(!IS_SIP(msg)) {
263                         if((ret = nonsip_msg_run_hooks(msg)) != NONSIP_MSG_ACCEPT) {
264                                 if(unlikely(ret == NONSIP_MSG_ERROR))
265                                         goto error03;
266                                 goto end; /* drop the message */
267                         }
268                 }
269                 /* sanity checks */
270                 if(unlikely((msg->via1 == 0) || (msg->via1->error != PARSE_OK))) {
271                         /* no via, send back error ? */
272                         LM_ERR("no via found in request\n");
273                         STATS_BAD_MSG();
274                         goto error02;
275                 }
276 /* check if necessary to add receive?->moved to forward_req */
277 /* check for the alias stuff */
278 #ifdef USE_TCP
279                 if(msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases)
280                                 && (((rcv_info->proto == PROTO_TCP) && !tcp_disable)
281 #ifdef USE_TLS
282                                                    || ((rcv_info->proto == PROTO_TLS) && !tls_disable)
283 #endif
284                                                                    )) {
285                         if(tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
286                                            rcv_info->proto)
287                                         != 0) {
288                                 LM_ERR("tcp alias failed\n");
289                                 /* continue */
290                         }
291                 }
292 #endif
293
294                 /*      skip: */
295                 LM_DBG("preparing to run routing scripts...\n");
296                 if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
297                                 || stats_on == 1) {
298                         gettimeofday(&tvb, &tz);
299                 }
300                 /* execute pre-script callbacks, if any; -jiri */
301                 /* if some of the callbacks said not to continue with
302                  * script processing, don't do so
303                  * if we are here basic sanity checks are already done
304                  * (like presence of at least one via), so you can count
305                  * on via1 being parsed in a pre-script callback --andrei
306                 */
307                 if(exec_pre_script_cb(msg, REQUEST_CB_TYPE) == 0) {
308                         STATS_REQ_FWD_DROP();
309                         goto end; /* drop the request */
310                 }
311
312                 set_route_type(REQUEST_ROUTE);
313                 /* exec the routing script */
314                 if(unlikely(main_rt.rlist[DEFAULT_RT] == NULL)) {
315                         keng = sr_kemi_eng_get();
316                         if(keng == NULL) {
317                                 LM_ERR("no request_route {...} and no other config routing"
318                                                 " engine registered\n");
319                                 goto error_req;
320                         }
321                         if(unlikely(cidlockset)) {
322                                 rec_lock_set_get(ksr_route_locks_set, cidlockidx);
323                                 if(keng->froute(msg, REQUEST_ROUTE, NULL, NULL) < 0)
324                                         LM_NOTICE("negative return code from engine function\n");
325                                 rec_lock_set_release(ksr_route_locks_set, cidlockidx);
326                         } else {
327                                 if(keng->froute(msg, REQUEST_ROUTE, NULL, NULL) < 0)
328                                         LM_NOTICE("negative return code from engine function\n");
329                         }
330                 } else {
331                         if(unlikely(cidlockset)) {
332                                 rec_lock_set_get(ksr_route_locks_set, cidlockidx);
333                                 if(run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0) < 0) {
334                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
335                                         LM_WARN("error while trying script\n");
336                                         goto error_req;
337                                 }
338                                 rec_lock_set_release(ksr_route_locks_set, cidlockidx);
339                         } else {
340                                 if(run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0) < 0) {
341                                         LM_WARN("error while trying script\n");
342                                         goto error_req;
343                                 }
344                         }
345                 }
346
347                 if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
348                                 || stats_on == 1) {
349                         gettimeofday(&tve, &tz);
350                         diff = (tve.tv_sec - tvb.tv_sec) * 1000000
351                                    + (tve.tv_usec - tvb.tv_usec);
352                         LOG(cfg_get(core, core_cfg, latency_cfg_log),
353                                         "request-route executed in: %d usec\n", diff);
354 #ifdef STATS
355                         stats->processed_requests++;
356                         stats->acc_req_time += diff;
357                         STATS_RX_REQUEST(msg->first_line.u.request.method_value);
358 #endif
359                 }
360
361                 /* execute post request-script callbacks */
362                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
363         } else if(msg->first_line.type == SIP_REPLY) {
364                 /* sanity checks */
365                 if((msg->via1 == 0) || (msg->via1->error != PARSE_OK)) {
366                         /* no via, send back error ? */
367                         LM_ERR("no via found in reply\n");
368                         STATS_BAD_RPL();
369                         goto error02;
370                 }
371
372                 if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
373                                 || stats_on == 1) {
374                         gettimeofday(&tvb, &tz);
375                 }
376 #ifdef STATS
377                 STATS_RX_RESPONSE(msg->first_line.u.reply.statuscode / 100);
378 #endif
379
380                 /* execute pre-script callbacks, if any; -jiri */
381                 /* if some of the callbacks said not to continue with
382                  * script processing, don't do so
383                  * if we are here basic sanity checks are already done
384                  * (like presence of at least one via), so you can count
385                  * on via1 being parsed in a pre-script callback --andrei
386                 */
387                 if(exec_pre_script_cb(msg, ONREPLY_CB_TYPE) == 0) {
388                         STATS_RPL_FWD_DROP();
389                         goto end; /* drop the reply */
390                 }
391
392                 /* exec the onreply routing script */
393                 if(kemi_reply_route_callback.len>0) {
394                         keng = sr_kemi_eng_get();
395                 }
396                 if(onreply_rt.rlist[DEFAULT_RT] != NULL || keng != NULL) {
397                         set_route_type(CORE_ONREPLY_ROUTE);
398                         ret = 1;
399                         if(unlikely(keng != NULL)) {
400                                 bctx = sr_kemi_act_ctx_get();
401                                 init_run_actions_ctx(&ctx);
402                                 sr_kemi_act_ctx_set(&ctx);
403                                 if(unlikely(cidlockset)) {
404                                         rec_lock_set_get(ksr_route_locks_set, cidlockidx);
405                                         ret = keng->froute(msg, CORE_ONREPLY_ROUTE, NULL, NULL);
406                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
407                                 } else {
408                                         ret = keng->froute(msg, CORE_ONREPLY_ROUTE, NULL, NULL);
409                                 }
410                                 sr_kemi_act_ctx_set(bctx);
411                         } else {
412                                 if(unlikely(cidlockset)) {
413                                         rec_lock_set_get(ksr_route_locks_set, cidlockidx);
414                                         ret = run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
415                                         rec_lock_set_release(ksr_route_locks_set, cidlockidx);
416                                 } else  {
417                                         ret = run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, &ctx);
418                                 }
419                         }
420 #ifndef NO_ONREPLY_ROUTE_ERROR
421                         if(unlikely(ret < 0)) {
422                                 LM_WARN("error while trying onreply script\n");
423                                 goto error_rpl;
424                         } else
425 #endif /* NO_ONREPLY_ROUTE_ERROR */
426                                 if(unlikely(ret == 0 || (ctx.run_flags & DROP_R_F))) {
427                                         STATS_RPL_FWD_DROP();
428                                         LM_DBG("drop flag set - skip forwarding the reply\n");
429                                         goto skip_send_reply; /* drop the message, no error */
430                                 }
431                 }
432                 /* send the msg */
433                 forward_reply(msg);
434         skip_send_reply:
435                 if(is_printable(cfg_get(core, core_cfg, latency_cfg_log))
436                                 || stats_on == 1) {
437                         gettimeofday(&tve, &tz);
438                         diff = (tve.tv_sec - tvb.tv_sec) * 1000000
439                                    + (tve.tv_usec - tvb.tv_usec);
440                         LOG(cfg_get(core, core_cfg, latency_cfg_log),
441                                         "reply-route executed in: %d usec\n", diff);
442 #ifdef STATS
443                         stats->processed_responses++;
444                         stats->acc_res_time += diff;
445 #endif
446                 }
447
448                 /* execute post reply-script callbacks */
449                 exec_post_script_cb(msg, ONREPLY_CB_TYPE);
450         }
451
452 end:
453 #ifdef STATS
454         skipped = 0;
455 #endif
456         ksr_msg_env_reset();
457         LM_DBG("cleaning up\n");
458         free_sip_msg(msg);
459         pkg_free(msg);
460 #ifdef STATS
461         if(skipped)
462                 STATS_RX_DROPS;
463 #endif
464         /* reset log prefix */
465         log_prefix_set(NULL);
466         return 0;
467
468 #ifndef NO_ONREPLY_ROUTE_ERROR
469 error_rpl:
470         /* execute post reply-script callbacks */
471         exec_post_script_cb(msg, ONREPLY_CB_TYPE);
472         goto error02;
473 #endif /* NO_ONREPLY_ROUTE_ERROR */
474 error_req:
475         LM_DBG("error:...\n");
476         /* execute post request-script callbacks */
477         exec_post_script_cb(msg, REQUEST_CB_TYPE);
478 error03:
479 error02:
480         free_sip_msg(msg);
481         pkg_free(msg);
482 error00:
483         ksr_msg_env_reset();
484         STATS_RX_DROPS;
485         /* reset log prefix */
486         log_prefix_set(NULL);
487         return -1;
488 }
489
490 /**
491  * clean up msg environment, such as avp and xavp lists
492  */
493 void ksr_msg_env_reset(void)
494 {
495         reset_avps();
496 #ifdef WITH_XAVP
497         xavp_reset_list();
498 #endif
499 }