Coverage Report

Created: 2025-07-11 06:28

/src/opensips/action.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2010-2014 OpenSIPS Solutions
3
 * Copyright (C) 2005-2006 Voice Sistem S.R.L.
4
 * Copyright (C) 2001-2003 FhG Fokus
5
 *
6
 * This file is part of opensips, a free SIP server.
7
 *
8
 * opensips is free software; you can redistribute it and/or modify
9
 * it under the terms of the GNU General Public License as published by
10
 * the Free Software Foundation; either version 2 of the License, or
11
 * (at your option) any later version
12
 *
13
 * opensips is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
21
 *
22
 * History:
23
 * ---------
24
 *  2003-02-28  scratchpad compatibility abandoned (jiri)
25
 *  2003-01-29  removed scratchpad (jiri)
26
 *  2003-03-19  fixed set* len calculation bug & simplified a little the code
27
 *              (should be a little faster now) (andrei)
28
 *              replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
29
 *  2003-04-01  Added support for loose routing in forward (janakj)
30
 *  2003-04-12  FORCE_RPORT_T added (andrei)
31
 *  2003-04-22  strip_tail added (jiri)
32
 *  2003-10-02  added SET_ADV_ADDR_T & SET_ADV_PORT_T (andrei)
33
 *  2003-10-29  added FORCE_TCP_ALIAS_T (andrei)
34
 *  2004-11-30  added FORCE_SEND_SOCKET_T (andrei)
35
 *  2005-11-29  added serialize_branches and next_branches (bogdan)
36
 *  2006-03-02  MODULE_T action points to a cmd_export_t struct instead to
37
 *               a function address - more info is accessible (bogdan)
38
 *  2006-05-22  forward(_udp,_tcp,_tls) and send(_tcp) merged in forward() and
39
 *               send() (bogdan)
40
 *  2006-12-22  functions for script and branch flags added (bogdan)
41
 */
42
43
/*!
44
 * \file
45
 * \brief OpenSIPS Generic functions
46
 */
47
48
#include "action.h"
49
#include "config.h"
50
#include "error.h"
51
#include "dprint.h"
52
#include "route.h"
53
#include "parser/msg_parser.h"
54
#include "ut.h"
55
#include "sr_module.h"
56
#include "mem/mem.h"
57
#include "errinfo.h"
58
#include "msg_translator.h"
59
#include "mod_fix.h"
60
#include "script_var.h"
61
#include "xlog.h"
62
#include "cfg_pp.h"
63
64
#include <string.h>
65
66
#ifdef DEBUG_DMALLOC
67
#include <dmalloc.h>
68
#endif
69
70
int action_flags = 0;
71
int return_code  = 0;
72
int max_while_loops = 10000;
73
74
/* script tracing options  */
75
int use_script_trace = 0;
76
int script_trace_log_level = L_ALERT;
77
char *script_trace_info = NULL;
78
pv_elem_t script_trace_elem;
79
80
extern err_info_t _oser_err_info;
81
82
action_time longest_action[LONGEST_ACTION_SIZE];
83
int min_action_time=0;
84
85
struct route_params_level {
86
  void *params;
87
  void *extra; /* extra params used */
88
  param_getf_t get_param;
89
};
90
static struct route_params_level route_params[ROUTE_MAX_REC_LEV];
91
static int route_rec_level = -1;
92
93
/* the current stack of route names (first route name is at index 0) */
94
char *route_stack[ROUTE_MAX_REC_LEV + 1];
95
96
/* the virtual start of the stack; typically 0, but may get temporarily bumped
97
 * with each added nesting level of script route callback execution
98
 * (e.g. due to logic similar to dlg_on_hangup(), followed by a SIP BYE) */
99
int route_stack_start;
100
101
/* the total size of the stack, counting from index 0 */
102
int route_stack_size;
103
104
int curr_action_line;
105
char *curr_action_file;
106
107
static int for_each_handler(struct sip_msg *msg, struct action *a);
108
static int route_param_get(struct sip_msg *msg,  pv_param_t *ip,
109
    pv_value_t *res, void *params, void *extra);
