Coverage Report

Created: 2025-07-11 06:28

/src/opensips/dset.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2004 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
21
/*!
22
 * \file
23
 * \brief Destination set handling functions
24
 */
25
26
27
#include <string.h>
28
#include "dprint.h"
29
#include "config.h"
30
#include "parser/parser_f.h"
31
#include "parser/msg_parser.h"
32
#include "ut.h"
33
#include "hash_func.h"
34
#include "error.h"
35
#include "context.h"
36
#include "dset.h"
37
#include "mem/mem.h"
38
#include "ip_addr.h"
39
#include "usr_avp.h"
40
41
0
#define CONTACT "Contact: "
42
0
#define CONTACT_LEN (sizeof(CONTACT) - 1)
43
44
0
#define CONTACT_DELIM ", "
45
0
#define CONTACT_DELIM_LEN (sizeof(CONTACT_DELIM) - 1)
46
47
0
#define Q_PARAM ";q="
48
0
#define Q_PARAM_LEN (sizeof(Q_PARAM) - 1)
49
50
0
#define DSET_INCREMENT 4
51
52
53
/* This is an extension of the `msg_branch` struct, bringing the
54
 * buffers to hold the strings
55
 */
56
struct msg_branch_wrap
57
{
58
  struct msg_branch branch;
59
60
  char tag[MAX_URI_SIZE];
61
62
  char uri[MAX_URI_SIZE];
63
64
  char dst_uri[MAX_URI_SIZE];
65
66
  char path[MAX_PATH_SIZE];
67
};
68
69
70
struct dset_ctx
71
{
72
  int enabled;
73
74
  /*! how many of them we currently have */
75
  int nr_branches;
76
77
  /*!
78
   * Where we store URIs of additional transaction branches
79
   * (-1 because of the default branch, #0)
80
   */
81
  struct msg_branch_wrap *branches;
82
83
  /*!
84
   * this is the set of attrs (brnach avps) corresponding to the
85
   * RURI branch (the 0-branch); we do not want to keep them into the
86
   * SIP msg (due to cloning issues), so we store them here (anyhow
87
   * the lifespan of this hook is short, only during request route)
88
   */
89
  struct usr_avp *ruri_attrs;
90
};
91
92
static int dset_ctx_idx = -1;
93
94
#define get_dset_ctx() \
95
0
  (!current_processing_ctx ? NULL : (struct dset_ctx *) \
96
0
    context_get_ptr(CONTEXT_GLOBAL, current_processing_ctx, dset_ctx_idx))
97
98
#define store_dset_ctx(value) \
99
0
  (context_put_ptr( \
100
0
    CONTEXT_GLOBAL, current_processing_ctx, dset_ctx_idx, value))
101
102
103
104
int get_dset_size(void)
105
0
{
106
0
  struct dset_ctx *dsct = get_dset_ctx();
107
108
0
  return !dsct ? 0 : dsct->nr_branches;
109
0
}
110
111
/* empties/frees the content of a dset without free'ing the dset itself */
112
static inline void _empty_branches(struct dset_ctx *dsct)
113
0
{
114
0
  int i;
115
116
0
  for( i = 0 ; i < dsct->nr_branches ; i++ )
117
0
    destroy_avp_list( &dsct->branches[i].branch.attrs );
118
0
  pkg_free( dsct->branches );
119
0
  dsct->branches = NULL;
120
0
}
121
122
/*! Frees a destination set which used to be stored in the global context */
123
static void dset_destroy(void *dsct)
124
0
{
125
  /* emptry all branches */
126
0
  _empty_branches( (struct dset_ctx *)dsct );
127
  /* free attrs/avp for the RURI/0 branch */
128
0
  destroy_avp_list( &((struct dset_ctx *)dsct)->ruri_attrs );
129
0
  pkg_free( dsct );
130
0
}
131
132
133
int init_dset(void)
134
2
{
135
2
  dset_ctx_idx = context_register_ptr(CONTEXT_GLOBAL, dset_destroy);
136
2
  if (dset_ctx_idx < 0)
137
0
    return -1;
138
139
2
  return 0;
140
2
}
141
142
143
/*! \brief Disable/Enables parallel branch usage (read and write)
144
 */
