Merge remote branch 'origin/sr_3.0'
[sip-router] / receive.c
1 /* 
2  *$Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History:
28  * ---------
29  * 2003-02-28 scratchpad compatibility abandoned (jiri)
30  * 2003-01-29 transport-independent message zero-termination in
31  *            receive_msg (jiri)
32  * 2003-02-07 undoed jiri's zero term. changes (they break tcp) (andrei)
33  * 2003-02-10 moved zero-term in the calling functions (udp_receive &
34  *            tcp_read_req)
35  * 2003-08-13 fixed exec_pre_cb returning 0 (backported from stable) (andrei)
36  * 2004-02-06 added user preferences support - destroy_avps() (bogdan)
37  * 2004-04-30 exec_pre_cb is called after basic sanity checks (at least one
38  *            via present & parsed ok)  (andrei)
39  * 2004-08-23 avp core changed - destroy_avp-> reset_avps (bogdan)
40  * 2006-11-29 nonsip_msg hooks called for non-sip msg (e.g HTTP) (andrei)
41  */
42
43 /*!
44  * \file
45  * \brief SIP-router core :: 
46  * \ingroup core
47  * Module: \ref core
48  */
49
50
51 #include <string.h>
52 #include <stdlib.h>
53 #include <sys/time.h>
54
55 #include "receive.h"
56 #include "globals.h"
57 #include "dprint.h"
58 #include "route.h"
59 #include "parser/msg_parser.h"
60 #include "forward.h"
61 #include "action.h"
62 #include "mem/mem.h"
63 #include "stats.h"
64 #include "ip_addr.h"
65 #include "script_cb.h"
66 #include "nonsip_hooks.h"
67 #include "dset.h"
68 #include "usr_avp.h"
69 #include "select_buf.h"
70
71 #include "tcp_server.h" /* for tcpconn_add_alias */
72 #include "tcp_options.h" /* for access to tcp_accept_aliases*/
73 #include "cfg/cfg.h"
74
75 #ifdef DEBUG_DMALLOC
76 #include <mem/dmalloc.h>
77 #endif
78
79 unsigned int msg_no=0;
80 /* address preset vars */
81 str default_global_address={0,0};
82 str default_global_port={0,0};
83 str default_via_address={0,0};
84 str default_via_port={0,0};
85
86 /**
87  * increment msg_no and return the new value
88  */
89 unsigned int inc_msg_no(void)
90 {
91         return ++msg_no;
92 }
93
94
95 /* WARNING: buf must be 0 terminated (buf[len]=0) or some things might 
96  * break (e.g.: modules/textops)
97  */
98 int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) 
99 {
100         struct sip_msg* msg;
101         int ret;
102 #ifdef STATS
103         int skipped = 1;
104         struct timeval tvb, tve;        
105         struct timezone tz;
106         unsigned int diff;
107 #endif
108         str inb;
109
110         inb.s = buf;
111         inb.len = len;
112         sr_event_exec(SREV_NET_DATA_IN, (void*)&inb);
113         len = inb.len;
114
115         msg=pkg_malloc(sizeof(struct sip_msg));
116         if (msg==0) {
117                 LOG(L_ERR, "ERROR: receive_msg: no mem for sip_msg\n");
118                 goto error00;
119         }
120         msg_no++;
121         /* number of vias parsed -- good for diagnostic info in replies */
122         via_cnt=0;
123
124         memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
125         /* fill in msg */
126         msg->buf=buf;
127         msg->len=len;
128         /* zero termination (termination of orig message bellow not that
129            useful as most of the work is done with scratch-pad; -jiri  */
130         /* buf[len]=0; */ /* WARNING: zero term removed! */
131         msg->rcv=*rcv_info;
132         msg->id=msg_no;
133         msg->set_global_address=default_global_address;
134         msg->set_global_port=default_global_port;
135         
136         if (parse_msg(buf,len, msg)!=0){
137                 LOG(L_ERR, "ERROR: receive_msg: parse_msg failed\n");
138                 goto error02;
139         }
140         DBG("After parse_msg...\n");
141
142
143         /* ... clear branches from previous message */
144         clear_branches();
145
146         if (msg->first_line.type==SIP_REQUEST){
147                 if (!IS_SIP(msg)){
148                         if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){
149                                 if (unlikely(ret==NONSIP_MSG_ERROR))
150                                         goto error03;
151                                 goto end; /* drop the message */
152                         }
153                 }
154                 /* sanity checks */
155                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
156                         /* no via, send back error ? */
157                         LOG(L_ERR, "ERROR: receive_msg: no via found in request\n");
158                         goto error02;
159                 }
160                 /* check if necessary to add receive?->moved to forward_req */
161                 /* check for the alias stuff */
162 #ifdef USE_TCP
163                 if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) && 
164                                 (((rcv_info->proto==PROTO_TCP) && !tcp_disable)
165 #ifdef USE_TLS
166                                         || ((rcv_info->proto==PROTO_TLS) && !tls_disable)
167 #endif
168                                 )
169                         ){
170                         if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
171                                                                         rcv_info->proto)!=0){
172                                 LOG(L_ERR, " ERROR: receive_msg: tcp alias failed\n");
173                                 /* continue */
174                         }
175                 }
176 #endif
177                         
178         /*      skip: */
179                 DBG("preparing to run routing scripts...\n");
180 #ifdef  STATS
181                 gettimeofday( & tvb, &tz );
182 #endif
183                 /* execute pre-script callbacks, if any; -jiri */
184                 /* if some of the callbacks said not to continue with
185                    script processing, don't do so
186                    if we are here basic sanity checks are already done
187                    (like presence of at least one via), so you can count
188                    on via1 being parsed in a pre-script callback --andrei
189                 */
190                 if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
191                         goto end; /* drop the request */
192
193                 set_route_type(REQUEST_ROUTE);
194                 /* exec the routing script */
195                 if (run_top_route(main_rt.rlist[DEFAULT_RT], msg, 0)<0){
196                         LOG(L_WARN, "WARNING: receive_msg: "
197                                         "error while trying script\n");
198                         goto error_req;
199                 }
200
201 #ifdef STATS
202                 gettimeofday( & tve, &tz );
203                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
204                 stats->processed_requests++;
205                 stats->acc_req_time += diff;
206                 DBG("successfully ran routing scripts...(%d usec)\n", diff);
207                 STATS_RX_REQUEST( msg->first_line.u.request.method_value );
208 #endif
209
210                 /* execute post request-script callbacks */
211                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
212         }else if (msg->first_line.type==SIP_REPLY){
213                 /* sanity checks */
214                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
215                         /* no via, send back error ? */
216                         LOG(L_ERR, "ERROR: receive_msg: no via found in reply\n");
217                         goto error02;
218                 }
219
220 #ifdef STATS
221                 gettimeofday( & tvb, &tz );
222                 STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
223 #endif
224                 
225                 /* execute pre-script callbacks, if any; -jiri */
226                 /* if some of the callbacks said not to continue with
227                    script processing, don't do so
228                    if we are here basic sanity checks are already done
229                    (like presence of at least one via), so you can count
230                    on via1 being parsed in a pre-script callback --andrei
231                 */
232                 if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 )
233                         goto end; /* drop the request */
234
235                 /* exec the onreply routing script */
236                 if (onreply_rt.rlist[DEFAULT_RT]){
237                         set_route_type(ONREPLY_ROUTE);
238                         ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg, 0);
239                         if (ret<0){
240                                 LOG(L_WARN, "WARNING: receive_msg: "
241                                                 "error while trying onreply script\n");
242                                 goto error_rpl;
243                         }else if (ret==0) goto skip_send_reply; /* drop the message, 
244                                                                                                            no error */
245                 }
246                 /* send the msg */
247                 forward_reply(msg);
248         skip_send_reply:
249 #ifdef STATS
250                 gettimeofday( & tve, &tz );
251                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
252                 stats->processed_responses++;
253                 stats->acc_res_time+=diff;
254                 DBG("successfully ran reply processing...(%d usec)\n", diff);
255 #endif
256
257                 /* execute post reply-script callbacks */
258                 exec_post_script_cb(msg, ONREPLY_CB_TYPE);
259         }
260
261 end:
262 #ifdef STATS
263         skipped = 0;
264 #endif
265         /* free possible loaded avps -bogdan */
266         reset_avps();
267         DBG("receive_msg: cleaning up\n");
268         free_sip_msg(msg);
269         pkg_free(msg);
270 #ifdef STATS
271         if (skipped) STATS_RX_DROPS;
272 #endif
273         return 0;
274 error_rpl:
275         /* execute post reply-script callbacks */
276         exec_post_script_cb(msg, ONREPLY_CB_TYPE);
277         reset_avps();
278         goto error02;
279 error_req:
280         DBG("receive_msg: error:...\n");
281         /* execute post request-script callbacks */
282         exec_post_script_cb(msg, REQUEST_CB_TYPE);
283 error03:
284         /* free possible loaded avps -bogdan */
285         reset_avps();
286 error02:
287         free_sip_msg(msg);
288         pkg_free(msg);
289 error00:
290         STATS_RX_DROPS;
291         return -1;
292 }
293