Coverage Report

Created: 2025-07-18 06:32

/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
}