145
void set_dset_state(unsigned char enable)
146
0
{
147
0
  struct dset_ctx *dsct = get_dset_ctx();
148
0
  static unsigned int bk_nr_branches;
149
150
0
  if (!dsct)
151
0
    return;
152
153
0
  if (enable) {
154
    /* enable dset usage */
155
0
    if (dsct->enabled) return; /* already enabled */
156
    /* enable read */
157
0
    dsct->nr_branches = bk_nr_branches;
158
0
    bk_nr_branches = 0;
159
    /* enable write */
160
0
    dsct->enabled = 1;
161
0
  } else {
162
    /* disable dset usage */
163
0
    if (!dsct->enabled) return; /* already disabled */
164
    /* disable read */
165
0
    bk_nr_branches = dsct->nr_branches;
166
0
    dsct->nr_branches = 0;
167
    /* disabel write */
168
0
    dsct->enabled = 0;
169
0
  }
170
0
}
171
172
173
/*! \brief Find the next brand from the destination set
174
 * \return Return the next branch from the dset
175
 * array, 0 is returned if there are no
176
 * more branches
177
 */
178
struct msg_branch* get_msg_branch(unsigned int idx)
179
0
{
180
0
  struct dset_ctx *dsct = get_dset_ctx();
181
182
0
  if (dsct && idx < dsct->nr_branches) {
183
0
    return &dsct->branches[idx].branch;
184
0
  } else {
185
0
    return NULL;
186
0
  }
187
0
}
188
189
190
/*! \brief
191
 * Empty the dset array
192
 */
193
void clear_dset(void)
194
0
{
195
0
  struct dset_ctx *dsct = get_dset_ctx();
196
197
0
  if (dsct) {
198
0
    _empty_branches( dsct );
199
0
    dsct->nr_branches = 0;
200
0
  }
201
0
}
202
203
204
/* copies and fills in a branch_wrap with the values from a msg_branch 
205
 * IMPORTANT: if any attrs are attached the `branch`, they will be moved
206
 * into the dset!!! */
207
static inline int _set_msg_branch(struct msg_branch_wrap *br, 
208
                          struct msg_branch *branch)
209
0
{
210
  /* be sure and clear the attrs from target branch */
211
0
  destroy_avp_list( &br->branch.attrs );
212
213
  /* do full copy, copy the buffers later */
214
0
  br->branch = *branch;
215
216
  /* copy ruri */
217
0
  if (ZSTR(branch->uri) || branch->uri.len > MAX_URI_SIZE - 1) {
218
0
    LM_ERR("too long uri: [%.*s]/%d\n", branch->uri.len, branch->uri.s,
219
0
      branch->uri.len);
220
0
    return -1;
221
0
  }
222
0
  br->branch.uri.s = br->uri;
223
0
  memcpy( br->branch.uri.s, branch->uri.s, branch->uri.len);
224
225
  /* copy the dst_uri */
226
0
  if (!ZSTR(branch->dst_uri)) {
227
0
    if (branch->dst_uri.len > MAX_URI_SIZE - 1) {
228
0
      LM_ERR("too long dst_uri: [%.*s]/%d\n",
229
0
        branch->dst_uri.len, branch->dst_uri.s, branch->dst_uri.len);
230
0
      return -1;
231
0
    }
232
0
    br->branch.dst_uri.s = br->dst_uri;
233
0
    memcpy( br->branch.dst_uri.s, branch->dst_uri.s, branch->dst_uri.len);
234
0
  }
235
236
  /* copy the path string */
237
0
  if (!ZSTR(branch->path)) {
238
0
    if (branch->path.len > MAX_PATH_SIZE - 1) {
239
0
      LM_ERR("too long path: [%.*s]/%d\n",
240
0
        branch->path.len, branch->path.s, branch->path.len);
241
0
      return -1;
242
0
    }
243
0
    br->branch.path.s = br->path;
244
0
    memcpy( br->branch.path.s, branch->path.s, branch->path.len);
245
0
  }
246
0
  return 0;
247
0
}
248
249
250
static inline int _dst_malloc(struct dset_ctx **dsct)
251
0
{
252
0
  *dsct = pkg_malloc(sizeof **dsct);
253
0
  if (*dsct==NULL) {
254
0
    LM_ERR("oom 1\n");
255
0
    return E_OUT_OF_MEM;
256
0
  }
257
0
  memset(*dsct, 0, sizeof **dsct);
258
0
  (*dsct)->enabled = 1;
259
0
  store_dset_ctx(*dsct);
260
0
  return 0;
261
0
}
262
263
/* ! \brief
264
 * Add a new branch to current transaction
265
 */
