/src/opensips/script_cb.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2001-2003 FhG Fokus |
3 | | * |
4 | | * This file is part of opensips, a free SIP server. |
5 | | * |
6 | | * opensips is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version |
10 | | * |
11 | | * opensips is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; if not, write to the Free Software |
18 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | | * |
20 | | * History: |
21 | | * -------- |
22 | | * 2003-03-29 cleaning pkg allocation introduced (jiri) |
23 | | * 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei) |
24 | | * 2005-02-13 script callbacks devided into request and reply types (bogdan) |
25 | | * 2009-05-21 keep the callback lists in the same order as callbacks |
26 | | were registered (bogdan) |
27 | | */ |
28 | | |
29 | | /*! |
30 | | * \file |
31 | | * \brief Script callbacks |
32 | | */ |
33 | | |
34 | | |
35 | | #include <stdlib.h> |
36 | | #include "script_cb.h" |
37 | | #include "dprint.h" |
38 | | #include "error.h" |
39 | | #include "mem/mem.h" |
40 | | |
41 | | static struct script_cb *pre_req_cb=0; |
42 | | static struct script_cb *post_req_cb=0; |
43 | | |
44 | | static struct script_cb *pre_rpl_cb=0; |
45 | | static struct script_cb *post_rpl_cb=0; |
46 | | |
47 | | static struct script_cb *parse_err_cb=0; |
48 | | |
49 | | static unsigned int cb_id=0; |
50 | | |
51 | | struct raw_processing_cb_list* pre_processing_cb_list = NULL; |
52 | | struct raw_processing_cb_list* post_processing_cb_list = NULL; |
53 | | |
54 | | static inline int add_callback( struct script_cb **list, |
55 | | cb_function f, void *param, int prio) |
56 | 0 | { |
57 | 0 | struct script_cb *last_cb; |
58 | 0 | struct script_cb *new_cb; |
59 | |
|
60 | 0 | new_cb=pkg_malloc(sizeof(struct script_cb)); |
61 | 0 | if (new_cb==0) { |
62 | 0 | LM_ERR("out of pkg memory\n"); |
63 | 0 | return -1; |
64 | 0 | } |
65 | 0 | new_cb->cbf = f; |
66 | 0 | new_cb->id = cb_id++; |
67 | 0 | new_cb->param = param; |
68 | 0 | new_cb->next = NULL; |
69 | 0 | new_cb->prio = prio; |
70 | | |
71 | | /* descending priority sorting; equal priorities are inserted at the end |
72 | | it is important to keep the order at register time, as this reflects the |
73 | | order of loading/init the modules --bogdan */ |
74 | 0 | if (*list==NULL) { |
75 | 0 | *list = new_cb; |
76 | 0 | } else if ((*list)->prio < prio) { |
77 | 0 | new_cb->next = *list; |
78 | 0 | *list = new_cb; |
79 | 0 | } else { |
80 | 0 | for (last_cb = *list; |
81 | 0 | last_cb->next && last_cb->next->prio >= prio; |
82 | 0 | last_cb = last_cb->next) |
83 | 0 | ; |
84 | |
|
85 | 0 | new_cb->next = last_cb->next; |
86 | 0 | last_cb->next = new_cb; |
87 | 0 | } |
88 | |
|
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | | |
93 | | int __register_script_cb( cb_function f, int type, void *param, int prio) |
94 | 0 | { |
95 | | /* type checkings */ |
96 | 0 | if ( (type&(REQ_TYPE_CB|RPL_TYPE_CB|PARSE_ERR_CB))==0 ) { |
97 | 0 | LM_CRIT("request / reply / error type not specified\n"); |
98 | 0 | goto error; |
99 | 0 | } |
100 | 0 | if ( (type&(PRE_SCRIPT_CB|POST_SCRIPT_CB|PARSE_ERR_CB))==0 || |
101 | 0 | (type&PRE_SCRIPT_CB && type&POST_SCRIPT_CB) ) { |
102 | 0 | LM_CRIT("callback POST or PRE type must be exactly one\n"); |
103 | 0 | goto error; |
104 | 0 | } |
105 | | |
106 | 0 | if (type&PARSE_ERR_CB) { |
107 | 0 | if (add_callback( &parse_err_cb, f, param, prio)<0) |
108 | 0 | goto add_error; |
109 | 0 | } |
110 | | |
111 | 0 | if (type&REQ_TYPE_CB) { |
112 | | /* callback for request script */ |
113 | 0 | if (type&PRE_SCRIPT_CB) { |
114 | 0 | if (add_callback( &pre_req_cb, f, param, prio)<0) |
115 | 0 | goto add_error; |
116 | 0 | } else if (type&POST_SCRIPT_CB) { |
117 | 0 | if (add_callback( &post_req_cb, f, param, prio)<0) |
118 | 0 | goto add_error; |
119 | 0 | } |
120 | 0 | } |
121 | 0 | if (type&RPL_TYPE_CB) { |
122 | | /* callback (also) for reply script */ |
123 | 0 | if (type&PRE_SCRIPT_CB) { |
124 | 0 | if (add_callback( &pre_rpl_cb, f, param, prio)<0) |
125 | 0 | goto add_error; |
126 | 0 | } else if (type&POST_SCRIPT_CB) { |
127 | 0 | if (add_callback( &post_rpl_cb, f, param, prio)<0) |
128 | 0 | goto add_error; |
129 | 0 | } |
130 | 0 | } |
131 | | |
132 | 0 | return 0; |
133 | 0 | add_error: |
134 | 0 | LM_ERR("failed to add callback\n"); |
135 | 0 | error: |
136 | 0 | return -1; |
137 | 0 | } |
138 | | |
139 | | |
140 | | static inline void destroy_cb_list(struct script_cb **list) |
141 | 0 | { |
142 | 0 | struct script_cb *foo; |
143 | |
|
144 | 0 | while( *list ) { |
145 | 0 | foo = *list; |
146 | 0 | *list = (*list)->next; |
147 | 0 | pkg_free( foo ); |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | |
152 | | void destroy_script_cb(void) |
153 | 0 | { |
154 | 0 | destroy_cb_list( &pre_req_cb ); |
155 | 0 | destroy_cb_list( &post_req_cb ); |
156 | 0 | destroy_cb_list( &pre_rpl_cb ); |
157 | 0 | destroy_cb_list( &post_req_cb ); |
158 | 0 | destroy_cb_list( &parse_err_cb ); |
159 | 0 | } |
160 | | |
161 | | |
162 | | static inline int exec_pre_cb( struct sip_msg *msg, struct script_cb *cb) |
163 | 0 | { |
164 | 0 | int bitmask = SCB_RUN_ALL; |
165 | |
|
166 | 0 | for ( ; cb ; cb=cb->next ) { |
167 | 0 | bitmask &= cb->cbf(msg, cb->param); |
168 | |
|
169 | 0 | if (bitmask == SCB_DROP_MSG) |
170 | 0 | break; |
171 | 0 | } |
172 | |
|
173 | 0 | return bitmask; |
174 | 0 | } |
175 | | |
176 | | |
177 | | static inline int exec_post_cb( struct sip_msg *msg, struct script_cb *cb) |
178 | 0 | { |
179 | 0 | for ( ; cb ; cb=cb->next){ |
180 | 0 | cb->cbf( msg, cb->param); |
181 | 0 | } |
182 | 0 | return 1; |
183 | 0 | } |
184 | | |
185 | | |
186 | | int exec_pre_req_cb( struct sip_msg *msg) |
187 | 0 | { |
188 | 0 | return exec_pre_cb( msg, pre_req_cb); |
189 | 0 | } |
190 | | |
191 | | int exec_pre_rpl_cb( struct sip_msg *msg) |
192 | 0 | { |
193 | 0 | return exec_pre_cb( msg, pre_rpl_cb); |
194 | 0 | } |
195 | | |
196 | | int exec_post_req_cb( struct sip_msg *msg) |
197 | 0 | { |
198 | 0 | return exec_post_cb( msg, post_req_cb); |
199 | 0 | } |
200 | | |
201 | | int exec_post_rpl_cb( struct sip_msg *msg) |
202 | 0 | { |
203 | 0 | return exec_post_cb( msg, post_rpl_cb); |
204 | 0 | } |
205 | | |
206 | | int exec_parse_err_cb( struct sip_msg *msg) |
207 | 0 | { |
208 | 0 | return exec_post_cb( msg, parse_err_cb); |
209 | 0 | } |
210 | | |
211 | | static inline int insert_raw_processing_cb(raw_processing_func f, int type, struct raw_processing_cb_list* list, char freeable) |
212 | 0 | { |
213 | 0 | struct raw_processing_cb_list *elem; |
214 | |
|
215 | 0 | if (f == NULL) { |
216 | 0 | LM_ERR("null callback\n"); |
217 | 0 | return -1; |
218 | 0 | } |
219 | | |
220 | 0 | elem = pkg_malloc(sizeof(struct raw_processing_cb_list)); |
221 | 0 | if (elem == NULL) { |
222 | 0 | LM_ERR("no more pkg mem\n"); |
223 | 0 | return -1; |
224 | 0 | } |
225 | | |
226 | 0 | elem->f = f; |
227 | 0 | elem->freeable = freeable; |
228 | 0 | elem->next = NULL; |
229 | |
|
230 | 0 | if (list == NULL) { |
231 | 0 | list = elem; |
232 | 0 | return !(type==PRE_RAW_PROCESSING ? (pre_processing_cb_list=list) |
233 | 0 | : (post_processing_cb_list=list)); |
234 | 0 | } else { |
235 | 0 | while (list->next != NULL) |
236 | 0 | list = list->next; |
237 | 0 | list->next=elem; |
238 | 0 | } |
239 | | |
240 | 0 | return 0; |
241 | |
|
242 | 0 | } |
243 | | |
244 | | int register_pre_raw_processing_cb(raw_processing_func f, int type, char freeable) |
245 | 0 | { |
246 | 0 | return insert_raw_processing_cb(f, type, pre_processing_cb_list, freeable); |
247 | 0 | } |
248 | | |
249 | | int register_post_raw_processing_cb(raw_processing_func f, int type, char freeable) |
250 | 0 | { |
251 | 0 | return insert_raw_processing_cb(f, type, post_processing_cb_list, freeable); |
252 | 0 | } |
253 | | |
254 | | |
255 | | |
256 | | |
257 | | |
258 | | int run_pre_raw_processing_cb(int type, str* data, struct sip_msg* msg) |
259 | 0 | { |
260 | 0 | return run_raw_processing_cb(type, data, msg, pre_processing_cb_list); |
261 | 0 | } |
262 | | |
263 | | int run_post_raw_processing_cb(int type, str* data, struct sip_msg* msg) |
264 | 0 | { |
265 | 0 | return run_raw_processing_cb(type, data, msg, post_processing_cb_list); |
266 | 0 | } |
267 | | |
268 | | int run_raw_processing_cb(int type, str *data, struct sip_msg* msg, struct raw_processing_cb_list* list) |
269 | 0 | { |
270 | |
|
271 | 0 | struct raw_processing_cb_list *foo=NULL, *last_good=NULL, *head=NULL; |
272 | 0 | char *initial_data = data->s, *input_data; |
273 | 0 | int rc; |
274 | |
|
275 | 0 | if (list == NULL) |
276 | 0 | return 0; |
277 | | |
278 | 0 | while (list) { |
279 | 0 | input_data = data->s; |
280 | | /* a return code bigger than 0 means you want to keep the callback */ |
281 | 0 | if ((rc = list->f(data, msg)) < 0) { |
282 | 0 | LM_ERR("failed to run callback\n"); |
283 | 0 | return -1; |
284 | 0 | } |
285 | | |
286 | 0 | if (input_data != initial_data && input_data != data->s) |
287 | 0 | pkg_free(input_data); |
288 | |
|
289 | 0 | foo = list; |
290 | 0 | list = list->next; |
291 | |
|
292 | 0 | if (foo != NULL) { |
293 | 0 | if (foo->freeable && rc == 0) { |
294 | | /* foo will be gone so link the last good element |
295 | | * to the next one */ |
296 | 0 | if (last_good) |
297 | 0 | last_good->next=list; |
298 | |
|
299 | 0 | pkg_free(foo); |
300 | 0 | } else { |
301 | | /* keep the first element not to be freed */ |
302 | 0 | if (head == NULL) |
303 | 0 | head = foo; |
304 | | /* and keep track of the last viable element to link with the |
305 | | * next viable element */ |
306 | 0 | last_good = foo; |
307 | 0 | } |
308 | 0 | } |
309 | 0 | } |
310 | | |
311 | 0 | return !(type==PRE_RAW_PROCESSING?(pre_processing_cb_list=head) |
312 | 0 | :(post_processing_cb_list=head)); |
313 | 0 | } |
314 | | |