Coverage Report

Created: 2025-07-11 06:28

/src/opensips/script_cb.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2001-2003 FhG Fokus
3
 *
4
 * This file is part of opensips, a free SIP server.
5
 *
6
 * opensips is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version
10
 *
11
 * opensips is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19
 *
20
 * History:
21
 * --------
22
 *  2003-03-29  cleaning pkg allocation introduced (jiri)
23
 *  2003-03-19  replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
24
 *  2005-02-13  script callbacks devided into request and reply types (bogdan)
25
 *  2009-05-21  keep the callback lists in the same order as callbacks
26
                 were registered (bogdan)
27
 */
28
29
/*!
30
 * \file
31
 * \brief Script callbacks
32
 */
33
34
35
#include <stdlib.h>
36
#include "script_cb.h"
37
#include "dprint.h"
38
#include "error.h"
39
#include "mem/mem.h"
40
41
static struct script_cb *pre_req_cb=0;
42
static struct script_cb *post_req_cb=0;
43
44
static struct script_cb *pre_rpl_cb=0;
45
static struct script_cb *post_rpl_cb=0;
46
47
static struct script_cb *parse_err_cb=0;
48
49
static unsigned int cb_id=0;
50
51
struct raw_processing_cb_list* pre_processing_cb_list = NULL;
52
struct raw_processing_cb_list* post_processing_cb_list = NULL;
53
54
static inline int add_callback( struct script_cb **list,
55
  cb_function f, void *param, int prio)