266
int append_msg_branch(struct msg_branch *branch)
267
0
{
268
0
  int idx;
269
0
  struct msg_branch_wrap *new_br;
270
0
  struct dset_ctx *dsct = get_dset_ctx();
271
272
0
  if (dsct && !dsct->enabled)
273
0
    return -1;
274
275
0
  if (dsct==NULL &&  _dst_malloc(&dsct)<0 )
276
0
    return -1;
277
278
0
  idx = dsct->nr_branches;
279
280
  /* if we have already set up the maximum number
281
   * of branches, don't try new ones
282
   */
283
0
  if (idx == MAX_BRANCHES - 1) {
284
0
    LM_ERR("max nr of branches exceeded\n");
285
0
    ser_error = E_TOO_MANY_BRANCHES;
286
0
    return -1;
287
0
  }
288
289
0
  if (idx % DSET_INCREMENT == 0) {
290
0
    new_br = pkg_realloc(dsct->branches,
291
0
                      (idx + DSET_INCREMENT) * sizeof *dsct->branches);
292
0
    if (!new_br) {
293
0
      LM_ERR("oom 2\n");
294
0
      return E_OUT_OF_MEM;
295
0
    }
296
0
    memset((char *)new_br + idx * sizeof *new_br, 0,
297
0
        DSET_INCREMENT * sizeof *new_br);
298
299
0
    dsct->branches = new_br;
300
0
  }
301
302
0
  if (_set_msg_branch( dsct->branches + idx, branch)<0)
303
0
    return -1;
304
305
0
  dsct->nr_branches++;
306
0
  return 1;
307
0
}
308
309
310
/* ! \brief
311
 * Updates URI of an already appended branch
312
 */
313
int update_msg_branch_uri(unsigned int idx, str *val)
314
0
{
315
0
  struct dset_ctx *dsct = get_dset_ctx();
316
0
  struct msg_branch_wrap *br;
317
318
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches || ZSTRP(val))
319
0
    return -1;
320
321
0
  br = dsct->branches + idx;
322
323
0
  if (val->len > MAX_URI_SIZE - 1) {
324
0
    LM_ERR("too long uri: [%.*s]/%d\n", val->len, val->s, val->len);
325
0
    return -1;
326
0
  }
327
0
  br->branch.uri.s = br->uri; /* internal buffer */
328
0
  br->branch.uri.len = val->len;
329
0
  memcpy( br->branch.uri.s, val->s, val->len);
330
331
0
  return 0;
332
0
}
333
334
335
/* ! \brief
336
 * Updates DST_URI of an already appended branch
337
 */
338
int update_msg_branch_dst_uri(unsigned int idx, str *val)
339
0
{
340
0
  struct dset_ctx *dsct = get_dset_ctx();
341
0
  struct msg_branch_wrap *br;
342
343
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
344
0
    return -1;
345
346
0
  br = dsct->branches + idx;
347
348
0
  if (ZSTRP(val)) {
349
0
    br->branch.dst_uri.s = NULL;
350
0
    br->branch.dst_uri.len = 0;
351
0
  } else {
352
0
    if (val->len > MAX_URI_SIZE - 1) {
353
0
      LM_ERR("too long dst_uri: [%.*s]/%d\n", val->len, val->s,val->len);
354
0
      return -1;
355
0
    }
356
0
    br->branch.dst_uri.s = br->dst_uri; /* internal buffer */
357
0
    br->branch.dst_uri.len = val->len;
358
0
    memcpy( br->branch.dst_uri.s, val->s, val->len);
359
0
  }
360
0
  return 0;
361
0
}
362
363
364
365
/* ! \brief
366
 * Updates PATH of an already appended branch
367
 */
368
int update_msg_branch_path(unsigned int idx, str *val)
369
0
{
370
0
  struct dset_ctx *dsct = get_dset_ctx();
371
0
  struct msg_branch_wrap *br;
372
373
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
374
0
    return -1;
375
376
0
  br = dsct->branches + idx;
377
378
0
  if (ZSTRP(val)) {
379
0
    br->branch.path.s = NULL;
380
0
    br->branch.path.len = 0;
381
0
  } else {
382
0
    if (val->len > MAX_PATH_SIZE - 1) {
383
0
      LM_ERR("too long path: [%.*s]/%d\n", val->len, val->s,val->len);
384
0
      return -1;
385
0
    }
386
0
    br->branch.path.s = br->path; /* internal buffer */
387
0
    br->branch.path.len = val->len;
388
0
    memcpy( br->branch.path.s, val->s, val->len);
389
0
  }
390
0
  return 0;
391
0
}
392
393
394
/* ! \brief
395
 * Updates PATH of an already appended branch
396
 */