110
111
112
/* run actions from a route */
113
/* returns: 0, or 1 on success, <0 on error */
114
/* (0 if drop or break encountered, 1 if not ) */
115
static inline int run_actions(struct action* a, struct sip_msg* msg)
116
0
{
117
0
  int ret, _, ret_lvl;
118
0
  str top_route;
119
120
0
  if (route_stack_size > ROUTE_MAX_REC_LEV) {
121
0
    get_top_route_type(&top_route, &_);
122
0
    LM_ERR("route recursion limit reached, giving up! (nested routes: %d, "
123
0
               "first: '%.*s', last: '%s')!\n", route_stack_size,
124
0
            top_route.len, top_route.s, route_stack[ROUTE_MAX_REC_LEV]);
125
0
    ret=E_UNSPEC;
126
0
    goto error;
127
0
  }
128
129
0
  if (a==0){
130
0
    LM_WARN("null action list (route stack size: %d)\n",
131
0
            route_stack_size);
132
0
    ret=1;
133
0
    goto error;
134
0
  }
135
136
0
  ret_lvl=script_return_push();
137
138
0
  ret=run_action_list(a, msg);
139
140
  /* if 'return', reset the flag */
141
0
  if(action_flags&ACT_FL_RETURN)
142
0
    action_flags &= ~ACT_FL_RETURN;
143
144
0
  script_return_pop(ret_lvl);
145
146
0
  return ret;
147
148
0
error:
149
0
  return ret;
150
0
}
151
152
153
int _run_actions(struct action *a, struct sip_msg *msg)
154
0
{
155
0
  return run_actions(a, msg);
156
0
}
157
158
159
int inside_error_route;
160
void run_error_route(struct sip_msg* msg, int init_route_stack)
161
0
{
162
0
  int old_route;
163
164
0
  LM_DBG("triggering\n");
165
0
  inside_error_route = 1;
166
167
0
  if (init_route_stack) {
168
0
    swap_route_type(old_route, ERROR_ROUTE);
169
170
0
    route_stack[0] = NULL;
171
0
    route_stack_start = 0;
172
0
    route_stack_size = 1;
173
174
0
    run_actions(sroutes->error.a, msg);
175
0
    set_route_type(old_route);
176
0
  } else {
177
0
    route_params_push_level("!error_route", NULL, 0, route_param_get);
178
0
    run_actions(sroutes->error.a, msg);
179
0
    route_params_pop_level();
180
0
  }
181
182
  /* reset error info */
183
0
  init_err_info();
184
0
  inside_error_route = 0;
185
0
}
186
187
188
/* run a list of actions */
189
int run_action_list(struct action* a, struct sip_msg* msg)
190
0
{
191
0
  int ret=E_UNSPEC;
192
0
  struct action* t;
193
0
  for (t=a; t!=0; t=t->next){
194
0
    ret=do_action(t, msg);
195
    /* if action returns 0, then stop processing the script */
196
0
    if(ret==0)
197
0
      action_flags |= ACT_FL_EXIT;
198
199
    /* check for errors */
200
0
    if (_oser_err_info.eclass!=0 && sroutes->error.a!=NULL &&
201
0
    (route_type&(ONREPLY_ROUTE|LOCAL_ROUTE))==0 && !inside_error_route)
202
0
      run_error_route(msg, 0);
203
204
    /* continue or not ? */
205
0
    if (action_flags & (ACT_FL_RETURN | ACT_FL_EXIT | ACT_FL_BREAK))
206
0
      break;
207
0
  }
208
0
  return ret;
209
0
}
210
211
int run_top_route(struct script_route sr, struct sip_msg* msg)
212
0
{
213
0
  static int recursing;
214
215
0
  int bk_action_flags, route_stack_start_bkp = -1, route_stack_size_bkp;
216
0
  int ret;
217
0
  context_p ctx = NULL;
218
219
0
  bk_action_flags = action_flags;
220
221
0
  action_flags = 0;
222
0
  init_err_info();
223
224
0
  if (current_processing_ctx==NULL) {
225
0
    if ( (ctx=context_alloc(CONTEXT_GLOBAL))==NULL) {
226
0
      LM_ERR("failed to allocated new global context\n");
227
0
      return -1;
228
0
    }
229
0
    memset( ctx, 0, context_size(CONTEXT_GLOBAL));
230
0
    set_global_context(ctx);
231
0
  }
232
233
  /* the recursion support allows run_top_route() to be freely called from
234
   * other modules (e.g. dialog) in order to provide contextless script
235
   * callbacks using routes, without losing the original route stack */
236
0
  if (recursing) {
237
0
    route_stack_start_bkp = route_stack_start;
238
0
    route_stack_size_bkp = route_stack_size;
239
0
    route_stack_start = route_stack_size;
240
0
    route_stack_size += 1;
241
0
  } else {
242
0
    route_stack_start = 0;
243
0
    route_stack_size = 1;
244
0
    recursing = 1;
245
0
  }
246
247
0
  if (route_type & (ERROR_ROUTE|LOCAL_ROUTE|STARTUP_ROUTE) ||
248
0
       (route_type &
249
0
          (REQUEST_ROUTE|ONREPLY_ROUTE) && !strcmp(sr.name, "0")))
250
0
    route_stack[route_stack_start] = NULL;
251
0
  else
252
0
    route_stack[route_stack_start] = sr.name;
253
254
0
  run_actions(sr.a, msg);
255
0
  ret = action_flags;
256
257
0
  if (route_stack_start_bkp != -1) {
258
0
    route_stack_size = route_stack_size_bkp;
259
0
    route_stack_start = route_stack_start_bkp;
260
0
  } else {
261
0
    recursing = 0;
262
0
  }
263
264
0
  action_flags = bk_action_flags;
265
  /* reset script tracing */
266
0
  use_script_trace = 0;
267
268
0
  if (ctx && current_processing_ctx) {
269
0
    context_destroy(CONTEXT_GLOBAL, ctx);
270
0
    context_free(ctx);
271
0
    set_global_context(NULL);
272
0
  }
273
274
0
  return ret;
275
0
}
276
277
278
/* execute assignment operation */
279
int do_assign(struct sip_msg* msg, struct action* a)
280
0
{
281
0
  str st;
282
0
  int ret;
283
0
  pv_value_t lval, val;
284
0
  pv_spec_p dspec;
285
286
0
  dspec = (pv_spec_p)a->elem[0].u.data;
287
0
  if(!pv_is_w(dspec))
288
0
  {
289
0
    LM_ERR("read only PV in left expression\n");
290
0
    goto error;
291
0
  }
292
293
0
  memset(&val, 0, sizeof(pv_value_t));
294
0
  if(a->elem[1].type != NULLV_ST)
295
0
  {
296
0
    ret = eval_expr((struct expr*)a->elem[1].u.data, msg, &val);
297
0
    if(ret < 0 || !(val.flags & (PV_VAL_STR | PV_VAL_INT | PV_VAL_NULL)))
298
0
    {
299
0
      LM_WARN("no value in right expression at %s:%d\n",
300
0
        a->file, a->line);
301
0
      goto error2;
302
0
    }
303
0
  }
304
305
0
  switch (a->type) {
306
0
  case EQ_T:
307
0
  case COLONEQ_T:
308
0
    break;
309
0
  case PLUSEQ_T:
310
0
  case MINUSEQ_T:
311
0
  case DIVEQ_T:
312
0
  case MULTEQ_T:
313
0
  case MODULOEQ_T:
314
0
  case BANDEQ_T:
315
0
  case BOREQ_T:
316
0
  case BXOREQ_T:
317
0
    if (pv_get_spec_value(msg, dspec, &lval) != 0) {
318
0
      LM_ERR("failed to get left-hand side value\n");
319
0
      goto error;
320
0
    }
321
322
0
    if (lval.flags & PV_VAL_NULL || val.flags & PV_VAL_NULL) {
323
0
      LM_ERR("NULL value(s) in complex assignment expressions "
324
0
               "(+=, -=, etc.)\n");
325
0
      goto error;
326
0
    }
327
328
    /* both include STR versions and neither is primarily an INT */
329
0
    if ((lval.flags & PV_VAL_STR) && (val.flags & PV_VAL_STR) &&
330
0
      !(lval.flags & PV_TYPE_INT) && !(val.flags & PV_TYPE_INT)) {
331
0
      val.ri = 0;
332
333
0
      if (a->type != PLUSEQ_T)
334
0
        goto bad_operands;
335
336
0
      if (!(val.flags & PV_VAL_PKG)) {
337
0
        st = val.rs;
338
0
        val.rs.s = pkg_malloc(val.rs.len + lval.rs.len + 1);
339
0
        if (!val.rs.s) {
340
0
          val.rs.s = st.s;
341
0
          LM_ERR("oom 1\n");
342
0
          goto error;
343
0
        }
344
345
0
        memcpy(val.rs.s, lval.rs.s, lval.rs.len);
346
0
        memcpy(val.rs.s + lval.rs.len, st.s, st.len);
347
0
        val.rs.len += lval.rs.len;
348
0
        val.rs.s[val.rs.len] = '\0';
349
0
        val.flags |= PV_VAL_PKG;
350
351
0
        if (val.flags & PV_VAL_SHM) {
352
0
          val.flags &= ~PV_VAL_SHM;
353
0
          shm_free(st.s);
354
0
        }
355
0
      } else {
356
0
        st.len = val.rs.len;
357
0
        if (pkg_str_extend(&val.rs, val.rs.len + lval.rs.len + 1) != 0) {
358
0
          LM_ERR("oom 2\n");
359
0
          goto error;
360
0
        }
361
0
        val.rs.len--;
362
0
        memmove(val.rs.s + lval.rs.len, val.rs.s, st.len);
363
0
        memcpy(val.rs.s, lval.rs.s, lval.rs.len);
364
0
        val.rs.s[val.rs.len] = '\0';
365
0
      }
366
0
    } else if ((lval.flags & PV_VAL_INT) && (val.flags & PV_VAL_INT)) {
367
0
      if (val.flags & PV_VAL_STR)
368
0
        val.flags &= ~PV_VAL_STR;
369
0
      switch (a->type) {
370
0
      case PLUSEQ_T:
371
0
        val.ri = lval.ri + val.ri;
372
0
        break;
373
0
      case MINUSEQ_T:
374
0
        val.ri = lval.ri - val.ri;
375
0
        break;
376
0
      case DIVEQ_T:
377
0
        val.ri = lval.ri / val.ri;
378
0
        break;
379
0
      case MULTEQ_T:
380
0
        val.ri = lval.ri * val.ri;
381
0
        break;
382
0
      case MODULOEQ_T:
383
0
        val.ri = lval.ri % val.ri;
384
0
        break;
385
0
      case BANDEQ_T:
386
0
        val.ri = lval.ri & val.ri;
387
0
        break;
388
0
      case BOREQ_T:
389
0
        val.ri = lval.ri | val.ri;
390
0
        break;
391
0
      case BXOREQ_T:
392
0
        val.ri = lval.ri ^ val.ri;
393
0
        break;
394
0
      }
395
0
    } else {
396
0
      goto bad_operands;
397
0
    }
398
0
    break;
399
0
  default:
400
0
    LM_ALERT("BUG -> unknown op type %d\n", a->type);
401
0
    goto error;
402
0
  }
403
404
0
  script_trace("assign",
405
0
    (unsigned char)a->type == EQ_T      ? "equal" :
406
0
    (unsigned char)a->type == COLONEQ_T ? "colon-eq" :
407
0
    (unsigned char)a->type == PLUSEQ_T  ? "plus-eq" :
408
0
    (unsigned char)a->type == MINUSEQ_T ? "minus-eq" :
409
0
    (unsigned char)a->type == DIVEQ_T   ? "div-eq" :
410
0
    (unsigned char)a->type == MULTEQ_T  ? "mult-eq" :
411
0
    (unsigned char)a->type == MODULOEQ_T? "modulo-eq" :
412
0
    (unsigned char)a->type == BANDEQ_T  ? "b-and-eq" :
413
0
    (unsigned char)a->type == BOREQ_T   ? "b-or-eq":"b-xor-eq",
414
0
    msg, a->file, a->line);
415
416
0
  if(a->elem[1].type == NULLV_ST || (val.flags & PV_VAL_NULL))
417
0
  {
418
0
    if(pv_set_value(msg, dspec, (int)a->type, 0)<0)
419
0
    {
420
0
      LM_ERR("setting PV failed\n");
421
0
      goto error;
422
0
    }
423
0
  } else {
424
0
    if(pv_set_value(msg, dspec, (int)a->type, &val)<0)
425
0
    {
426
0
      LM_ERR("setting PV failed\n");
427
0
      goto error;
428
0
    }
429
0
  }
430
431
0
  pv_value_destroy(&val);
432
0
  return 1;
433
434
0
bad_operands:
435
0
  LM_ERR("unsupported operand type(s) for %s: %s and %s\n",
436
0
         assignop_str(a->type),
437
0
         lval.flags & PV_VAL_STR ? "string" : "int",
438
0
         val.flags & PV_VAL_STR ? "string" : "int");
439
0
  pv_value_destroy(&val);
440
0
  return -1;
441
442
0
error:
443
0
  LM_ERR("error at %s:%d\n", a->file, a->line);
444
0
error2:
445
0
  pv_value_destroy(&val);
446
0
  return -1;
447
0
}
448
449
static pv_value_t *route_params_expand(struct sip_msg *msg,
450
  void *params, int params_no)
