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