397
int update_msg_branch_q(unsigned int idx, int val)
398
0
{
399
0
  struct dset_ctx *dsct = get_dset_ctx();
400
0
  struct msg_branch_wrap *br;
401
402
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
403
0
    return -1;
404
405
0
  br = dsct->branches + idx;
406
407
0
  br->branch.q = val;
408
0
  return 0;
409
0
}
410
411
412
/* ! \brief
413
 * Updates SOCKET of an already appended branch
414
 */
415
int update_msg_branch_socket(unsigned int idx, const struct socket_info* val)
416
0
{
417
0
  struct dset_ctx *dsct = get_dset_ctx();
418
0
  struct msg_branch_wrap *br;
419
420
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
421
0
    return -1;
422
423
0
  br = dsct->branches + idx;
424
425
0
  br->branch.force_send_socket = val;
426
0
  return 0;
427
0
}
428
429
430
/* ! \brief
431
 * Updates SOCKET of an already appended branch
432
 */
433
int update_msg_branch_bflags(unsigned int idx, unsigned int val)
434
0
{
435
0
  struct dset_ctx *dsct = get_dset_ctx();
436
0
  struct msg_branch_wrap *br;
437
438
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
439
0
    return -1;
440
441
0
  br = dsct->branches + idx;
442
443
0
  br->branch.bflags = val;
444
0
  return 0;
445
0
}
446
447
448
#define _post_copy_branch_update(_br)             \
449
0
  do {                                          \
450
0
    (_br)->branch.uri.s = (_br)->uri;         \
451
0
    (_br)->branch.dst_uri.s = (_br)->dst_uri; \
452
0
    (_br)->branch.path.s = (_br)->path;       \
453
0
  } while(0)
454
455
/*! \brief
456
 * Removes a msg branch by index. The whole array gets shifted, so the
457
 * indexes inside may change
458
 */
459
int remove_msg_branch(unsigned int idx)
460
0
{
461
0
  struct dset_ctx *dsct = get_dset_ctx();
462
0
  int i;
463
464
0
  if (!dsct || !dsct->enabled || idx >= dsct->nr_branches)
465
0
    return -1;
466
467
  /* destroy any attrs the branch may have */
468
0
  destroy_avp_list( &dsct->branches[idx].branch.attrs );
469
470
  /* not last branch? */
471
0
  if (idx + 1 != dsct->nr_branches) {
472
0
    memmove( dsct->branches + idx, dsct->branches + idx + 1,
473
0
      (dsct->nr_branches - idx - 1) * sizeof *dsct->branches);
474
    /* update internal links */
475
0
    for ( i=idx ; i<dsct->nr_branches-1 ; i++)
476
0
      _post_copy_branch_update( dsct->branches+i );
477
0
  }
478
479
0
  dsct->nr_branches--;
480
  /* cleanup the slot not used anymore */
481
0
  memset(  dsct->branches + dsct->nr_branches, 0, sizeof *dsct->branches );
482
483
0
  return 0;
484
0
}
485
486
487
/*! \brief
488
 * Create a Contact header field from the dset
489
 * array
490
 */