451
0
{
452
0
  str tmp;
453
0
  int index;
454
0
  pv_value_t *route_vals, *res;
455
0
  action_elem_p actions = (action_elem_p)params;
456
457
0
  route_vals = pkg_malloc(params_no * sizeof(*route_vals));
458
0
  if (!route_vals) {
459
0
    LM_ERR("oom\n");
460
0
    return NULL;
461
0
  }
462
0
  memset(route_vals, 0, params_no * sizeof(*route_vals));
463
464
0
  for (index = 0; index < params_no; index++) {
465
0
    res = &route_vals[index];
466
0
    switch (actions[index].type)
467
0
    {
468
0
      case STRING_ST:
469
0
        res->rs.s = actions[index].u.string;
470
0
        res->rs.len = strlen(res->rs.s);
471
0
        res->flags = PV_VAL_STR;
472
0
        break;
473
474
0
      case NUMBER_ST:
475
0
        res->ri = actions[index].u.number;
476
0
        res->flags = PV_VAL_INT|PV_TYPE_INT;
477
0
        tmp.s = sint2str(res->ri, &tmp.len);
478
0
        if (pkg_str_dup(&res->rs, &tmp) == 0)
479
0
          res->flags |= PV_VAL_STR|PV_VAL_PKG;
480
0
        else
481
0
          LM_ERR("cannot duplicate param value\n");
482
0
        break;
483
484
0
      case SCRIPTVAR_ST:
485
0
        if(pv_get_spec_value(msg, (pv_spec_p)actions[index].u.data, res)==0)
486
0
        {
487
0
          if (pvv_is_str(res)) {
488
            /* but we need to duplicate the string */
489
0
            if (pkg_str_dup(&tmp, &res->rs) == 0) {
490
0
              res->rs.s = tmp.s;
491
0
              res->flags |= PV_VAL_PKG;
492
0
              break;
493
0
            } else {
494
0
              LM_ERR("cannot duplicate param value\n");
495
0
            }
496
0
          } else {
497
0
            break;
498
0
          }
499
0
        } else {
500
0
          LM_ERR("cannot get spec value\n");
501
0
        }
502
        /* fallback */
503
504
0
      default:
505
0
        LM_ALERT("BUG: invalid parameter type %d\n",
506
0
            actions[index].type);
507
        /* fallback */
508
0
      case NULLV_ST:
509
0
        res->rs.s = NULL;
510
0
        res->rs.len = res->ri = 0;
511
0
        res->flags = PV_VAL_NULL;
512
0
        break;
513
0
    }
514
0
  }
515
0
  return route_vals;
516
0
}
517
518
static void route_params_release(pv_value_t *params, int params_no)
519
0
{
520
0
  int p;
521
0
  for (p = 0; p < params_no; p++) {
522
0
    if (params[p].flags & PV_VAL_PKG)
523
0
      pkg_free(params[p].rs.s);
524
0
  }
525
0
  pkg_free(params);
526
0
}
527
528
529
/* function used to get parameter from a route scope */
530
static int route_param_get(struct sip_msg *msg,  pv_param_t *ip,
531
    pv_value_t *res, void *_params, void *_extra)
