Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2010-2014 OpenSIPS Solutions |
3 | | * Copyright (C) 2001-2003 FhG Fokus |
4 | | * |
5 | | * This file is part of opensips, a free SIP server. |
6 | | * |
7 | | * opensips is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 2 of the License, or |
10 | | * (at your option) any later version |
11 | | * |
12 | | * opensips is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | * |
21 | | * History: |
22 | | * --------- |
23 | | * 2003-02-28 scratchpad compatibility abandoned (jiri) |
24 | | * 2003-01-29 transport-independent message zero-termination in |
25 | | * receive_msg (jiri) |
26 | | * 2003-02-07 undoed jiri's zero term. changes (they break tcp) (andrei) |
27 | | * 2003-02-10 moved zero-term in the calling functions (udp_receive & |
28 | | * tcp_read_req) |
29 | | * 2003-08-13 fixed exec_pre_cb returning 0 (backported from stable) (andrei) |
30 | | * 2004-02-06 added user preferences support - destroy_avps() (bogdan) |
31 | | * 2004-04-30 exec_pre_cb is called after basic sanity checks (at least one |
32 | | * via present & parsed ok) (andrei) |
33 | | * 2004-08-23 avp core changed - destroy_avp-> reset_avps (bogdan) |
34 | | * 2005-07-26 default onreply route added (andrei) |
35 | | * 2006-12-22 functions for script flags added (bogdan) |
36 | | */ |
37 | | |
38 | | /*! |
39 | | * \file |
40 | | * \brief Receive message and process routing for it |
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 "ip_addr.h" |
57 | | #include "script_cb.h" |
58 | | #include "dset.h" |
59 | | #include "usr_avp.h" |
60 | | #include "core_stats.h" |
61 | | #include "ut.h" |
62 | | #include "context.h" |
63 | | |
64 | | |
65 | | #ifdef DEBUG_DMALLOC |
66 | | #include <mem/dmalloc.h> |
67 | | #endif |
68 | | |
69 | | static unsigned int msg_no=0; |
70 | | /* address preset vars */ |
71 | | str * const default_global_address=&STR_NULL; |
72 | | str * const default_global_port=&STR_NULL; |
73 | | str * const default_via_address=&STR_NULL; |
74 | | str * const default_via_port=&STR_NULL; |
75 | | |
76 | | |
77 | | unsigned int get_next_msg_no(void) |
78 | 0 | { |
79 | 0 | return ++msg_no; |
80 | 0 | } |
81 | | |
82 | | |
83 | | #define prepare_context( _ctx, _err ) \ |
84 | 0 | do { \ |
85 | 0 | if (_ctx==NULL) { \ |
86 | 0 | _ctx = context_alloc(CONTEXT_GLOBAL);\ |
87 | 0 | if (_ctx==NULL) { \ |
88 | 0 | LM_ERR("failed to allocated new context, skipping\n"); \ |
89 | 0 | goto _err; \ |
90 | 0 | } \ |
91 | 0 | } \ |
92 | 0 | memset( _ctx, 0, context_size(CONTEXT_GLOBAL)); \ |
93 | 0 | }while(0) |
94 | | |
95 | | |
96 | | /*! \note WARNING: buf must be 0 terminated (buf[len]=0) or some things might |
97 | | * break (e.g.: modules/textops) |
98 | | */ |
99 | | int receive_msg(char* buf, unsigned int len, struct receive_info* rcv_info, |
100 | | context_p existing_context, unsigned int msg_flags) |
101 | 0 | { |
102 | 0 | #define reset_global_context() \ |
103 | 0 | do {\ |
104 | 0 | if (!current_processing_ctx) { \ |
105 | 0 | ctx = NULL; \ |
106 | 0 | } else { \ |
107 | 0 | context_destroy(CONTEXT_GLOBAL, ctx); \ |
108 | 0 | set_global_context(NULL); \ |
109 | 0 | } \ |
110 | 0 | } while (0) |
111 | 0 | static context_p ctx = NULL; |
112 | |
|
113 | 0 | struct sip_msg* msg; |
114 | 0 | struct timeval start; |
115 | 0 | int rc, old_route_type; |
116 | 0 | char *tmp; |
117 | 0 | str in_buff; |
118 | |
|
119 | 0 | in_buff.len = len; |
120 | 0 | in_buff.s = buf; |
121 | |
|
122 | 0 | if (existing_context) { |
123 | 0 | context_free(ctx); |
124 | 0 | ctx = existing_context; |
125 | 0 | } |
126 | | |
127 | | /* the raw processing callbacks can change the buffer, |
128 | | further use in_buff.s and at the end try to free in_buff.s |
129 | | if changed by callbacks */ |
130 | 0 | if (run_pre_raw_processing_cb(PRE_RAW_PROCESSING,&in_buff,NULL)<0) { |
131 | 0 | LM_ERR("error in running pre raw callbacks, dropping\n"); |
132 | 0 | goto error; |
133 | 0 | } |
134 | | /* update the length for further processing */ |
135 | 0 | len = in_buff.len; |
136 | |
|
137 | 0 | msg=pkg_malloc(sizeof(struct sip_msg)); |
138 | 0 | if (msg==0) { |
139 | 0 | LM_ERR("no pkg mem left for sip_msg\n"); |
140 | 0 | goto error; |
141 | 0 | } |
142 | 0 | msg_no++; |
143 | | /* number of vias parsed -- good for diagnostic info in replies */ |
144 | 0 | via_cnt=0; |
145 | |
|
146 | 0 | memset(msg,0, sizeof(struct sip_msg)); /* init everything to 0 */ |
147 | | /* fill in msg */ |
148 | 0 | msg->buf=in_buff.s; |
149 | 0 | msg->len=len; |
150 | 0 | msg->rcv=*rcv_info; |
151 | 0 | msg->id=msg_no; |
152 | 0 | msg->msg_flags=msg_flags; |
153 | 0 | msg->ruri_q = Q_UNSPECIFIED; |
154 | |
|
155 | 0 | if (parse_msg_opt(in_buff.s,len, msg, 0)!=0){ |
156 | 0 | tmp=ip_addr2a(&(rcv_info->src_ip)); |
157 | 0 | LM_ERR("Unable to parse msg received from [%s:%d]\n", |
158 | 0 | tmp, rcv_info->src_port); |
159 | | /* if a REQUEST msg was detected (first line was successfully parsed) |
160 | | we should trigger the error route */ |
161 | 0 | if ( msg->first_line.type==SIP_REQUEST && sroutes->error.a!=NULL ) { |
162 | 0 | if (existing_context == NULL) |
163 | 0 | prepare_context( ctx, parse_error ); |
164 | 0 | set_global_context(ctx); |
165 | 0 | run_error_route(msg, 1); |
166 | 0 | reset_global_context(); |
167 | 0 | } |
168 | 0 | goto parse_error; |
169 | 0 | } |
170 | 0 | LM_DBG("After parse_msg...\n"); |
171 | |
|
172 | 0 | start_expire_timer(start,execmsgthreshold); |
173 | | /* jumpt to parse_error_reset (not to parse_error) while |
174 | | * start_expire_timer() is still on */ |
175 | | |
176 | | /* ... clear branches from previous message */ |
177 | 0 | clear_dset(); |
178 | |
|
179 | 0 | if (msg->first_line.type==SIP_REQUEST) { |
180 | 0 | update_stat( rcv_reqs, 1); |
181 | | /* sanity checks */ |
182 | 0 | if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ |
183 | | /* no via, send back error ? */ |
184 | 0 | LM_ERR("no via found in request\n"); |
185 | 0 | update_stat( err_reqs, 1); |
186 | 0 | goto parse_error_reset; |
187 | 0 | } |
188 | | /* check if necessary to add receive?->moved to forward_req */ |
189 | | |
190 | | /* should we reuse this connection for the opposite direction? */ |
191 | 0 | if (is_tcp_based_proto(rcv_info->proto) |
192 | 0 | && tcpconn_add_alias(msg, rcv_info->proto_reserved1, |
193 | 0 | msg->via1->port, rcv_info->proto) != 0) { |
194 | 0 | LM_WARN("tcp alias failed\n"); |
195 | | /* continue */ |
196 | 0 | } |
197 | |
|
198 | 0 | LM_DBG("preparing to run routing scripts...\n"); |
199 | | /* set request route type --bogdan*/ |
200 | 0 | set_route_type( REQUEST_ROUTE ); |
201 | | |
202 | | /* prepare and set a new processing context for this request only if |
203 | | * no context was set from the upper layers */ |
204 | 0 | if (existing_context == NULL) |
205 | 0 | prepare_context( ctx, parse_error_reset ); |
206 | 0 | set_global_context(ctx); |
207 | | |
208 | | /* execute pre-script callbacks, if any; |
209 | | * if some of the callbacks said not to continue with |
210 | | * script processing, don't do so; |
211 | | * if we are here basic sanity checks are already done |
212 | | * (like presence of at least one via), so you can count |
213 | | * on via1 being parsed in a pre-script callback --andrei |
214 | | */ |
215 | 0 | rc = exec_pre_req_cb(msg); |
216 | 0 | if (rc == SCB_DROP_MSG) { |
217 | 0 | update_stat( drp_reqs, 1); |
218 | 0 | goto end; /* drop the message */ |
219 | 0 | } |
220 | | |
221 | | /* exec the routing script */ |
222 | 0 | if (rc & SCB_RUN_TOP_ROUTE) |
223 | | /* run the main request route and skip post_script callbacks |
224 | | * if the TOBE_CONTINUE flag is returned */ |
225 | 0 | if ( run_top_route(sroutes->request[DEFAULT_RT], msg) & |
226 | 0 | ACT_FL_TBCONT ) |
227 | 0 | goto end; |
228 | | |
229 | | /* execute post request-script callbacks */ |
230 | 0 | if (rc & SCB_RUN_POST_CBS) |
231 | 0 | exec_post_req_cb(msg); |
232 | |
|
233 | 0 | } else if (msg->first_line.type==SIP_REPLY) { |
234 | 0 | update_stat( rcv_rpls, 1); |
235 | | /* sanity checks */ |
236 | 0 | if ((msg->via1==0) || (msg->via1->error!=PARSE_OK)){ |
237 | | /* no via, send back error ? */ |
238 | 0 | LM_ERR("no via found in reply\n"); |
239 | 0 | update_stat( err_rpls, 1); |
240 | 0 | goto parse_error_reset; |
241 | 0 | } |
242 | | |
243 | | /* set reply route type --bogdan*/ |
244 | 0 | set_route_type( ONREPLY_ROUTE ); |
245 | | |
246 | | /* prepare and set a new processing context for this reply only if |
247 | | * no context was set from the upper layers */ |
248 | 0 | if (existing_context == NULL) |
249 | 0 | prepare_context( ctx, parse_error_reset ); |
250 | 0 | set_global_context(ctx); |
251 | | |
252 | | /* execute pre-script callbacks, if any ; |
253 | | * if some of the callbacks said not to continue with |
254 | | * script processing, don't do so ; |
255 | | * if we are here, basic sanity checks are already done |
256 | | * (like presence of at least one via), so you can count |
257 | | * on via1 being parsed in a pre-script callback --andrei |
258 | | */ |
259 | 0 | rc = exec_pre_rpl_cb(msg); |
260 | 0 | if (rc == SCB_DROP_MSG) { |
261 | 0 | update_stat( drp_rpls, 1); |
262 | 0 | goto end; /* drop the reply */ |
263 | 0 | } |
264 | | |
265 | 0 | swap_route_type(old_route_type, ONREPLY_ROUTE); |
266 | | /* exec the onreply routing script */ |
267 | 0 | if (rc & SCB_RUN_TOP_ROUTE && sroutes->onreply[DEFAULT_RT].a && |
268 | 0 | (run_top_route(sroutes->onreply[DEFAULT_RT],msg) & ACT_FL_DROP) |
269 | 0 | && msg->REPLY_STATUS < 200) { |
270 | 0 | set_route_type(old_route_type); |
271 | |
|
272 | 0 | LM_DBG("dropping provisional reply %d\n", msg->REPLY_STATUS); |
273 | 0 | update_stat( drp_rpls, 1); |
274 | 0 | goto end; /* drop the message */ |
275 | 0 | } else { |
276 | 0 | set_route_type(old_route_type); |
277 | | /* send the msg */ |
278 | 0 | forward_reply(msg); |
279 | | /* TODO - TX reply stat */ |
280 | 0 | } |
281 | | |
282 | | /* execute post reply-script callbacks */ |
283 | 0 | if (rc & SCB_RUN_POST_CBS) |
284 | 0 | exec_post_rpl_cb(msg); |
285 | 0 | } |
286 | | |
287 | 0 | end: |
288 | 0 | reset_global_context(); |
289 | |
|
290 | 0 | __stop_expire_timer( start, execmsgthreshold, "msg processing", |
291 | 0 | msg->buf, msg->len, 0, slow_msgs); |
292 | 0 | reset_longest_action_list(execmsgthreshold); |
293 | | |
294 | | /* free possible loaded avps -bogdan */ |
295 | 0 | reset_avps(); |
296 | 0 | LM_DBG("cleaning up\n"); |
297 | 0 | free_sip_msg(msg); |
298 | 0 | pkg_free(msg); |
299 | 0 | if (in_buff.s != buf) |
300 | 0 | pkg_free(in_buff.s); |
301 | 0 | return 0; |
302 | 0 | parse_error_reset: |
303 | 0 | reset_longest_action_list(execmsgthreshold); |
304 | 0 | parse_error: |
305 | 0 | exec_parse_err_cb(msg); |
306 | 0 | free_sip_msg(msg); |
307 | 0 | pkg_free(msg); |
308 | 0 | error: |
309 | 0 | if (in_buff.s != buf) |
310 | 0 | pkg_free(in_buff.s); |
311 | 0 | return -1; |
312 | 0 | } |
313 | | |