491
char* print_dset(struct sip_msg* msg, int* len)
492
0
{
493
0
  int cnt, i, idx;
494
0
  unsigned int qlen;
495
0
  char* p, *qbuf;
496
0
  static char *dset = NULL;
497
0
  static unsigned int dset_len = 0;
498
0
  struct msg_branch *br;
499
500
0
  if (msg->new_uri.s) {
501
0
    cnt = 1;
502
0
    *len = msg->new_uri.len+2 /*for <>*/;
503
0
    if (get_ruri_q(msg) != Q_UNSPECIFIED) {
504
0
      *len += Q_PARAM_LEN + len_q(get_ruri_q(msg));
505
0
    }
506
0
  } else {
507
0
    cnt = 0;
508
0
    *len = 0;
509
0
  }
510
511
0
  for( idx=0 ; (br=get_msg_branch(idx))!=NULL ; idx++ ) {
512
0
    cnt++;
513
0
    *len += br->uri.len+2 /*for <>*/ ;
514
0
    if (br->q != Q_UNSPECIFIED) {
515
0
      *len += Q_PARAM_LEN + len_q(br->q);
516
0
    }
517
0
  }
518
519
0
  if (cnt == 0) return 0;
520
521
0
  *len += CONTACT_LEN + CRLF_LEN + (cnt - 1) * CONTACT_DELIM_LEN;
522
523
  /* does the current buffer fit the new dset ? */
524
0
  if (*len + 1 > dset_len) {
525
    /* need to resize */
526
0
    dset = pkg_realloc(dset, *len + 1);
527
0
    if (!dset) {
528
0
      dset_len = 0;
529
0
      LM_ERR("failed to allocate redirect buffer for %d bytes\n", *len + 1);
530
0
      return NULL;
531
0
    }
532
0
    dset_len = *len + 1;
533
0
  }
534
535
0
  memcpy(dset, CONTACT, CONTACT_LEN);
536
0
  p = dset + CONTACT_LEN;
537
0
  if (msg->new_uri.s) {
538
0
    *p++ = '<';
539
0
    memcpy(p, msg->new_uri.s, msg->new_uri.len);
540
0
    p += msg->new_uri.len;
541
0
    *p++ = '>';
542
543
0
    if (get_ruri_q(msg) != Q_UNSPECIFIED) {
544
0
      memcpy(p, Q_PARAM, Q_PARAM_LEN);
545
0
      p += Q_PARAM_LEN;
546
547
0
      qbuf = q2str(get_ruri_q(msg), &qlen);
548
0
      memcpy(p, qbuf, qlen);
549
0
      p += qlen;
550
0
    }
551
0
    i = 1;
552
0
  } else {
553
0
    i = 0;
554
0
  }
555
556
0
  for( idx=0 ; (br=get_msg_branch(idx))!=NULL ; idx++ ) {
557
0
    if (i) {
558
0
      memcpy(p, CONTACT_DELIM, CONTACT_DELIM_LEN);
559
0
      p += CONTACT_DELIM_LEN;
560
0
    }
561
562
0
    *p++ = '<';
563
0
    memcpy(p, br->uri.s, br->uri.len);
564
0
    p += br->uri.len;
565
0
    *p++ = '>';
566
567
0
    if (br->q != Q_UNSPECIFIED) {
568
0
      memcpy(p, Q_PARAM, Q_PARAM_LEN);
569
0
      p += Q_PARAM_LEN;
570
571
0
      qbuf = q2str(br->q, &qlen);
572
0
      memcpy(p, qbuf, qlen);
573
0
      p += qlen;
574
0
    }
575
0
    i++;
576
0
  }
577
578
0
  memcpy(p, CRLF " ", CRLF_LEN + 1);
579
0
  return dset;
580
0
}
581
582
583
/*! \brief moves the uri to destination for all branches and
584
 * all uris are set to given uri */
585
int msg_branch_uri2dset( str *new_uri )
586
0
{
587
0
  struct dset_ctx *dsct = get_dset_ctx();
588
0
  struct msg_branch *branch;
589
0
  unsigned int b;
590
591
  /* no branches have been added yet */
592
0
  if (!dsct)
593
0
    return 0;
594
595
0
  if (new_uri->len+1 > MAX_URI_SIZE) {
596
0
    LM_ERR("new uri too long (%d)\n",new_uri->len);
597
0
    return -1;
598
0
  }
599
600
0
  for (b = 0; b < dsct->nr_branches; b++) {
601
0
    branch = &(dsct->branches[b].branch);
602
    /* move uri to dst */
603
0
    memcpy(branch->dst_uri.s, branch->uri.s, branch->uri.len + 1);
604
0
    branch->dst_uri.len = branch->uri.len;
605
    /* set new uri */
606
0
    memcpy(branch->uri.s, new_uri->s, new_uri->len);
607
0
    branch->uri.len =  new_uri->len;
608
0
    branch->uri.s[new_uri->len] = '\0';
609
0
  }
610
611
0
  return 0;
612
0
}
613
614
615
static inline int _branch_2_msg(struct dset_ctx *dsct,
616
              struct msg_branch_wrap *br,struct sip_msg *msg)