532
0
{
533
0
  int index;
534
0
  pv_value_t tv;
535
0
  pv_value_t *params = (pv_value_t *)_params;
536
0
  int params_no = (int)(unsigned long)_extra;
537
538
0
  if (params_no <= 0) {
539
0
    LM_DBG("route without parameters\n");
540
0
    return pv_get_null(msg, ip, res);
541
0
  }
542
543
0
  if(ip->pvn.type==PV_NAME_INTSTR)
544
0
  {
545
0
    if (ip->pvn.u.isname.type != 0)
546
0
    {
547
0
      LM_ERR("route $param variable accepts only integer indexes\n");
548
0
      return -1;
549
0
    }
550
0
    index = ip->pvn.u.isname.name.n;
551
0
  } else
552
0
  {
553
    /* pvar -> it might be another $param variable! */
554
0
    route_rec_level--;
555
0
    if(pv_get_spec_value(msg, (pv_spec_p)(ip->pvn.u.dname), &tv)!=0)
556
0
    {
557
0
      LM_ERR("cannot get spec value\n");
558
0
      route_rec_level++;
559
0
      return -1;
560
0
    }
561
0
    route_rec_level++;
562
563
0
    if(tv.flags&PV_VAL_NULL || tv.flags&PV_VAL_EMPTY)
564
0
    {
565
0
      LM_ERR("null or empty name\n");
566
0
      return -1;
567
0
    }
568
0
    if (!(tv.flags&PV_VAL_INT) || str2int(&tv.rs,(unsigned int*)&index) < 0)
569
0
    {
570
0
      LM_ERR("invalid index <%.*s>\n", tv.rs.len, tv.rs.s);
571
0
      return -1;
572
0
    }
573
0
  }
574
575
0
  if (!params)
576
0
  {
577
0
    LM_DBG("no parameter specified for this route\n");
578
0
    return pv_get_null(msg, ip, res);
579
0
  }
580
581
0
  if (index < 1 || index > params_no)
582
0
  {
583
0
    LM_DBG("no such parameter index %d\n", index);
584
0
    return pv_get_null(msg, ip, res);
585
0
  }
586
587
  /* the parameters start at 0, whereas the index starts from 1 */
588
0
  index--;
589
0
  *res = params[index];
590
0
  res->flags &= ~PV_VAL_PKG; /* not interested in this flag */
591
592
0
  return 0;
593
0
}
594
595
#define should_skip_updating(action_type) \
596
0
  (action_type == IF_T || action_type == ROUTE_T || \
597
0
   action_type == WHILE_T || action_type == FOR_EACH_T)
598
599
0
#define update_longest_action(a) do { \
600
0
    if (execmsgthreshold && !should_skip_updating((unsigned char)(a)->type)) { \
601
0
      end_time = get_time_diff(&start); \
602
0
      if (end_time > min_action_time) { \
603
0
        for (i=0;i<LONGEST_ACTION_SIZE;i++) { \
604
0
          if (longest_action[i].a_time < end_time) { \
605
0
            memmove(longest_action+i+1,longest_action+i,  \
606
0
                (LONGEST_ACTION_SIZE-i-1)*sizeof(action_time)); \
607
0
            longest_action[i].a_time=end_time;  \
608
0
            longest_action[i].a = a;  \
609
0
            min_action_time = longest_action[LONGEST_ACTION_SIZE-1].a_time; \
610
0
            break;  \
611
0
          } \
612
0
        } \
613
0
      } \
614
0
    } \
615
0
  } while(0)
616
617
/* ret= 0! if action -> end of list(e.g DROP),
618
      > 0 to continue processing next actions
619
   and <0 on error */
620
int do_action(struct action* a, struct sip_msg* msg)
621
0
{
622
0
  int ret;
623
0
  int v;
624
0
  int i;
625
0
  int len;
626
0
  int cmatch;
627
0
  struct action *aitem;
628
0
  struct action *adefault;
629
0
  pv_spec_t *spec;
630
0
  pv_value_t val;
631
0
  struct timeval start;
632
0
  int end_time;
633
0
  const cmd_export_t *cmd = NULL;
634
0
  const acmd_export_t *acmd;
635
0
  void* cmdp[MAX_CMD_PARAMS];
636
0
  pv_value_t tmp_vals[MAX_CMD_PARAMS];
637
0
  pv_value_t *route_p;
638
0
  str sval;
639
640
  /* reset the value of error to E_UNSPEC so avoid unknowledgable
641
     functions to return with error (status<0) and not setting it
642
     leaving there previous error; cache the previous value though
643
     for functions which want to process it */
644
0
  prev_ser_error=ser_error;
645
0
  ser_error=E_UNSPEC;
646
647
0
  start_expire_timer(start,execmsgthreshold);
648
649
0
  curr_action_line = a->line;
650
0
  curr_action_file = a->file;
651
652
0
  ret=E_BUG;
653
0
  switch ((unsigned char)a->type){
654
0
    case ASSERT_T:
655
0
        if (enable_asserts) {
656
          /* if null expr => ignore if? */
657
0
          if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
658
0
            v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
659
660
0
            ret=1;  /*default is continue */
661
662
0
            if (v<=0) {
663
0
              ret=0;
664
665
0
              if (a->elem[1].u.string)
666
0
                LM_CRIT("ASSERTION FAILED (%s) at %s:%d\n",
667
0
                        a->elem[1].u.string, a->file, a->line);
668
0
              else
669
0
                LM_CRIT("ASSERTION FAILED at %s:%d\n",
670
0
                        a->file, a->line);
671
672
0
              if (abort_on_assert) {
673
0
                abort();
674
0
              } else {
675
0
                set_err_info(OSER_EC_ASSERT, OSER_EL_CRITIC, "assertion failed");
676
0
                set_err_reply(500, "server error");
677
678
0
                run_error_route(msg, 0);
679
0
              }
680
0
            }
681
0
          }
682
0
        }
683
0
      break;
684
0
    case DROP_T:
685
0
        script_trace("core", "drop", msg, a->file, a->line) ;
686
0
        action_flags |= ACT_FL_DROP|ACT_FL_EXIT;
687
0
      break;
688
0
    case EXIT_T:
689
0
        script_trace("core", "exit", msg, a->file, a->line) ;
690
0
        ret=0;
691
0
        action_flags |= ACT_FL_EXIT;
692
0
      break;
693
0
    case RETURN_T:
694
0
        if (a->elem[1].type == EXPR_ST)
695
0
          script_return_set(msg, a->elem[1].u.data);
696
0
        else
697
0
          script_return_set(msg, NULL);
698
0
        script_trace("core", "return", msg, a->file, a->line) ;
699
0
        if (a->elem[0].type == SCRIPTVAR_ST)
700
0
        {
701
0
          spec = (pv_spec_t*)a->elem[0].u.data;
702
0
          if(pv_get_spec_value(msg, spec, &val)!=0
703
0
            || (val.flags&PV_VAL_NULL))
704
0
          {
705
0
            ret=-1;
706
0
          } else {
707
0
            if(!(val.flags&PV_VAL_INT))
708
0
              ret = 1;
709
0
            else
710
0
              ret = val.ri;
711
0
          }
712
0
          pv_value_destroy(&val);
713
0
        } else {
714
0
          ret=a->elem[0].u.number;
715
0
        }
716
0
        action_flags |= ACT_FL_RETURN;
717
0
      break;
718
0
    case LOG_T:
719
0
      script_trace("core", "log", msg, a->file, a->line) ;
720
0
      if ((a->elem[0].type!=NUMBER_ST)|(a->elem[1].type!=STRING_ST)){
721
0
        LM_ALERT("BUG in log() types %d, %d\n",
722
0
            a->elem[0].type, a->elem[1].type);
723
0
        ret=E_BUG;
724
0
        break;
725
0
      }
726
0
      LM_GEN1(a->elem[0].u.number, "%s", a->elem[1].u.string);
727
0
      ret=1;
728
0
      break;
729
0
    case LEN_GT_T:
730
0
      script_trace("core", "len_gt", msg, a->file, a->line) ;
731
0
      if (a->elem[0].type!=NUMBER_ST) {
732
0
        LM_ALERT("BUG in len_gt type %d\n",
733
0
          a->elem[0].type );
734
0
        ret=E_BUG;
735
0
        break;
736
0
      }
737
0
      ret = (msg->len >= (unsigned int)a->elem[0].u.number) ? 1 : -1;
738
0
      break;
739
0
    case ERROR_T:
740
0
      script_trace("core", "error", msg, a->file, a->line) ;
741
0
      if ((a->elem[0].type!=STRING_ST)|(a->elem[1].type!=STRING_ST)){
742
0
        LM_ALERT("BUG in error() types %d, %d\n",
743
0
            a->elem[0].type, a->elem[1].type);
744
0
        ret=E_BUG;
745
0
        break;
746
0
      }
747
0
      LM_ERR("error(\"%s\", \"%s\") not implemented yet\n",
748
0
        a->elem[0].u.string, a->elem[1].u.string);
749
0
      ret=1;
750
0
      break;
751
0
    case ROUTE_T:
752
0
      init_str(&sval, "unknown");
753
0
      switch (a->elem[0].type) {
754
0
        case NUMBER_ST:
755
0
          i = a->elem[0].u.number;
756
0
          break;
757
0
        case SCRIPTVAR_ST:
758
0
          if (pv_get_spec_value(msg, a->elem[0].u.item, &val) < 0) {
759
0
            LM_ERR("cannot print route name!\n");
760
0
            i = -1;
761
0
            break;
762
0
          }
763
0
          if (val.flags & PV_VAL_INT)
764
0
            sval.s = int2str(val.ri, &sval.len);
765
0
          else
766
0
            sval = val.rs;
767
0
          i = get_script_route_ID_by_name_str(&sval, sroutes->request, RT_NO);
768
0
          break;
769
0
        case SCRIPTVAR_ELEM_ST:
770
0
          if (pv_printf_s(msg, a->elem[0].u.data, &sval) < 0) {
771
0
            LM_ERR("cannot print route name!\n");
772
0
            i = -1;
773
0
            break;
774
0
          }
775
0
          i = get_script_route_ID_by_name_str(&sval, sroutes->request, RT_NO);
776
0
          break;
777
0
        default:
778
0
          i = -1;
779
0
          break;
780
0
      }
781
0
      if (i == -1) {
782
0
        LM_ALERT("unknown route(%.*s) (type %d)\n", sval.len, sval.s,
783
0
            a->elem[0].type);
784
0
        ret=E_BUG;
785
0
        break;
786
0
      }
787
0
      if ((i>=RT_NO)||(i<0)){
788
0
        LM_BUG("invalid routing table number in route(%u)\n", i);
789
0
        ret=E_CFG;
790
0
        break;
791
0
      }
792
0
      script_trace("route", sroutes->request[i].name,
793
0
        msg, a->file, a->line) ;
794
      /* check if the route has parameters */
795
0
      if (a->elem[1].type != 0) {
796
0
        if (a->elem[1].type != NUMBER_ST || a->elem[2].type != SCRIPTVAR_ST) {
797
0
          LM_ALERT("BUG in route() type %d/%d\n",
798
0
              a->elem[1].type, a->elem[2].type);
799
0
          ret=E_BUG;
800
0
          break;
801
0
        }
802
0
        len = a->elem[1].u.number;
803
0
        route_p = route_params_expand(msg, a->elem[2].u.data, len);
804
0
        if (!route_p) {
805
0
          LM_ERR("could not expand route params!\n");
806
0
          ret=E_OUT_OF_MEM;
807
0
          break;
808
0
        }
809
0
        route_params_push_level(sroutes->request[i].name,
810
0
            route_p, (void *)(unsigned long)len, route_param_get);
811
0
        return_code=run_actions(sroutes->request[i].a, msg);
812
0
        route_params_release(route_p, len);
813
0
        route_params_pop_level();
814
0
      } else {
815
0
        route_params_push_level(sroutes->request[i].name, NULL, 0, route_param_get);
816
0
        return_code=run_actions(sroutes->request[i].a, msg);
817
0
        route_params_pop_level();
818
0
      }
819
0
      ret=return_code;
820
0
      break;
821
0
    case IF_T:
822
0
      script_trace("core", "if", msg, a->file, a->line) ;
823
        /* if null expr => ignore if? */
824
0
        if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
825
0
          v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
826
          /* set return code to expr value */
827
0
          if (v<0 || (action_flags&ACT_FL_RETURN)
828
0
              || (action_flags&ACT_FL_EXIT) ){
829
0
            if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
830
0
                || (action_flags&ACT_FL_EXIT) ){ /* hack to quit on DROP*/
831
0
              ret=0;
832
0
              return_code = 0;
833
0
              break;
834
0
            }else{
835
0
              LM_WARN("error in expression at %s:%d\n",
836
0
                a->file, a->line);
837
0
            }
838
0
          }
