Coverage Report

Created: 2026-03-11 06:49

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