617
0
{
618
0
  if (set_ruri( msg, &br->branch.uri))
619
0
    return -1;
620
621
0
  if (set_dst_uri( msg, &br->branch.dst_uri))
622
0
    return -1;
623
624
0
  if (set_path_vector( msg, &br->branch.path))
625
0
    return -1;
626
627
0
  msg->ruri_q = br->branch.q;
628
0
  msg->force_send_socket = br->branch.force_send_socket;
629
0
  msg->ruri_bflags = br->branch.bflags;
630
631
0
  destroy_avp_list( &dsct->ruri_attrs );
632
0
  dsct->ruri_attrs = clone_avp_list(br->branch.attrs);
633
634
0
  return 0;
635
0
}
636
637
638
static inline int _msg_2_branch(struct dset_ctx *dsct,
639
              struct sip_msg *msg, struct msg_branch_wrap *br)
640
0
{
641
0
  struct msg_branch branch;
642
643
  /* run tests first */
644
0
  memset( &branch, 0, sizeof branch);
645
0
  branch.uri = *GET_RURI(msg);
646
0
  branch.dst_uri = msg->dst_uri;
647
0
  branch.path = msg->path_vec;
648
0
  branch.q = msg->ruri_q;
649
0
  branch.force_send_socket = msg->force_send_socket;
650
0
  branch.bflags = msg->ruri_bflags;
651
0
  branch.attrs = clone_avp_list(dsct->ruri_attrs);
652
  /* the cloned list ^^ will remain attached to the branch */
653
654
0
  if (_set_msg_branch( br, &branch)<0)
655
0
    return -1;
656
657
0
  return 0;
658
0
}
659
660
661
static inline int _copy_branch(struct sip_msg *msg, struct dset_ctx *dsct,
662
                          int src_idx, int dst_idx)
663
0
{
664
0
  struct msg_branch_wrap *brs = dsct->branches;
665
0
  int ret = 0;
666
667
0
  if (dst_idx>=0) {
668
    /* we copy into a branch */
669
0
    if (src_idx>=0) {
670
      /* we copy from a branch */
671
      /* destroy the avps of the dst branch before the bulk copy */
672
0
      destroy_avp_list( &brs[dst_idx].branch.attrs );
673
      /* do the copy */
674
0
      brs[dst_idx] = brs[src_idx];
675
0
      _post_copy_branch_update( brs+dst_idx );
676
      /* clone the list of attrs from src to dst now */
677
0
      brs[dst_idx].branch.attrs =
678
0
        clone_avp_list( brs[src_idx].branch.attrs );
679
0
    } else {
680
      /* we copy from msg */
681
0
      ret = _msg_2_branch( dsct, msg, &brs[dst_idx]);
682
0
    }
683
0
  } else {
684
    /* we copy into msg */
685
0
    if (src_idx>=0) {
686
      /* we copy from a branch */
687
0
      ret = _branch_2_msg( dsct, &brs[src_idx], msg);
688
0
    } else {
689
      /* this should not happen, it is a NOP */
690
0
    }
691
0
  }
692
693
0
  return ret;
694
0
}
695
696
697
int move_msg_branch_to_ruri(int idx, struct sip_msg *msg)
698
0
{
699
0
  struct dset_ctx *dsct = get_dset_ctx();
700
701
  /* no branches have been added yet */
702
0
  if (!dsct) {
703
0
    LM_DBG("no branches found\n");
704
0
    return -1;
705
0
  }
706
707
0
  if (idx >= dsct->nr_branches) {
708
0
    LM_DBG("trying to move inexisting branch idx %d, out of %d\n",
709
0
      idx, dsct->nr_branches);
710
0
    return -1;
711
0
  }
712
713
0
  if (_branch_2_msg( dsct, &dsct->branches[idx], msg)!=0) {
714
0
    LM_ERR("failed to move brnach to RURI\n");
715
0
    return -1;
716
0
  }
717
718
0
  return 0;
719
0
}
720
721
722
int swap_msg_branches(struct sip_msg *msg, int src_idx, int dst_idx)
723
0
{
724
0
  struct dset_ctx *dsct = get_dset_ctx();
725
0
  struct msg_branch_wrap *brs;
726
0
  struct msg_branch_wrap bk;
727
0
  struct usr_avp *bk_attrs;
728
729
0
  if (src_idx==dst_idx)
730
    /* this is a NOP */
731
0
    return 0;
732
733
  /* no branches have been added yet */
734
0
  if (!dsct)
735
0
    return -1;
736
737
0
  if ( (src_idx>0 && src_idx>=dsct->nr_branches)
738
0
  || (dst_idx>0 && dst_idx>=dsct->nr_branches) ) {
739
0
    LM_ERR("overflow in src [%d] or dst [%d] indexes (having %d)\n",
740
0
      src_idx, dst_idx, dsct->nr_branches);
741
0
    return -1;
742
0
  }
743
744
0
  brs = dsct->branches;
745
746
  /* to avoid useless cloning of the attr lists, better detach them
747
   * before doing anything and swap them at the end */
748
749
  /* backup the info from dst branch, so we can write into it */
750
0
  if (dst_idx>=0) {
751
    /* detach the attrs */
752
0
    bk_attrs = brs[dst_idx].branch.attrs;
753
0
    brs[dst_idx].branch.attrs = NULL;
754
    /* backup the dst branch */
755
0
    bk = brs[dst_idx];
756
0
    _post_copy_branch_update( &bk );
757
0
  } else {
758
    /* detach the attrs */
759
0
    bk_attrs = dsct->ruri_attrs;
760
0
    dsct->ruri_attrs = NULL;
761
    /* backup the msg branch */
762
0
    if (_msg_2_branch(dsct, msg, &bk)<0)
763
0
      return -1;
764
0
  }
765
766
  /* copy dst over src */
767
0
  if (_copy_branch( msg, dsct, src_idx, dst_idx)<0)
768
0
    return -1;
769
770
  /* now copy the original dst (from bk) into src */
771
0
  if (src_idx>=0) {
772
    /* copy bk into a branch */
773
0
    brs[src_idx] = bk;
774
0
    _post_copy_branch_update( brs+src_idx );
775
    /* attach the dst list of attrs */
776
0
    brs[src_idx].branch.attrs = bk_attrs;
777
0
  } else {
778
    /* copy bk in msg */
779
0
    if (_branch_2_msg( dsct, &bk, msg)<0)
780
0
      return -1; //we may have an inconsistent msg branch :(
781
    /* attach the dst list of attrs */
782
0
    dsct->ruri_attrs = bk_attrs;
783
0
  }
784
785
0
  return 0;
786
0
}
787
788
789
int move_msg_branch(struct sip_msg *msg, int src_idx, int dst_idx,
790
                              int keep_src)