839
840
0
          ret=1;  /*default is continue */
841
0
          if (v>0) {
842
0
            if ((a->elem[1].type==ACTIONS_ST)&&a->elem[1].u.data){
843
0
              ret=run_action_list(
844
0
                  (struct action*)a->elem[1].u.data,msg );
845
0
              return_code = ret;
846
0
            } else return_code = v;
847
0
          }else{
848
0
            if ((a->elem[2].type==ACTIONS_ST)&&a->elem[2].u.data){
849
0
              ret=run_action_list(
850
0
                (struct action*)a->elem[2].u.data,msg);
851
0
              return_code = ret;
852
0
            } else return_code = v;
853
0
          }
854
0
        }
855
0
      break;
856
0
    case WHILE_T:
857
0
      script_trace("core", "while", msg, a->file, a->line) ;
858
      /* if null expr => ignore if? */
859
0
      if ((a->elem[0].type==EXPR_ST)&&a->elem[0].u.data){
860
0
        len = 0;
861
0
        while(1)
862
0
        {
863
0
          if(len++ >= max_while_loops)
864
0
          {
865
0
            LM_ERR("max while loops reached (%d), increase the "
866
0
                   "'max_while_loops' global!\n", max_while_loops);
867
0
            break;
868
0
          }
869
0
          v=eval_expr((struct expr*)a->elem[0].u.data, msg, 0);
870
          /* set return code to expr value */
871
0
          if (v<0 || (action_flags&ACT_FL_RETURN)
872
0
              || (action_flags&ACT_FL_EXIT) ){
873
0
            if (v==EXPR_DROP || (action_flags&ACT_FL_RETURN)
874
0
                || (action_flags&ACT_FL_EXIT) ){
875
0
              ret=0;
876
0
              return_code = 0;
877
0
              break;
878
0
            }else{
879
0
              LM_WARN("error in expression at %s:%d\n",
880
0
                  a->file, a->line);
881
0
            }
882
0
          }
883
884
0
          ret=1;  /*default is continue */
885
0
          if (v>0) {
886
0
            if ((a->elem[1].type==ACTIONS_ST)
887
0
                &&a->elem[1].u.data){
888
0
              ret=run_action_list(
889
0
                (struct action*)a->elem[1].u.data,msg );
890
              /* check if return was done */
891
0
              if (action_flags &
892
0
                  (ACT_FL_RETURN|ACT_FL_EXIT|ACT_FL_BREAK)) {
893
0
                action_flags &= ~ACT_FL_BREAK;
894
0
                break;
895
0
              }
896
0
              return_code = ret;
897
0
            } else {
898
              /* we should not get here */
899
0
              return_code = v;
900
0
              break;
901
0
            }
902
0
          } else {
903
            /* condition was false */
904
0
            return_code = v;
905
0
            break;
906
0
          }
907
0
        }
908
0
      }
909
0
      break;
910
0
    case BREAK_T:
911
0
      script_trace("core", "break", msg, a->file, a->line) ;
