/src/opensips/serialize.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2005 Juha Heinanen |
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 | | * 2005-11-29 splitted from lcr module (bogdan) |
23 | | */ |
24 | | |
25 | | /*! |
26 | | * \file |
27 | | * \brief Sequential forking implementation |
28 | | */ |
29 | | #define _ISOC11_SOURCE |
30 | | #define _DEFAULT_SOURCE |
31 | | |
32 | | #include <assert.h> |
33 | | |
34 | | #include "str.h" |
35 | | #include "qvalue.h" |
36 | | #include "usr_avp.h" |
37 | | #include "dset.h" |
38 | | #include "action.h" |
39 | | #include "route.h" |
40 | | #include "parser/msg_parser.h" |
41 | | #include "parser/parse_rr.h" |
42 | | #include "mem/mem.h" |
43 | | |
44 | | |
45 | | struct serial_contact { |
46 | | str enc_info; |
47 | | qvalue_t q; |
48 | | unsigned short q_flag; |
49 | | int next; |
50 | | }; |
51 | | |
52 | 0 | #define Q_FLAG (1<<4) /*!< usr_avp flag for sequential forking */ |
53 | 0 | #define SERIAL_AVP_ALIAS "serial_branch" /*!< avp alias to be used */ |
54 | | #define SERIAL_AVL_ID 0xff3434 /*!< avp ID of serial AVP */ |
55 | | |
56 | | static int serial_avp; |
57 | | |
58 | | |
59 | | |
60 | | int init_serialization(void) |
61 | 0 | { |
62 | 0 | str alias = { SERIAL_AVP_ALIAS, sizeof(SERIAL_AVP_ALIAS)-1 }; |
63 | |
|
64 | 0 | if (parse_avp_spec(&alias, &serial_avp)) { |
65 | 0 | LM_ERR("cannot parse avp spec\n"); |
66 | 0 | return -1; |
67 | 0 | } |
68 | 0 | return 0; |
69 | 0 | } |
70 | | |
71 | 0 | #define seras(p, var, sertype) { \ |
72 | 0 | sertype _tval = 0; \ |
73 | 0 | static_assert(sizeof(var) <= sizeof(_tval), "variable " #var " is too big for " #sertype); \ |
74 | 0 | memcpy(&_tval, (var), sizeof(*(var))); \ |
75 | 0 | memcpy(p, &_tval, sizeof(sertype));} |
76 | | |
77 | 0 | #define unseras(var, p, sertype) { \ |
78 | 0 | sertype _tval; \ |
79 | 0 | memcpy(&_tval, (p), sizeof(sertype)); \ |
80 | 0 | *(var) = (typeof(*(var)))_tval;} |
81 | | |
82 | | /*! \brief |
83 | | * Loads contacts in destination set into "serial_avp" AVP in reverse |
84 | | * priority order and associated each contact with Q_FLAG telling if |
85 | | * contact is the last one in its priority class. Finally, removes |
86 | | * all branches from destination set. |
87 | | */ |
88 | | int serialize_branches(struct sip_msg *msg, int clean_before, int keep_order) |
89 | 0 | { |
90 | 0 | static struct serial_contact contacts[MAX_BRANCHES]; |
91 | 0 | struct msg_branch *branch; |
92 | 0 | int n, last, first, i, prev, bflags; |
93 | 0 | str *ruri; |
94 | 0 | qvalue_t ruri_q; |
95 | 0 | char *p; |
96 | 0 | str enc_info; |
97 | 0 | int_str val; |
98 | 0 | int idx; |
99 | | |
100 | | /* Check if anything needs to be done */ |
101 | 0 | if (get_dset_size() == 0) { |
102 | 0 | LM_DBG("nothing to do - no branches!\n"); |
103 | 0 | return 0; |
104 | 0 | } |
105 | | |
106 | 0 | ruri = GET_RURI(msg); |
107 | 0 | ruri_q = get_ruri_q(msg); |
108 | 0 | bflags = getb0flags(msg); |
109 | |
|
110 | 0 | for (idx = 0; (branch = get_msg_branch(idx)); idx++) { |
111 | 0 | if (branch->q != ruri_q) |
112 | 0 | break; |
113 | 0 | } |
114 | |
|
115 | 0 | if (branch==NULL && !keep_order) { |
116 | 0 | LM_DBG("nothing to do - all same q!\n"); |
117 | 0 | return 0; |
118 | 0 | } |
119 | | |
120 | | /* reset contact array */ |
121 | 0 | n = 0; |
122 | | |
123 | | /* Insert Request-URI to contact list */ |
124 | 0 | enc_info.len = 3 * sizeof(long) |
125 | 0 | + ruri->len + msg->dst_uri.len + msg->path_vec.len + 3; |
126 | 0 | enc_info.s = (char*) pkg_malloc (enc_info.len); |
127 | |
|
128 | 0 | if (!enc_info.s) { |
129 | 0 | LM_ERR("no pkg memory left\n"); |
130 | 0 | goto error; /* nothing to free here */ |
131 | 0 | } |
132 | | |
133 | 0 | memset(enc_info.s, 0, enc_info.len); |
134 | 0 | p = enc_info.s; |
135 | |
|
136 | 0 | LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u>\n", |
137 | 0 | ruri->len, ruri->s, |
138 | 0 | msg->dst_uri.len, msg->dst_uri.s, |
139 | 0 | msg->path_vec.len, msg->path_vec.s, |
140 | 0 | ruri_q, bflags); |
141 | |
|
142 | 0 | seras(p, &msg->force_send_socket, long); |
143 | 0 | p += sizeof(long); |
144 | 0 | seras(p, &bflags, long); |
145 | 0 | p += sizeof(long); |
146 | 0 | seras(p, &ruri_q, long); |
147 | 0 | p += sizeof(long); |
148 | |
|
149 | 0 | memcpy(p , ruri->s, ruri->len); |
150 | 0 | p += ruri->len + 1; |
151 | 0 | memcpy(p, msg->dst_uri.s, msg->dst_uri.len); |
152 | 0 | p += msg->dst_uri.len + 1; |
153 | 0 | memcpy(p, msg->path_vec.s, msg->path_vec.len); |
154 | |
|
155 | 0 | contacts[n].enc_info = enc_info; |
156 | 0 | contacts[n].q = ruri_q; |
157 | 0 | contacts[n].next = -1; |
158 | 0 | last = n; |
159 | 0 | first = n; |
160 | 0 | n++; |
161 | | |
162 | | /* Insert branch URIs to contact list in increasing q order */ |
163 | 0 | for (idx = 0;(branch=get_msg_branch(idx))!=NULL; idx++){ |
164 | |
|
165 | 0 | enc_info.len = 3 * sizeof(long) |
166 | 0 | + branch->uri.len + branch->dst_uri.len + branch->path.len + 3; |
167 | 0 | enc_info.s = (char*) pkg_malloc (enc_info.len); |
168 | |
|
169 | 0 | if (!enc_info.s) { |
170 | 0 | LM_ERR("no pkg memory left\n"); |
171 | 0 | goto error_free; |
172 | 0 | } |
173 | | |
174 | 0 | memset(enc_info.s, 0, enc_info.len); |
175 | 0 | p = enc_info.s; |
176 | |
|
177 | 0 | LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u>\n", |
178 | 0 | branch->uri.len, branch->uri.s, |
179 | 0 | branch->dst_uri.len, branch->dst_uri.s, |
180 | 0 | branch->path.len, branch->path.s, |
181 | 0 | branch->q, branch->bflags); |
182 | |
|
183 | 0 | seras(p, &branch->force_send_socket, long); |
184 | 0 | p += sizeof(long); |
185 | 0 | seras(p, &branch->bflags, long); |
186 | 0 | p += sizeof(long); |
187 | 0 | seras(p, &branch->q, long); |
188 | 0 | p += sizeof(long); |
189 | |
|
190 | 0 | memcpy(p , branch->uri.s, branch->uri.len); |
191 | 0 | p += branch->uri.len + 1; |
192 | 0 | memcpy(p, branch->dst_uri.s, branch->dst_uri.len); |
193 | 0 | p += branch->dst_uri.len + 1; |
194 | 0 | memcpy(p, branch->path.s, branch->path.len); |
195 | |
|
196 | 0 | contacts[n].enc_info = enc_info; |
197 | 0 | contacts[n].q = branch->q; |
198 | |
|
199 | 0 | if (keep_order) { |
200 | 0 | contacts[n].next = first; |
201 | 0 | first = n++; |
202 | 0 | continue; |
203 | 0 | } |
204 | | |
205 | | /* insert based on ascending q values, so add_avp() reverses them */ |
206 | 0 | for (i = first, prev = -1; |
207 | 0 | i != -1 && contacts[i].q < branch->q; |
208 | 0 | prev = i ,i = contacts[i].next); |
209 | |
|
210 | 0 | if (i == -1) { |
211 | | /* append */ |
212 | 0 | last = contacts[last].next = n; |
213 | 0 | contacts[n].next = -1; |
214 | 0 | } else { |
215 | 0 | if (i == first) { |
216 | | /* first element */ |
217 | 0 | contacts[n].next = first; |
218 | 0 | first = n; |
219 | 0 | } else { |
220 | | /* before pos i */ |
221 | 0 | contacts[n].next = contacts[prev].next; |
222 | 0 | contacts[prev].next = n; |
223 | 0 | } |
224 | 0 | } |
225 | |
|
226 | 0 | n++; |
227 | 0 | } |
228 | | |
229 | | /* Assign values for q_flags */ |
230 | 0 | for (i = first; contacts[i].next != -1; i = contacts[i].next) { |
231 | 0 | if (keep_order || contacts[i].q < contacts[contacts[i].next].q) |
232 | 0 | contacts[contacts[i].next].q_flag = Q_FLAG; |
233 | 0 | else |
234 | 0 | contacts[contacts[i].next].q_flag = 0; |
235 | 0 | } |
236 | |
|
237 | 0 | if (clean_before) |
238 | 0 | destroy_avps( 0/*type*/, serial_avp, 1/*all*/); |
239 | | |
240 | | /* Add contacts to "contacts" AVP */ |
241 | 0 | for (i = first; i != -1; i = contacts[i].next) { |
242 | 0 | val.s = contacts[i].enc_info; |
243 | |
|
244 | 0 | if (add_avp( AVP_VAL_STR|contacts[i].q_flag, serial_avp, val)) { |
245 | 0 | LM_ERR("failed to add avp\n"); |
246 | 0 | goto error_free; |
247 | 0 | } |
248 | | |
249 | 0 | pkg_free(contacts[i].enc_info.s); |
250 | 0 | contacts[i].enc_info.s = NULL; |
251 | 0 | } |
252 | | |
253 | | /* Clear all branches */ |
254 | 0 | clear_dset(); |
255 | |
|
256 | 0 | return 0; |
257 | 0 | error_free: |
258 | 0 | for( i=0 ; i<n ; i++) { |
259 | 0 | if (contacts[i].enc_info.s) |
260 | 0 | pkg_free(contacts[i].enc_info.s); |
261 | 0 | } |
262 | 0 | error: |
263 | 0 | return -1; |
264 | 0 | } |
265 | | |
266 | | |
267 | | |
268 | | /*! \brief |
269 | | * Adds to request a destination set that includes all highest priority |
270 | | * class contacts in "serial_avp" AVP. If called from a route block, |
271 | | * rewrites the request uri with first contact and adds the remaining |
272 | | * contacts as branches. If called from failure route block, adds all |
273 | | * contacts as brances. Removes added contacts from "serial_avp" AVP. |
274 | | */ |
275 | | int next_branches( struct sip_msg *msg) |
276 | 0 | { |
277 | 0 | struct msg_branch branch; |
278 | 0 | struct usr_avp *avp, *prev; |
279 | 0 | int_str val; |
280 | 0 | struct socket_info *sock_info; |
281 | 0 | qvalue_t q; |
282 | 0 | str uri, dst_uri, path, path_dst; |
283 | 0 | char *p; |
284 | 0 | unsigned int flags, last_parallel_fork; |
285 | 0 | int rval; |
286 | |
|
287 | 0 | if (route_type != REQUEST_ROUTE && route_type != FAILURE_ROUTE ) { |
288 | | /* unsupported route type */ |
289 | 0 | LM_ERR("called from unsupported route type %d\n", route_type); |
290 | 0 | goto error; |
291 | 0 | } |
292 | | |
293 | | /* Find first avp */ |
294 | 0 | avp = search_first_avp(0, serial_avp, &val, 0); |
295 | |
|
296 | 0 | if (!avp) { |
297 | 0 | LM_DBG("no AVPs -- we are done!\n"); |
298 | 0 | goto error; |
299 | 0 | } |
300 | | |
301 | 0 | if (!val.s.s) { |
302 | 0 | LM_ERR("invalid avp value\n"); |
303 | 0 | goto error; |
304 | 0 | } |
305 | | |
306 | | /* *sock_info, flags, q, uri, 0, dst_uri, 0, path, 0,... */ |
307 | | |
308 | 0 | p = val.s.s; |
309 | 0 | unseras(&sock_info, p, long); |
310 | 0 | p += sizeof(long); |
311 | 0 | unseras(&flags, p, long); |
312 | 0 | p += sizeof(long); |
313 | 0 | unseras(&q, p, long); |
314 | 0 | p += sizeof(long); |
315 | 0 | uri.s = p; |
316 | 0 | uri.len = strlen(p); |
317 | 0 | p += uri.len + 1; |
318 | 0 | dst_uri.s = p; |
319 | 0 | dst_uri.len = strlen(p); |
320 | 0 | p += dst_uri.len + 1; |
321 | 0 | path.s = p; |
322 | 0 | path.len = strlen(p); |
323 | | |
324 | | /* set PATH and DURI */ |
325 | 0 | if (path.s && path.len) { |
326 | 0 | if (get_path_dst_uri(&path, &path_dst) < 0) { |
327 | 0 | LM_ERR("failed to get first hop from Path\n"); |
328 | 0 | goto error1; |
329 | 0 | } |
330 | 0 | if (set_path_vector( msg, &path) < 0) { |
331 | 0 | LM_ERR("failed to set path vector\n"); |
332 | 0 | goto error1; |
333 | 0 | } |
334 | 0 | if (set_dst_uri( msg, &path_dst) < 0) { |
335 | 0 | LM_ERR("failed to set dst_uri of Path\n"); |
336 | 0 | goto error1; |
337 | 0 | } |
338 | 0 | } else { |
339 | 0 | if (set_dst_uri( msg, &dst_uri) < 0) { |
340 | 0 | goto error1; |
341 | 0 | } |
342 | 0 | } |
343 | | |
344 | | /* Set Request-URI */ |
345 | 0 | if ( set_ruri(msg, &uri) == -1 ) |
346 | 0 | goto error1; |
347 | | |
348 | 0 | msg->force_send_socket = sock_info; |
349 | 0 | set_ruri_q( msg, q ); |
350 | 0 | setb0flags( msg, flags ); |
351 | |
|
352 | 0 | LM_DBG("Msg information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", |
353 | 0 | uri.len, uri.s, |
354 | 0 | dst_uri.len, dst_uri.s, |
355 | 0 | path.len, path.s, |
356 | 0 | q, flags, avp->flags); |
357 | |
|
358 | 0 | last_parallel_fork = (avp->flags & Q_FLAG); |
359 | 0 | prev = avp; |
360 | 0 | avp = search_next_avp(avp, &val); |
361 | 0 | destroy_avp(prev); |
362 | |
|
363 | 0 | if (last_parallel_fork) |
364 | 0 | goto done; |
365 | | |
366 | | /* Append branches until out of branches or Q_FLAG is set */ |
367 | 0 | while (avp != NULL) { |
368 | |
|
369 | 0 | if (!val.s.s) { |
370 | 0 | LM_ERR("invalid avp value\n"); |
371 | 0 | goto next_avp; |
372 | 0 | } |
373 | | |
374 | 0 | memset( &branch, 0, sizeof branch); |
375 | 0 | p = val.s.s; |
376 | 0 | unseras(&branch.force_send_socket, p, long); |
377 | 0 | p += sizeof(long); |
378 | 0 | unseras(&branch.bflags, p, long); |
379 | 0 | p += sizeof(long); |
380 | 0 | unseras(&branch.q, p, long); |
381 | 0 | p += sizeof(long); |
382 | 0 | branch.uri.s = p; |
383 | 0 | branch.uri.len = strlen(p); |
384 | 0 | p += strlen(p) + 1; |
385 | 0 | branch.dst_uri.s = p; |
386 | 0 | branch.dst_uri.len = strlen(p); |
387 | 0 | p += strlen(p) + 1; |
388 | 0 | branch.path.s = p; |
389 | 0 | branch.path.len = strlen(p); |
390 | |
|
391 | 0 | LM_DBG("Branch information <%.*s,%.*s,%.*s,%d,%u> (avp flag=%u)\n", |
392 | 0 | branch.uri.len, branch.uri.s, |
393 | 0 | branch.dst_uri.len, branch.dst_uri.s, |
394 | 0 | branch.path.len, branch.path.s, |
395 | 0 | branch.q, branch.bflags, avp->flags); |
396 | | |
397 | |
|
398 | 0 | rval = append_msg_branch(&branch); |
399 | |
|
400 | 0 | if (rval == -1) { |
401 | 0 | LM_ERR("append_branch failed\n"); |
402 | 0 | goto error1; |
403 | 0 | } |
404 | | |
405 | 0 | next_avp: |
406 | 0 | last_parallel_fork = (avp->flags & Q_FLAG); |
407 | 0 | prev = avp; |
408 | 0 | avp = search_next_avp(avp, &val); |
409 | 0 | destroy_avp(prev); |
410 | |
|
411 | 0 | if (last_parallel_fork) |
412 | 0 | goto done; |
413 | 0 | } |
414 | | |
415 | 0 | return 2; |
416 | 0 | done: |
417 | 0 | return avp ? 1 : 2; |
418 | 0 | error1: |
419 | 0 | destroy_avp(avp); |
420 | 0 | error: |
421 | 0 | return -1; |
422 | 0 | } |