791
0
{
792
0
  struct dset_ctx *dsct = get_dset_ctx();
793
794
0
  if (src_idx==dst_idx)
795
    /* this is a NOP */
796
0
    return 0;
797
798
  /* no branches have been added yet */
799
0
  if (!dsct)
800
0
    return -1;
801
802
0
  if ( (src_idx>0 && src_idx>=dsct->nr_branches)
803
0
  || (dst_idx>0 && dst_idx>=dsct->nr_branches) ) {
804
0
    LM_ERR("overflow in src [%d] or dst [%d] indexes (having %d)\n",
805
0
      src_idx, dst_idx, dsct->nr_branches);
806
0
    return -1;
807
0
  }
808
809
  /* copy dst over src */
810
0
  if (_copy_branch( msg, dsct, src_idx, dst_idx)<0)
811
0
    return -1;
812
813
0
  if (!keep_src && src_idx>0)
814
0
    remove_msg_branch(src_idx);
815
816
0
  return 0;
817
0
}
818
819
820
/**** Functions to work with the members ****/
821
822
static inline unsigned int* get_ptr_bflags(struct sip_msg *msg,
823
                            unsigned int b_idx)
824
0
{
825
0
  struct dset_ctx *dsct = get_dset_ctx();
826
827
0
  if (!dsct && b_idx != 0)
828
0
    return NULL;
829
830
0
  if (b_idx == 0) {
831
0
    return &getb0flags(msg);
832
0
  } else {
833
0
    if (b_idx - 1 < dsct->nr_branches) {
834
0
      return &dsct->branches[b_idx - 1].branch.bflags;
835
0
    } else {
836
0
      return 0;
837
0
    }
838
0
  }
839
0
}
840
841
int setbflag(struct sip_msg *msg, unsigned int b_idx, unsigned int mask)
842
0
{
843
0
  unsigned int *flags;
844
845
0
  flags = get_ptr_bflags( msg, b_idx );
846
#ifdef EXTRA_DEBUG
847
  LM_DBG("bflags for %p : (%u, %u)\n", msg, mask, *flags);
848
#endif
849
0
  if (flags==0)
850
0
    return -1;
851
852
0
  (*flags) |= mask;
853
0
  return 1;
854
0
}
855
856
857
/*! \brief
858
 * Tests the per branch flags
859
 */