912
0
      action_flags |= ACT_FL_BREAK;
913
0
      break;
914
0
    case FOR_EACH_T:
915
0
      script_trace("core", "for-each", msg, a->file, a->line) ;
916
0
      ret = for_each_handler(msg, a);
917
0
      break;
918
0
    case XDBG_T:
919
0
      script_trace("core", "xdbg", msg, a->file, a->line) ;
920
0
      if (a->elem[0].type == SCRIPTVAR_ELEM_ST)
921
0
      {
922
0
        ret = xdbg(msg, a->elem[0].u.data);
923
0
        if (ret < 0)
924
0
        {
925
0
          LM_ERR("error while printing xdbg message\n");
926
0
          break;
927
0
        }
928
0
      }
929
0
      else
930
0
      {
931
0
        LM_ALERT("BUG in xdbg() type %d\n", a->elem[0].type);
932
0
        ret=E_BUG;
933
0
      }
934
0
      break;
935
0
    case XLOG_T:
936
0
      script_trace("core", "xlog", msg, a->file, a->line) ;
937
0
      if (a->elem[1].u.data != NULL)
938
0
      {
939
0
        if (a->elem[1].type != SCRIPTVAR_ELEM_ST)
940
0
        {
941
0
          LM_ALERT("BUG in xlog() type %d\n", a->elem[1].type);
942
0
          ret=E_BUG;
943
0
          break;
944
0
        }
945
0
        if (a->elem[0].type != STR_ST)
946
0
        {
947
0
          LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
948
0
          ret=E_BUG;
949
0
          break;
950
0
        }
951
0
        ret = xlog_2(msg,a->elem[0].u.data, a->elem[1].u.data);
952
0
        if (ret < 0)
953
0
        {
954
0
          LM_ERR("error while printing xlog message\n");
955
0
          break;
956
0
        }
957
0
      }
958
0
      else
959
0
      {
960
0
        if (a->elem[0].type != SCRIPTVAR_ELEM_ST)
961
0
        {
962
0
          LM_ALERT("BUG in xlog() type %d\n", a->elem[0].type);
963
0
          ret=E_BUG;
964
0
          break;
965
0
        }
966
0
        ret = xlog_1(msg,a->elem[0].u.data);
967
0
        if (ret < 0)
968
0
        {
969
0
          LM_ERR("error while printing xlog message\n");
970
0
          break;
971
0
        }
972
0
      }
973
974
0
      break;
975
0
    case SWITCH_T:
976
0
      script_trace("core", "switch", msg, a->file, a->line) ;
977
#ifdef EXTRA_DEBUG
978
      if (a->elem[0].type!=SCRIPTVAR_ST || a->elem[1].type!=ACTIONS_ST) {
979
        LM_ALERT("BUG in switch() type %d\n",
980
            a->elem[0].type);
981
        ret=E_BUG;
982
        break;
983
      }
984
#endif
985
0
      spec = (pv_spec_t*)a->elem[0].u.data;
986
0
      if(pv_get_spec_value(msg, spec, &val)!=0)
987
0
      {
988
0
        LM_ALERT("BUG - no value in switch()\n");
989
0
        ret=E_BUG;
990
0
        break;
991
0
      }
992
993
0
      return_code=1;
994
0
      adefault = NULL;
995
0
      aitem = (struct action*)a->elem[1].u.data;
996
0
      cmatch=0;
997
0
      while(aitem)
998
0
      {
999
0
        if((unsigned char)aitem->type==DEFAULT_T)
1000
0
          adefault=aitem;
1001
0
        if(cmatch==0)
1002
0
        {
1003
0
          if(aitem->elem[0].type==STR_ST)
1004
0
          {
1005
0
            if(val.flags&PV_VAL_STR
1006
0
                && val.rs.len==aitem->elem[0].u.s.len
1007
0
                && strncasecmp(val.rs.s, aitem->elem[0].u.s.s,
1008
0
                  val.rs.len)==0)
1009
0
              cmatch = 1;
1010
0
          } else { /* number */
1011
0
            if(val.flags&PV_VAL_INT &&
1012
0
                val.ri==aitem->elem[0].u.number)
1013
0
              cmatch = 1;
1014
0
          }
1015
0
        }
1016
0
        if(cmatch==1)
1017
0
        {
1018
0
          if(aitem->elem[1].u.data)
1019
0
          {
1020
0
            return_code=run_action_list(
1021
0
              (struct action*)aitem->elem[1].u.data, msg);
1022
0
            if (action_flags &
1023
0
                (ACT_FL_RETURN | ACT_FL_EXIT | ACT_FL_BREAK)) {
1024
0
              action_flags &= ~ACT_FL_BREAK;
1025
0
              break;
1026
0
            }
1027
0
          }
1028
1029
0
          if (!aitem->next)
1030
0
            cmatch = 0;
1031
0
        }
1032
0
        aitem = aitem->next;
1033
0
      }
1034
0
      if((cmatch==0) && (adefault!=NULL))
1035
0
      {
1036
0
        LM_DBG("switch: running default statement\n");
1037
0
        if(adefault->elem[0].u.data)
1038
0
          return_code=run_action_list(
1039
0
            (struct action*)adefault->elem[0].u.data, msg);
1040
0
        if (action_flags & ACT_FL_BREAK)
1041
0
          action_flags &= ~ACT_FL_BREAK;
1042
0
      }
1043
0
      ret=return_code;
1044
0
      break;
1045
0
    case CMD_T:
1046
0
      if (a->elem[0].type != CMD_ST ||
1047
0
        ((cmd = (const cmd_export_t*)a->elem[0].u.data_const) == NULL)) {
1048
0
        LM_ALERT("BUG in module call\n");
1049
0
        break;
1050
0
      }
1051
1052
0
      script_trace("module", cmd->name, msg, a->file, a->line);
1053
1054
0
      if ((ret = get_cmd_fixups(msg, cmd->params, a->elem, cmdp,
1055
0
        tmp_vals)) < 0) {
1056
0
        LM_ERR("Failed to get fixups for command <%s> in %s, line %d\n",
1057
0
          cmd->name, a->file, a->line);
1058
0
        break;
1059
0
      }
1060
1061
0
      ret = cmd->function(msg,
1062
0
        cmdp[0],cmdp[1],cmdp[2],
1063
0
        cmdp[3],cmdp[4],cmdp[5],
1064
0
        cmdp[6],cmdp[7]);
1065
1066
0
      if (free_cmd_fixups(cmd->params, a->elem, cmdp) < 0) {
1067
0
        LM_ERR("Failed to free fixups for command <%s> in %s, line %d\n",
1068
0
          cmd->name, a->file, a->line);
1069
0
        break;
1070
0
      }
1071
1072
0
      break;
1073
0
    case ASYNC_T:
1074
      /* first param - an ACTIONS_ST containing an ACMD_ST
1075
       * second param - a ROUTE_REF_ST pointing to resume route
1076
       * third param - an optional NUMBER_ST with a timeout */
1077
0
      aitem = (struct action *)(a->elem[0].u.data);
1078
0
      acmd = (const acmd_export_t *)aitem->elem[0].u.data_const;
