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