860
int isbflagset(struct sip_msg *msg, unsigned int b_idx, unsigned int mask)
861
0
{
862
0
  unsigned int *flags;
863
864
0
  flags = get_ptr_bflags( msg, b_idx );
865
#ifdef EXTRA_DEBUG
866
  LM_DBG("bflags for %p : (%u, %u)\n", msg, mask, *flags);
867
#endif
868
0
  if (flags==0)
869
0
    return -1;
870
871
0
  return ( (*flags) & mask) ? 1 : -1;
872
0
}
873
874
875
/*! \brief
876
 * Resets the per branch flags
877
 */
878
int resetbflag(struct sip_msg *msg, unsigned int b_idx, unsigned int mask)
879
0
{
880
0
  unsigned int *flags;
881
882
0
  flags = get_ptr_bflags( msg, b_idx );
883
#ifdef EXTRA_DEBUG
884
  LM_DBG("bflags for %p : (%u, %u)\n", msg, mask, *flags);
885
#endif
886
0
  if (flags==0)
887
0
    return -1;
888
889
0
  (*flags) &= ~mask;
890
0
  return 1;
891
0
}
892
893
894
int get_msg_branch_attr(unsigned int b_idx, int name_id,
895
                  unsigned short *flags, int_str *val)
896
0
{
897
0
  struct dset_ctx *dsct = get_dset_ctx();
898
0
  struct usr_avp **attrs;
899
0
  struct usr_avp *avp;
900
0
  struct usr_avp** old_list;
901
902
0
  if (!dsct)
903
0
    return -1;
904
905
0
  if (b_idx==0)
906
0
    attrs = &(dsct->ruri_attrs);
907
0
  else if (b_idx-1 < get_dset_size())
908
0
    attrs = &dsct->branches[b_idx - 1].branch.attrs;
909
0
  else {
910
0
    LM_DBG("index %d out of rante (available branches %d)\n",
911
0
      b_idx, get_dset_size() );
912
0
    return -1;
913
0
  }
914
915
0
  LM_DBG("getting attr [%d] on branch %d/ptr=%p\n",name_id, b_idx, attrs);
916
917
  /* operate on the list of ATTRS/AVPS of the branch */
918
0
  old_list = set_avp_list( attrs );
919
920
0
  avp = search_first_avp(0, name_id, val, 0);
921
922
0
  set_avp_list( old_list );
923
924
0
  if (avp)
925
0
    *flags = avp->flags;
926
0
  else
927
0
    *flags = AVP_VAL_NULL;
928
929
0
  return avp ? 1 : -1 ;
930
0
}
931
932
933
int set_msg_branch_attr(unsigned int b_idx, int name_id,
934
                    unsigned short flags, int_str val)
935
0
{
936
0
  struct dset_ctx *dsct = get_dset_ctx();
937
0
  struct usr_avp **attrs;
938
0
  struct usr_avp *avp;
939
0
  struct usr_avp** old_list;
940
941
  /* if we have to set an ATTR for RURI branch, we need to have the dset
942
   * allocated (as the attr holder is there) */
943
0
  if (dsct==NULL && (b_idx!=0 || (b_idx==0 && _dst_malloc(&dsct)<0)) )
944
0
    return -1;
945
946
0
  if (b_idx==0)
947
0
    attrs = &(dsct->ruri_attrs);
948
0
  else if (b_idx-1 < get_dset_size())
949
0
    attrs = &dsct->branches[b_idx - 1].branch.attrs;
950
0
  else {
951
0
    LM_DBG("index %d out of rante (available branches %d)\n",
952
0
      b_idx, get_dset_size() );
953
0
    return -1;
954
0
  }
955
956
0
  LM_DBG("setting attr [%d] on branch %d/ptr=%p\n",name_id, b_idx, attrs);
957
958
  /* operate on the list of ATTRS/AVPS of the branch */
959
0
  old_list = set_avp_list( attrs );
960
961
0
  if ( (avp=search_first_avp( 0, name_id, NULL, 0))!=NULL )
962
0
    destroy_avp(avp);
963
964
0
  if ( !(flags&AVP_VAL_NULL) )
965
0
    add_avp( flags, name_id, val);
966
967
0
  set_avp_list( old_list );
968
969
0
  return 1;
970
0
}
971
972
973
struct usr_avp **ruri_branch_attrs_head(void)
974
0
{
975
0
  struct dset_ctx *dsct = get_dset_ctx();
976
977
0
  if (!dsct)
978
0
    return NULL;
979
980
0
  return &dsct->ruri_attrs;
981
0
}