1079
1080
0
      if (async_script_start_f==NULL || a->elem[0].type!=ACTIONS_ST ||
1081
0
      a->elem[1].type!=ROUTE_REF_ST || aitem->type!=AMODULE_T) {
1082
0
        LM_ALERT("BUG in async expression "
1083
0
                 "(is the 'tm' module loaded?)\n");
1084
0
      } else {
1085
0
        script_trace("async", acmd->name, msg, a->file, a->line);
1086
1087
0
        if ((ret = get_cmd_fixups(msg, acmd->params, aitem->elem, cmdp,
1088
0
          tmp_vals)) < 0) {
1089
0
          LM_ERR("Failed to get fixups for async command <%s> in %s,"
1090
0
                 " line %d\n", acmd->name, a->file, a->line);
1091
0
          break;
1092
0
        }
1093
1094
0
        ret = async_script_start_f(msg, aitem,
1095
0
          (struct script_route_ref*)a->elem[1].u.data,
1096
0
          (unsigned int)a->elem[2].u.number, cmdp);
1097
0
        if (ret>=0)
1098
0
          action_flags |= ACT_FL_TBCONT;
1099
1100
0
        if (free_cmd_fixups(acmd->params, aitem->elem, cmdp) < 0) {
1101
0
          LM_ERR("Failed to free fixups for async command <%s> in %s,"
1102
0
                 " line %d\n", acmd->name, a->file, a->line);
1103
0
          break;
1104
0
        }
1105
0
      }
1106
0
      ret = 0;
1107
0
      break;
1108
0
    case LAUNCH_T:
1109
      /* first param - an ACTIONS_ST containing an ACMD_ST
1110
       * second param - an optional ROUTE_REF_ST pointing to an end route */
1111
0
      aitem = (struct action *)(a->elem[0].u.data);
1112
0
      acmd = (const acmd_export_t *)aitem->elem[0].u.data_const;
1113
1114
0
      if (async_script_start_f==NULL || a->elem[0].type!=ACTIONS_ST ||
1115
0
      a->elem[1].type!=ROUTE_REF_ST || aitem->type!=AMODULE_T) {
1116
0
        LM_ALERT("BUG in launch expression\n");
1117
0
      } else {
1118
0
        script_trace("launch", acmd->name, msg, a->file, a->line);
1119
        /* NOTE that the routeID (a->elem[1].u.data) is set to 
1120
         * NULL if no reporting route is set */
1121
1122
0
        if ((ret = get_cmd_fixups(msg, acmd->params, aitem->elem,
1123
0
          cmdp, tmp_vals)) < 0) {
1124
0
          LM_ERR("Failed to get fixups for launch command <%s> in %s,"
1125
0
                 " line %d\n", acmd->name, a->file, a->line);
1126
0
          break;
1127
0
        }
1128
1129
0
        if (a->elem[2].type==SCRIPTVAR_ELEM_ST && a->elem[2].u.data) {
1130
0
          if (pv_printf_s(msg, a->elem[2].u.data, &sval) < 0) {
1131
0
            LM_ERR("cannot print resume route parameter!\n");
1132
0
            break;
1133
0
          }
1134
1135
0
          ret = async_script_launch( msg, aitem,
1136
0
            (struct script_route_ref*)a->elem[1].u.data,
1137
0
            &sval, cmdp);
1138
0
        } else {
1139
0
          ret = async_script_launch( msg, aitem,
1140
0
            (struct script_route_ref*)a->elem[1].u.data,
1141
0
            NULL, cmdp);
1142
0
        }
1143
1144
0
        if (free_cmd_fixups(acmd->params, aitem->elem, cmdp) < 0) {
1145
0
          LM_ERR("Failed to free fixups for launch command <%s> in %s,"
1146
0
                 " line %d\n", acmd->name, a->file, a->line);
1147
0
          break;
1148
0
        }
1149
0
      }
1150
0
      break;
1151
0
    case EQ_T:
1152
0
    case COLONEQ_T:
1153
0
    case PLUSEQ_T:
1154
0
    case MINUSEQ_T:
1155
0
    case DIVEQ_T:
1156
0
    case MULTEQ_T:
1157
0
    case MODULOEQ_T:
1158
0
    case BANDEQ_T:
1159
0
    case BOREQ_T:
1160
0
    case BXOREQ_T:
1161
0
      ret = do_assign(msg, a);
1162
0
      break;
1163
0
    default:
1164
0
      LM_ALERT("BUG - unknown type %d\n", a->type);
1165
0
      goto error;
1166
0
  }
1167
1168
0
  if((unsigned char)a->type!=IF_T && (unsigned char)a->type!=ROUTE_T)
1169
0
    return_code = ret;
1170
/*skip:*/
1171
1172
0
  update_longest_action(a);
1173
0
  return ret;
1174
1175
0
error:
1176
0
  LM_ERR("error in %s:%d\n", a->file, a->line);
1177
0
  update_longest_action(a);
1178
0
  return ret;
1179
0
}
1180
1181
static int for_each_handler(struct sip_msg *msg, struct action *a)
1182
0
{
1183
0
  struct sip_msg *msg_src = msg;
1184
0
  pv_spec_p iter, spec;
1185
0
  pv_param_t pvp;
1186
0
  pv_value_t val;
1187
0
  int ret = 1;
1188
0
  int op = 0;
1189
1190
0
  if (a->elem[2].type == ACTIONS_ST && a->elem[2].u.data) {
1191
0
    iter = a->elem[0].u.data;
1192
0
    spec = a->elem[1].u.data;
1193
1194
    /*
1195
     * simple is always better.
1196
     * just don't allow fancy for-each statements
1197
     */
1198
0
    if (spec->pvp.pvi.type != PV_IDX_ALL) {
1199
0
      LM_ERR("for-each must be used on a \"[*]\" index! skipping!\n");
1200
0
      return E_SCRIPT;
1201
0
    }
1202
1203
0
    memset(&pvp, 0, sizeof pvp);
1204
0
    pvp.pvi.type = PV_IDX_INT;
1205
0
    pvp.pvn = spec->pvp.pvn;
1206
0
    if (spec->pvc && spec->pvc->contextf) {
1207
0
      msg_src = spec->pvc->contextf(msg);
1208
0
      if (!msg_src || msg_src == FAKED_REPLY) {
1209
0
        LM_BUG("Invalid pv context message: %p\n", msg_src);
1210
0
        return E_BUG;
1211
0
      }
1212
0
    }
1213
1214
    /*
1215
     * for $json iterators, better to assume script writer
1216
     * wants data to be interpreted, rather than not
1217
     *    (i.e. ":=" script operator, and not simply "=")
1218
     */
1219
0
    if (pv_type(iter->type) == PVT_JSON)
1220
0
      op = COLONEQ_T;
1221
1222
0
    for (;;) {
1223
0
      if (spec->getf(msg_src, &pvp, &val) != 0) {
1224
0
        LM_ERR("failed to get spec value\n");
1225
0
        return E_BUG;
1226
0
      }
1227
1228
0
      if (val.flags & PV_VAL_NULL)
1229
0
        break;
1230
1231
0
      if (iter->setf(msg, &iter->pvp, op, &val) != 0) {
1232
0
        LM_ERR("failed to set scriptvar value\n");
1233
0
        return E_BUG;
1234
0
      }
1235
1236
0
      ret = run_action_list(
1237
0
                    (struct action *)a->elem[2].u.data, msg);
1238
1239
      /* check for "return" statements or "0" retcodes */
1240
0
      if (action_flags & (ACT_FL_RETURN | ACT_FL_EXIT | ACT_FL_BREAK)) {
1241
0
        action_flags &= ~ACT_FL_BREAK;
1242
0
        return ret;
1243
0
      }
1244
1245
0
      pvp.pvi.u.ival++;
1246
0
    }
1247
0
  }
1248
1249
0
  return ret;
1250
0
}
1251
1252
/**
1253
 * prints the current point of execution in the OpenSIPS script
1254
 *
1255
 * @class - optional, string to be printed meaning the class of action (if any)
1256
 * @action - mandatory, string with the name of action
1257
 * @msg - mandatory, sip message
1258
 * @line - line in script
1259
 */
