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