core: build_req_buf_from_sip_req() has a new parameter
[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 #include <string.h>
45 #include <stdlib.h>
46 #include <sys/time.h>
47
48 #include "receive.h"
49 #include "globals.h"
50 #include "dprint.h"
51 #include "route.h"
52 #include "parser/msg_parser.h"
53 #include "forward.h"
54 #include "action.h"
55 #include "mem/mem.h"
56 #include "stats.h"
57 #include "ip_addr.h"
58 #include "script_cb.h"
59 #include "nonsip_hooks.h"
60 #include "dset.h"
61 #include "usr_avp.h"
62 #include "select_buf.h"
63
64 #include "tcp_server.h" /* for tcpconn_add_alias */
65 #include "tcp_options.h" /* for access to tcp_accept_aliases*/
66 #include "cfg/cfg.h"
67
68 #ifdef DEBUG_DMALLOC
69 #include <mem/dmalloc.h>
70 #endif
71
72 unsigned int msg_no=0;
73 /* address preset vars */
74 str default_global_address={0,0};
75 str default_global_port={0,0};
76 str default_via_address={0,0};
77 str default_via_port={0,0};
78
79 /**
80  * increment msg_no and return the new value
81  */
82 unsigned int inc_msg_no(void)
83 {
84         return ++msg_no;
85 }
86
87
88 /* WARNING: buf must be 0 terminated (buf[len]=0) or some things might 
89  * break (e.g.: modules/textops)
90  */
91 int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info) 
92 {
93         struct sip_msg* msg;
94         int ret;
95 #ifdef STATS
96         int skipped = 1;
97         struct timeval tvb, tve;        
98         struct timezone tz;
99         unsigned int diff;
100 #endif
101
102         msg=pkg_malloc(sizeof(struct sip_msg));
103         if (msg==0) {
104                 LOG(L_ERR, "ERROR: receive_msg: no mem for sip_msg\n");
105                 goto error00;
106         }
107         msg_no++;
108         /* number of vias parsed -- good for diagnostic info in replies */
109         via_cnt=0;
110
111         memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */
112         /* fill in msg */
113         msg->buf=buf;
114         msg->len=len;
115         /* zero termination (termination of orig message bellow not that
116            useful as most of the work is done with scratch-pad; -jiri  */
117         /* buf[len]=0; */ /* WARNING: zero term removed! */
118         msg->rcv=*rcv_info;
119         msg->id=msg_no;
120         msg->set_global_address=default_global_address;
121         msg->set_global_port=default_global_port;
122         
123         if (parse_msg(buf,len, msg)!=0){
124                 LOG(L_ERR, "ERROR: receive_msg: parse_msg failed\n");
125                 goto error02;
126         }
127         DBG("After parse_msg...\n");
128
129
130         /* ... clear branches from previous message */
131         clear_branches();
132
133         if (msg->first_line.type==SIP_REQUEST){
134                 if (!IS_SIP(msg)){
135                         if ((ret=nonsip_msg_run_hooks(msg))!=NONSIP_MSG_ACCEPT){
136                                 if (unlikely(ret==NONSIP_MSG_ERROR))
137                                         goto error03;
138                                 goto end; /* drop the message */
139                         }
140                 }
141                 /* sanity checks */
142                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
143                         /* no via, send back error ? */
144                         LOG(L_ERR, "ERROR: receive_msg: no via found in request\n");
145                         goto error02;
146                 }
147                 /* check if necessary to add receive?->moved to forward_req */
148                 /* check for the alias stuff */
149 #ifdef USE_TCP
150                 if (msg->via1->alias && cfg_get(tcp, tcp_cfg, accept_aliases) && 
151                                 (((rcv_info->proto==PROTO_TCP) && !tcp_disable)
152 #ifdef USE_TLS
153                                         || ((rcv_info->proto==PROTO_TLS) && !tls_disable)
154 #endif
155                                 )
156                         ){
157                         if (tcpconn_add_alias(rcv_info->proto_reserved1, msg->via1->port,
158                                                                         rcv_info->proto)!=0){
159                                 LOG(L_ERR, " ERROR: receive_msg: tcp alias failed\n");
160                                 /* continue */
161                         }
162                 }
163 #endif
164                         
165         /*      skip: */
166                 DBG("preparing to run routing scripts...\n");
167 #ifdef  STATS
168                 gettimeofday( & tvb, &tz );
169 #endif
170                 /* execute pre-script callbacks, if any; -jiri */
171                 /* if some of the callbacks said not to continue with
172                    script processing, don't do so
173                    if we are here basic sanity checks are already done
174                    (like presence of at least one via), so you can count
175                    on via1 being parsed in a pre-script callback --andrei
176                 */
177                 if (exec_pre_script_cb(msg, REQUEST_CB_TYPE)==0 )
178                         goto end; /* drop the request */
179
180                 set_route_type(REQUEST_ROUTE);
181                 /* exec the routing script */
182                 if (run_top_route(main_rt.rlist[DEFAULT_RT], msg)<0){
183                         LOG(L_WARN, "WARNING: receive_msg: "
184                                         "error while trying script\n");
185                         goto error_req;
186                 }
187
188 #ifdef STATS
189                 gettimeofday( & tve, &tz );
190                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
191                 stats->processed_requests++;
192                 stats->acc_req_time += diff;
193                 DBG("successfully ran routing scripts...(%d usec)\n", diff);
194                 STATS_RX_REQUEST( msg->first_line.u.request.method_value );
195 #endif
196
197                 /* execute post request-script callbacks */
198                 exec_post_script_cb(msg, REQUEST_CB_TYPE);
199         }else if (msg->first_line.type==SIP_REPLY){
200                 /* sanity checks */
201                 if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){
202                         /* no via, send back error ? */
203                         LOG(L_ERR, "ERROR: receive_msg: no via found in reply\n");
204                         goto error02;
205                 }
206
207 #ifdef STATS
208                 gettimeofday( & tvb, &tz );
209                 STATS_RX_RESPONSE ( msg->first_line.u.reply.statuscode / 100 );
210 #endif
211                 
212                 /* execute pre-script callbacks, if any; -jiri */
213                 /* if some of the callbacks said not to continue with
214                    script processing, don't do so
215                    if we are here basic sanity checks are already done
216                    (like presence of at least one via), so you can count
217                    on via1 being parsed in a pre-script callback --andrei
218                 */
219                 if (exec_pre_script_cb(msg, ONREPLY_CB_TYPE)==0 )
220                         goto end; /* drop the request */
221
222                 /* exec the onreply routing script */
223                 if (onreply_rt.rlist[DEFAULT_RT]){
224                         set_route_type(ONREPLY_ROUTE);
225                         ret=run_top_route(onreply_rt.rlist[DEFAULT_RT], msg);
226                         if (ret<0){
227                                 LOG(L_WARN, "WARNING: receive_msg: "
228                                                 "error while trying onreply script\n");
229                                 goto error_rpl;
230                         }else if (ret==0) goto skip_send_reply; /* drop the message, 
231                                                                                                            no error */
232                 }
233                 /* send the msg */
234                 forward_reply(msg);
235         skip_send_reply:
236 #ifdef STATS
237                 gettimeofday( & tve, &tz );
238                 diff = (tve.tv_sec-tvb.tv_sec)*1000000+(tve.tv_usec-tvb.tv_usec);
239                 stats->processed_responses++;
240                 stats->acc_res_time+=diff;
241                 DBG("successfully ran reply processing...(%d usec)\n", diff);
242 #endif
243
244                 /* execute post reply-script callbacks */
245                 exec_post_script_cb(msg, ONREPLY_CB_TYPE);
246         }
247
248 end:
249 #ifdef STATS
250         skipped = 0;
251 #endif
252         /* free possible loaded avps -bogdan */
253         reset_avps();
254         DBG("receive_msg: cleaning up\n");
255         free_sip_msg(msg);
256         pkg_free(msg);
257 #ifdef STATS
258         if (skipped) STATS_RX_DROPS;
259 #endif
260         return 0;
261 error_rpl:
262         /* execute post reply-script callbacks */
263         exec_post_script_cb(msg, ONREPLY_CB_TYPE);
264         reset_avps();
265         goto error02;
266 error_req:
267         DBG("receive_msg: error:...\n");
268         /* execute post request-script callbacks */
269         exec_post_script_cb(msg, REQUEST_CB_TYPE);
270 error03:
271         /* free possible loaded avps -bogdan */
272         reset_avps();
273 error02:
274         free_sip_msg(msg);
275         pkg_free(msg);
276 error00:
277         STATS_RX_DROPS;
278         return -1;
279 }
280