1260
void __script_trace(const char *class, const char *action, struct sip_msg *msg,
1261
  const char *file, int line)
1262
0
{
1263
0
  str val;
1264
1265
0
  if (pv_printf_s(msg, &script_trace_elem, &val) != 0) {
1266
0
    LM_ERR("Failed to evaluate variables\n");
1267
0
    return;
1268
0
  }
1269
1270
  /* Also print extra info */
1271
0
  if (script_trace_info) {
1272
0
    LM_GEN1(script_trace_log_level, "[Script Trace][%s:%d][%s][%s %s]"\
1273
0
      " -> (%.*s)\n", file, line, script_trace_info,
1274
0
      class?class:"", action, val.len, val.s);
1275
0
  } else {
1276
0
    LM_GEN1(script_trace_log_level, "[Script Trace][%s:%d][%s %s]"\
1277
0
      " -> (%.*s)\n", file, line,
1278
0
      class?class:"", action, val.len, val.s);
1279
0
  }
1280
0
}
1281
1282
/**
1283
 * functions used to populate $params() vars in the route_param structure
1284
 */
1285
1286
void route_params_push_level(char *rt_name, void *params, void *extra, param_getf_t getf)
1287
0
{
1288
0
  route_rec_level++;
1289
0
  route_params[route_rec_level].params = params;
1290
0
  route_params[route_rec_level].extra = extra;
1291
0
  route_params[route_rec_level].get_param = getf;
1292
1293
0
  if (rt_name) {
1294
0
    route_stack[route_stack_size] = rt_name;
1295
0
    route_stack_size++;
1296
0
  }
1297
0
}
1298
1299
void route_params_pop_level(void)
1300
0
{
1301
0
  route_rec_level--;
1302
0
  route_stack_size--;
1303
0
}
1304
1305
int route_params_run(struct sip_msg *msg,  pv_param_t *ip, pv_value_t *res)
1306
0
{
1307
0
  if (route_rec_level == -1)
1308
0
  {
1309
0
    LM_DBG("no parameter specified for this route\n");
1310
0
    return pv_get_null(msg, ip, res);
1311
0
  }
1312
1313
0
  return route_params[route_rec_level].get_param(msg, ip, res,
1314
0
      route_params[route_rec_level].params,
1315
0
      route_params[route_rec_level].extra);
1316
0
}
1317
1318
1319
static const char *_sip_msg_buf =
1320
"DUMMY sip:user@dummy.com SIP/2.0\r\n"
1321
"Via: SIP/2.0/UDP 127.0.0.1;branch=z9hG4bKdummy\r\n"
1322
"To: <sip:to@dummy.com>\r\n"
1323
"From: <sip:from@dummy.com>;tag=1\r\n"
1324
"Call-ID: dummy-1\r\n"
1325
"CSeq: 1 DUMMY\r\n\r\n";
1326
static struct sip_msg* dummy_static_req= NULL;
1327
static int dummy_static_in_used = 0;
1328
1329
int is_dummy_sip_msg(struct sip_msg *req)
1330
0
{
1331
0
  if (req && req->buf==_sip_msg_buf)
1332
0
    return 0;
1333
0
  return -1;
1334
0
}
1335
1336
struct sip_msg* get_dummy_sip_msg(void)
1337
0
{
1338
0
  struct sip_msg* req;
1339
1340
0
  if (dummy_static_req == NULL || dummy_static_in_used) {
1341
    /* if the static request is not yet allocated, or the static
1342
     * request is already in used (nested calls?), we better allocate
1343
     * a new structure */
1344
0
    LM_DBG("allocating new sip msg\n");
1345
0
    req = (struct sip_msg*)pkg_malloc(sizeof(struct sip_msg));
1346
0
    if(req == NULL)
1347
0
    {
1348
0
      LM_ERR("No more memory\n");
1349
0
      return NULL;
1350
0
    }
1351
0
    memset( req, 0, sizeof(struct sip_msg));
1352
1353
0
    req->buf = (char*)_sip_msg_buf;
1354
0
    req->len = strlen(_sip_msg_buf);
1355
0
    req->rcv.src_ip.af = AF_INET;
1356
0
    req->rcv.dst_ip.af = AF_INET;
1357
1358
0
    parse_msg((char*)_sip_msg_buf, strlen(_sip_msg_buf), req);
1359
0
    parse_headers( req, HDR_EOH_F, 0);
1360
0
    if (dummy_static_req==NULL) {
1361
0
      dummy_static_req = req;
1362
0
      dummy_static_in_used = 1;
1363
0
      LM_DBG("setting as static to %p\n",req);
1364
0
    }
1365
0
  } else {
1366
    /* reuse the static request */
1367
0
    req = dummy_static_req;
1368
0
    LM_DBG("reusing the static sip msg %p\n",req);
1369
0
  }
1370
1371
0
  return req;
1372
0
}
1373
1374
void release_dummy_sip_msg( struct sip_msg* req)
1375
0
{
1376
0
  struct hdr_field* hdrs;
1377
1378
0
  if (req==dummy_static_req) {
1379
    /* for the static request, just strip out the potential
1380
     * changes (lumps, new_uri, dst_uri, etc), but keep the parsed
1381
     * list of headers (this never changes) */
1382
0
    LM_DBG("cleaning the static sip msg %p\n",req);
1383
0
    hdrs = req->headers;
1384
0
    req->headers = NULL;
1385
0
    free_sip_msg(req);
1386
0
    req->headers = hdrs;
1387
0
    req->msg_cb = NULL;
1388
0
    req->new_uri.s = req->dst_uri.s = req->path_vec.s = NULL;
1389
0
    req->new_uri.len = req->dst_uri.len = req->path_vec.len = 0;
1390
0
    req->set_global_address.s = req->set_global_port.s = NULL;
1391
0
    req->set_global_address.len = req->set_global_port.len = 0;
1392
0
    req->add_rm = req->body_lumps = NULL;
1393
0
    req->reply_lump = NULL;
1394
0
    req->ruri_q = Q_UNSPECIFIED;
1395
0
    req->ruri_bflags = 0;
1396
0
    req->force_send_socket = NULL;
1397
0
    req->parsed_uri_ok = 0;
1398
0
    req->parsed_orig_ruri_ok = 0;
1399
0
    req->add_to_branch_len = 0;
1400
0
    req->flags = 0;
1401
0
    req->msg_flags = 0;
1402
0
    memset( &req->time, 0, sizeof(struct timeval));
1403
0
    dummy_static_in_used = 0;
1404
0
  } else {
1405
0
    LM_DBG("freeing allocated sip msg %p\n",req);
1406
    /* is was an 100% allocated request */
1407
0
    free_sip_msg(req);
1408
0
    pkg_free(req);
1409
0
  }
1410
0
}