56
0
{
57
0
  struct script_cb *last_cb;
58
0
  struct script_cb *new_cb;
59
60
0
  new_cb=pkg_malloc(sizeof(struct script_cb));
61
0
  if (new_cb==0) {
62
0
    LM_ERR("out of pkg memory\n");
63
0
    return -1;
64
0
  }
65
0
  new_cb->cbf = f;
66
0
  new_cb->id = cb_id++;
67
0
  new_cb->param = param;
68
0
  new_cb->next = NULL;
69
0
  new_cb->prio = prio;
70
71
  /* descending priority sorting; equal priorities are inserted at the end
72
    it is important to keep the order at register time, as this reflects the
73
    order of loading/init the modules --bogdan */
74
0
  if (*list==NULL) {
75
0
    *list = new_cb;
76
0
  } else if ((*list)->prio < prio) {
77
0
    new_cb->next = *list;
78
0
    *list = new_cb;
79
0
  } else {
80
0
    for (last_cb = *list;
81
0
         last_cb->next && last_cb->next->prio >= prio;
82
0
         last_cb = last_cb->next)
83
0
      ;
84
85
0
    new_cb->next = last_cb->next;
86
0
    last_cb->next = new_cb;
87
0
  }
88
89
0
  return 0;
90
0
}
91
92
93
int __register_script_cb( cb_function f, int type, void *param, int prio)
94
0
{
95
  /* type checkings */
96
0
  if ( (type&(REQ_TYPE_CB|RPL_TYPE_CB|PARSE_ERR_CB))==0 ) {
97
0
    LM_CRIT("request / reply / error type not specified\n");
98
0
    goto error;
99
0
  }
100
0
  if ( (type&(PRE_SCRIPT_CB|POST_SCRIPT_CB|PARSE_ERR_CB))==0 ||
101
0
  (type&PRE_SCRIPT_CB && type&POST_SCRIPT_CB) ) {
102
0
    LM_CRIT("callback POST or PRE type must be exactly one\n");
103
0
    goto error;
104
0
  }
105
106
0
  if (type&PARSE_ERR_CB) {
107
0
    if (add_callback( &parse_err_cb, f, param, prio)<0)
108
0
      goto add_error;
109
0
  }
110
111
0
  if (type&REQ_TYPE_CB) {
112
    /* callback for request script */
113
0
    if (type&PRE_SCRIPT_CB) {
114
0
      if (add_callback( &pre_req_cb, f, param, prio)<0)
115
0
        goto add_error;
116
0
    } else if (type&POST_SCRIPT_CB) {
117
0
      if (add_callback( &post_req_cb, f, param, prio)<0)
118
0
        goto add_error;
119
0
    }
120
0
  }
121
0
  if (type&RPL_TYPE_CB) {
122
    /* callback (also) for reply script */
123
0
    if (type&PRE_SCRIPT_CB) {
124
0
      if (add_callback( &pre_rpl_cb, f, param, prio)<0)
125
0
        goto add_error;
126
0
    } else if (type&POST_SCRIPT_CB) {
127
0
      if (add_callback( &post_rpl_cb, f, param, prio)<0)
128
0
        goto add_error;
129
0
    }
130
0
  }
131
132
0
  return 0;
133
0
add_error:
134
0
  LM_ERR("failed to add callback\n");
135
0
error:
136
0
  return -1;
137
0
}
138
139
140
static inline void destroy_cb_list(struct script_cb **list)
141
0
{
142
0
  struct script_cb *foo;
143
144
0
  while( *list ) {
145
0
    foo = *list;
146
0
    *list = (*list)->next;
147
0
    pkg_free( foo );
148
0
  }
149
0
}
150
151
152
void destroy_script_cb(void)
153
0
{
154
0
  destroy_cb_list( &pre_req_cb  );
155
0
  destroy_cb_list( &post_req_cb );
156
0
  destroy_cb_list( &pre_rpl_cb  );
157
0
  destroy_cb_list( &post_req_cb );
158
0
  destroy_cb_list( &parse_err_cb );
159
0
}
160
161
162
static inline int exec_pre_cb( struct sip_msg *msg, struct script_cb *cb)
163
0
{
164
0
  int bitmask = SCB_RUN_ALL;
165
166
0
  for ( ; cb ; cb=cb->next ) {
167
0
    bitmask &= cb->cbf(msg, cb->param);
168
169
0
    if (bitmask == SCB_DROP_MSG)
170
0
      break;
171
0
  }
172
173
0
  return bitmask;
174
0
}
175
176
177
static inline int exec_post_cb( struct sip_msg *msg, struct script_cb *cb)
178
0
{
179
0
  for ( ; cb ; cb=cb->next){
180
0
    cb->cbf( msg, cb->param);
181
0
  }
182
0
  return 1;
183
0
}
184
185
186
int exec_pre_req_cb( struct sip_msg *msg)
187
0
{
188
0
  return exec_pre_cb( msg, pre_req_cb);
189
0
}
190
191
int exec_pre_rpl_cb( struct sip_msg *msg)
192
0
{
193
0
  return exec_pre_cb( msg, pre_rpl_cb);
194
0
}
195
196
int exec_post_req_cb( struct sip_msg *msg)
197
0
{
198
0
  return exec_post_cb( msg, post_req_cb);
199
0
}
200
201
int exec_post_rpl_cb( struct sip_msg *msg)
202
0
{
203
0
  return exec_post_cb( msg, post_rpl_cb);
204
0
}
205
206
int exec_parse_err_cb( struct sip_msg *msg)
207
0
{
208
0
  return exec_post_cb( msg, parse_err_cb);
209
0
}
210
211
static inline int insert_raw_processing_cb(raw_processing_func f, int type, struct raw_processing_cb_list* list, char freeable)
212
0
{
213
0
  struct raw_processing_cb_list *elem;
214
215
0
  if (f == NULL) {
216
0
    LM_ERR("null callback\n");
217
0
    return -1;
218
0
  }
219
220
0
  elem = pkg_malloc(sizeof(struct raw_processing_cb_list));
221
0
  if (elem == NULL) {
222
0
    LM_ERR("no more pkg mem\n");
223
0
    return -1;
224
0
  }
225
226
0
  elem->f = f;
227
0
  elem->freeable = freeable;
228
0
  elem->next = NULL;
229
230
0
  if (list == NULL) {
231
0
    list = elem;
232
0
    return !(type==PRE_RAW_PROCESSING ? (pre_processing_cb_list=list)
233
0
                      : (post_processing_cb_list=list));
234
0
  } else {
235
0
    while (list->next != NULL)
236
0
      list = list->next;
237
0
    list->next=elem;
238
0
  }
239
240
0
  return 0;
241
242
0
}
243
244
int register_pre_raw_processing_cb(raw_processing_func f, int type, char freeable)
245
0
{
246
0
  return  insert_raw_processing_cb(f, type, pre_processing_cb_list, freeable);
247
0
}
248
249
int register_post_raw_processing_cb(raw_processing_func f, int type, char freeable)
250
0
{
251
0
  return  insert_raw_processing_cb(f, type, post_processing_cb_list, freeable);
252
0
}
253
254
255
256
257
258
int run_pre_raw_processing_cb(int type, str* data, struct sip_msg* msg)
259
0
{
260
0
  return run_raw_processing_cb(type, data, msg, pre_processing_cb_list);
261
0
}
262
263
int run_post_raw_processing_cb(int type, str* data, struct sip_msg* msg)
264
0
{
265
0
  return run_raw_processing_cb(type, data, msg, post_processing_cb_list);
266
0
}
267
268
int run_raw_processing_cb(int type, str *data, struct sip_msg* msg, struct raw_processing_cb_list* list)
269
0
{
270
271
0
  struct raw_processing_cb_list *foo=NULL, *last_good=NULL, *head=NULL;
272
0
  char *initial_data = data->s, *input_data;
273
0
  int rc;
274
275
0
  if (list == NULL)
276
0
    return 0;
277
278
0
  while (list) {
279
0
    input_data = data->s;
280
    /* a return code bigger than 0 means you want to keep the callback */
281
0
    if ((rc = list->f(data, msg)) < 0) {
282
0
      LM_ERR("failed to run callback\n");
283
0
      return -1;
284
0
    }
285
286
0
    if (input_data != initial_data && input_data != data->s)
287
0
      pkg_free(input_data);
288
289
0
    foo = list;
290
0
    list = list->next;
291
292
0
    if (foo != NULL) {
293
0
      if (foo->freeable && rc == 0) {
294
        /* foo will be gone so link the last good element
295
         * to the next one */
296
0
        if (last_good)
297
0
          last_good->next=list;
298
299
0
        pkg_free(foo);
300
0
      } else {
301
        /* keep the first element not to be freed */
302
0
        if (head == NULL)
303
0
          head = foo;
304
        /* and keep track of the last viable element to link with the
305
         * next viable element */
306
0
        last_good = foo;
307
0
      }
308
0
    }
309
0
  }
310
311
0
  return !(type==PRE_RAW_PROCESSING?(pre_processing_cb_list=head)
312
0
                    :(post_processing_cb_list=head));
313
0
}
314