Browse code

call_control: remove redundant str trim implementation and use the one from core

Henning Westerholt authored on 23/11/2019 22:19:32
Showing 1 changed files
... ...
@@ -40,6 +40,7 @@
40 40
 #include "../../core/str.h"
41 41
 #include "../../core/pvar.h"
42 42
 #include "../../core/ut.h"
43
+#include "../../core/trim.h"
43 44
 #include "../../core/script_cb.h"
44 45
 #include "../../core/parser/digest/digest.h"
45 46
 #include "../../core/parser/parse_from.h"
... ...
@@ -351,41 +352,6 @@ parse_param_stop(unsigned int type, void *val) {
351 352
 }
352 353
 
353 354
 
354
-// Functions dealing with strings
355
-//
356
-
357
-// returns string with whitespace trimmed from left end
358
-static inline void
359
-ltrim(str *string)
360
-{
361
-    while (string->len>0 && isspace((int)*(string->s))) {
362
-        string->len--;
363
-        string->s++;
364
-    }
365
-}
366
-
367
-// returns string with whitespace trimmed from right end
368
-static inline void
369
-rtrim(str *string)
370
-{
371
-    char *ptr;
372
-
373
-    ptr = string->s + string->len - 1;
374
-    while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) {
375
-        string->len--;
376
-        ptr--;
377
-    }
378
-}
379
-
380
-// returns string with whitespace trimmed from both ends
381
-static inline void
382
-trim(str *string)
383
-{
384
-    ltrim(string);
385
-    rtrim(string);
386
-}
387
-
388
-
389 355
 // Message checking and parsing
390 356
 //
391 357
 
Browse code

call_control: switch from deprecated /var/run to /run

The FHS 3.0 [F] has deprecated /var/run in favor of /run. Current
distributions have done so for a long time (for example in Debian
since 6.0 “squeeze”), even though they provide a compatibility
symlink from /var/run to /run. But software like systemd have
started emitting warnings when using /var/run, for example for
its PIDFile directive, which pollutes the logs.

Guillem Jover authored on 25/10/2019 09:56:53 • Daniel-Constantin Mierla committed on 25/10/2019 10:00:46
Showing 1 changed files
... ...
@@ -121,7 +121,7 @@ int parse_param_stop(unsigned int type, void *val);
121 121
 
122 122
 /* Local global variables */
123 123
 static CallControlSocket callcontrol_socket = {
124
-    "/var/run/callcontrol/socket", // name
124
+    "/run/callcontrol/socket", // name
125 125
     -1,                            // sock
126 126
     500,                           // timeout in 500 miliseconds if there is no answer
127 127
     0,                             // time of the last failure
Browse code

call_control: converted to the new module interface

Federico Cabiddu authored on 27/09/2018 15:55:59 • Victor Seva committed on 28/09/2018 11:03:26
Showing 1 changed files
... ...
@@ -172,14 +172,12 @@ struct module_exports exports = {
172 172
     DEFAULT_DLFLAGS, // dlopen flags
173 173
     commands,        // exported functions
174 174
     parameters,      // exported parameters
175
-    NULL,            // exported statistics
176
-    NULL,            // exported MI functions
177
-    NULL,            // exported pseudo-variables
178
-    NULL,            // extra processes
175
+    0,               // exported RPC commands
176
+    0,               // exported pseudo-variables
177
+    0,               // reply processing function
179 178
     mod_init,        // module init function (before fork. kids will inherit)
180
-    NULL,            // reply processing function
181
-    destroy,         // destroy function
182
-    child_init       // child init function
179
+    child_init,      // child init function
180
+    destroy          // destroy function
183 181
 };
184 182
 
185 183
 
Browse code

call_control: keep reference to allocated buffer used for params

Daniel-Constantin Mierla authored on 20/12/2017 08:36:54
Showing 1 changed files
... ...
@@ -91,6 +91,7 @@ typedef struct AVP_Param {
91 91
 typedef struct AVP_List {
92 92
     pv_spec_p pv;
93 93
     str name;
94
+    char *orig;
94 95
     struct AVP_List *next;
95 96
 } AVP_List;
96 97
 
... ...
@@ -261,6 +262,7 @@ cc_parse_param(void *val, AVP_List** avps) {
261 262
 
262 263
     p0 = (char*) pkg_malloc (content.len + 1);
263 264
     CHECK_ALLOC(p0);
265
+    memset(p0, 0, content.len + 1);
264 266
     p = p0;
265 267
 
266 268
     p[content.len] = '\0';
... ...
@@ -270,9 +272,11 @@ cc_parse_param(void *val, AVP_List** avps) {
270 272
 
271 273
         mp = (AVP_List*) pkg_malloc (sizeof(AVP_List));
272 274
         CHECK_ALLOC(mp);
275
+        memset(mp, 0, sizeof(AVP_List));
273 276
         mp->next = *avps;
274 277
         mp->pv = (pv_spec_p) pkg_malloc (sizeof(pv_spec_t));
275 278
         CHECK_ALLOC(mp->pv);
279
+        memset(mp->pv, 0, sizeof(pv_spec_t));
276 280
 
277 281
         for (; isspace(*p); p++);
278 282
         CHECK_COND(*p != '\0');
... ...
@@ -307,6 +311,12 @@ cc_parse_param(void *val, AVP_List** avps) {
307 311
         *avps = mp;
308 312
     }
309 313
 
314
+    if(mp==0) {
315
+        pkg_free(p0);
316
+    } else {
317
+        mp->orig = p0;
318
+    }
319
+
310 320
     return 0;
311 321
 
312 322
 error:
Browse code

call_control: check return values and free in case of errors in fixup

Daniel-Constantin Mierla authored on 30/07/2017 16:18:24
Showing 1 changed files
... ...
@@ -245,6 +245,7 @@ int
245 245
 cc_parse_param(void *val, AVP_List** avps) {
246 246
 
247 247
     char *p = NULL;
248
+    char *p0 = NULL;
248 249
     str s, content;
249 250
     AVP_List *mp = NULL;
250 251
 
... ...
@@ -258,13 +259,13 @@ cc_parse_param(void *val, AVP_List** avps) {
258 259
 		return -1;
259 260
 	}
260 261
 
261
-    p = (char*) pkg_malloc (content.len + 1);
262
-    CHECK_ALLOC(p);
262
+    p0 = (char*) pkg_malloc (content.len + 1);
263
+    CHECK_ALLOC(p0);
264
+    p = p0;
263 265
 
264 266
     p[content.len] = '\0';
265 267
     memcpy(p, content.s, content.len);
266 268
 
267
-
268 269
     for (;*p != '\0';) {
269 270
 
270 271
         mp = (AVP_List*) pkg_malloc (sizeof(AVP_List));
... ...
@@ -296,8 +297,13 @@ cc_parse_param(void *val, AVP_List** avps) {
296 297
         s.len = strlen(p);
297 298
 
298 299
         p = pv_parse_spec(&s, mp->pv);
300
+        if(p==NULL) {
301
+            LM_ERR("failed to parse pv spec\n");
302
+            goto error;
303
+        }
299 304
 
300 305
         for (; isspace(*p); p++);
306
+
301 307
         *avps = mp;
302 308
     }
303 309
 
... ...
@@ -310,6 +316,7 @@ error:
310 316
 		}
311 317
 		pkg_free(mp);
312 318
 	}
319
+    if(p0) pkg_free(p0);
313 320
 	return -1;
314 321
 }
315 322
 
... ...
@@ -581,6 +588,7 @@ make_custom_request(struct sip_msg *msg, CallInfo *call)
581 588
 {
582 589
     static char request[8192];
583 590
     int len = 0;
591
+    int len0 = 0;
584 592
     AVP_List *al;
585 593
     pv_value_t pt;
586 594
 
... ...
@@ -601,21 +609,26 @@ make_custom_request(struct sip_msg *msg, CallInfo *call)
601 609
     }
602 610
 
603 611
     for (; al; al = al->next) {
604
-        pv_get_spec_value(msg, al->pv, &pt);
612
+        if(pv_get_spec_value(msg, al->pv, &pt)<0) {
613
+            LM_ERR("failed to get pv value\n");
614
+            return NULL;
615
+        }
605 616
         if (pt.flags & PV_VAL_INT) {
606
-            len += snprintf(request + len, sizeof(request),
617
+            len += snprintf(request + len0, sizeof(request)-len0,
607 618
                       "%.*s = %d ", al->name.len, al->name.s,
608 619
                    pt.ri);
609 620
         } else    if (pt.flags & PV_VAL_STR) {
610
-            len += snprintf(request + len, sizeof(request),
621
+            len += snprintf(request + len0, sizeof(request)-len0,
611 622
                       "%.*s = %.*s ", al->name.len, al->name.s,
612 623
                    pt.rs.len, pt.rs.s);
613 624
         }
614 625
 
615
-          if (len >= sizeof(request)) {
616
-               LM_ERR("callcontrol request is longer than %ld bytes\n", (unsigned long)sizeof(request));
626
+        if (len >= sizeof(request)-len0) {
627
+            LM_ERR("callcontrol request is longer than %ld bytes\n",
628
+                    (unsigned long)sizeof(request));
617 629
             return NULL;
618
-             }
630
+        }
631
+        len0 = len;
619 632
     }
620 633
 
621 634
 
Browse code

call_control: free pkg memory in case of errors when parsing params

Daniel-Constantin Mierla authored on 30/06/2017 12:02:20
Showing 1 changed files
... ...
@@ -218,13 +218,13 @@ typedef struct CallInfo {
218 218
 #define CHECK_COND(cond) \
219 219
     if ((cond) == 0) { \
220 220
         LM_ERR("malformed modparam\n"); \
221
-        return -1;                            \
221
+        goto error;                     \
222 222
     }
223 223
 
224 224
 #define CHECK_ALLOC(p) \
225 225
     if (!(p)) {    \
226 226
         LM_ERR("no memory left\n"); \
227
-        return -1;    \
227
+        goto error;    \
228 228
     }
229 229
 
230 230
 
... ...
@@ -242,9 +242,9 @@ destroy_list(AVP_List *list) {
242 242
 
243 243
 
244 244
 int
245
-parse_param(void *val, AVP_List** avps) {
245
+cc_parse_param(void *val, AVP_List** avps) {
246 246
 
247
-    char *p;
247
+    char *p = NULL;
248 248
     str s, content;
249 249
     AVP_List *mp = NULL;
250 250
 
... ...
@@ -253,6 +253,10 @@ parse_param(void *val, AVP_List** avps) {
253 253
     content.s = (char*) val;
254 254
     content.len = strlen(content.s);
255 255
 
256
+	if(content.len==0) {
257
+		LM_ERR("empty parameter\n");
258
+		return -1;
259
+	}
256 260
 
257 261
     p = (char*) pkg_malloc (content.len + 1);
258 262
     CHECK_ALLOC(p);
... ...
@@ -298,26 +302,35 @@ parse_param(void *val, AVP_List** avps) {
298 302
     }
299 303
 
300 304
     return 0;
305
+
306
+error:
307
+	if(mp) {
308
+		if(mp->pv) {
309
+			pkg_free(mp->pv);
310
+		}
311
+		pkg_free(mp);
312
+	}
313
+	return -1;
301 314
 }
302 315
 
303 316
 
304 317
 int
305 318
 parse_param_init(unsigned int type, void *val) {
306
-    if (parse_param(val, &cc_init_avps) == -1)
319
+    if (cc_parse_param(val, &cc_init_avps) == -1)
307 320
         return E_CFG;
308 321
     return 0;
309 322
 }
310 323
 
311 324
 int
312 325
 parse_param_start(unsigned int type, void *val) {
313
-    if (parse_param(val, &cc_start_avps) == -1)
326
+    if (cc_parse_param(val, &cc_start_avps) == -1)
314 327
         return E_CFG;
315 328
     return 0;
316 329
 }
317 330
 
318 331
 int
319 332
 parse_param_stop(unsigned int type, void *val) {
320
-    if (parse_param(val, &cc_stop_avps) == -1)
333
+    if (cc_parse_param(val, &cc_stop_avps) == -1)
321 334
         return E_CFG;
322 335
     return 0;
323 336
 }
... ...
@@ -1233,4 +1246,4 @@ int mod_register(char *path, int *dlflags, void *p1, void *p2)
1233 1246
 {
1234 1247
 	sr_kemi_modules_add(sr_kemi_call_control_exports);
1235 1248
 	return 0;
1236
-}
1237 1249
\ No newline at end of file
1250
+}
Browse code

call_control: exported functions to kemi framework

Daniel-Constantin Mierla authored on 04/05/2017 05:31:01
Showing 1 changed files
... ...
@@ -43,6 +43,7 @@
43 43
 #include "../../core/script_cb.h"
44 44
 #include "../../core/parser/digest/digest.h"
45 45
 #include "../../core/parser/parse_from.h"
46
+#include "../../core/kemi.h"
46 47
 #include "../dialog/dlg_load.h"
47 48
 #include "../dialog/dlg_hash.h"
48 49
 
... ...
@@ -1031,8 +1032,7 @@ __dialog_loaded(struct dlg_cell *dlg, int type, struct dlg_cb_params *_params)
1031 1032
 //  -2 - Locked
1032 1033
 //  -3 - No provider
1033 1034
 //  -5 - Internal error (message parsing, communication, ...)
1034
-static int
1035
-CallControl(struct sip_msg *msg, char *str1, char *str2)
1035
+static int ki_call_control(sip_msg_t *msg)
1036 1036
 {
1037 1037
     int result;
1038 1038
 
... ...
@@ -1054,6 +1054,11 @@ CallControl(struct sip_msg *msg, char *str1, char *str2)
1054 1054
     return result;
1055 1055
 }
1056 1056
 
1057
+static int
1058
+CallControl(struct sip_msg *msg, char *str1, char *str2)
1059
+{
1060
+    return ki_call_control(msg);
1061
+}
1057 1062
 
1058 1063
 // Module management: initialization/destroy/function-parameter-fixing/...
1059 1064
 //
... ...
@@ -1206,4 +1211,26 @@ postprocess_request(struct sip_msg *msg, unsigned int flags, void *_param)
1206 1211
     return 1;
1207 1212
 }
1208 1213
 
1214
+/**
1215
+ *
1216
+ */
1217
+/* clang-format off */
1218
+static sr_kemi_t sr_kemi_call_control_exports[] = {
1219
+	{ str_init("call_control"), str_init("call_control"),
1220
+		SR_KEMIP_INT, ki_call_control,
1221
+		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
1222
+			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
1223
+	},
1224
+
1225
+	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
1226
+};
1227
+/* clang-format on */
1209 1228
 
1229
+/**
1230
+ *
1231
+ */
1232
+int mod_register(char *path, int *dlflags, void *p1, void *p2)
1233
+{
1234
+	sr_kemi_modules_add(sr_kemi_call_control_exports);
1235
+	return 0;
1236
+}
1210 1237
\ No newline at end of file
Browse code

core, lib, modules: updated include paths for header files

Daniel-Constantin Mierla authored on 07/12/2016 11:07:22
Showing 1 changed files
... ...
@@ -34,15 +34,15 @@
34 34
 #include <sys/select.h>
35 35
 #include <sys/un.h>
36 36
 
37
-#include "../../sr_module.h"
38
-#include "../../mem/mem.h"
39
-#include "../../dprint.h"
40
-#include "../../str.h"
41
-#include "../../pvar.h"
42
-#include "../../ut.h"
43
-#include "../../script_cb.h"
44
-#include "../../parser/digest/digest.h"
45
-#include "../../parser/parse_from.h"
37
+#include "../../core/sr_module.h"
38
+#include "../../core/mem/mem.h"
39
+#include "../../core/dprint.h"
40
+#include "../../core/str.h"
41
+#include "../../core/pvar.h"
42
+#include "../../core/ut.h"
43
+#include "../../core/script_cb.h"
44
+#include "../../core/parser/digest/digest.h"
45
+#include "../../core/parser/parse_from.h"
46 46
 #include "../dialog/dlg_load.h"
47 47
 #include "../dialog/dlg_hash.h"
48 48
 
Browse code

core, lib, modules: restructured source code tree

- new folder src/ to hold the source code for main project applications
- main.c is in src/
- all core files are subfolder are in src/core/
- modules are in src/modules/
- libs are in src/lib/
- application Makefiles are in src/
- application binary is built in src/ (src/kamailio)

Daniel-Constantin Mierla authored on 07/12/2016 11:03:51
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,1209 @@
1
+/* $Id$
2
+ *
3
+ * Copyright (C) 2005-2008 Dan Pascu
4
+ *
5
+ * This file is part of Kamailio, a free SIP server.
6
+ *
7
+ * Kamailio is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version
11
+ *
12
+ * Kamailio is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20
+ *
21
+ */
22
+
23
+#include <stdio.h>
24
+#include <stdlib.h>
25
+#include <unistd.h>
26
+#include <string.h>
27
+#include <time.h>
28
+#include <ctype.h>
29
+#include <errno.h>
30
+#include <assert.h>
31
+#include <sys/time.h>
32
+#include <sys/types.h>
33
+#include <sys/socket.h>
34
+#include <sys/select.h>
35
+#include <sys/un.h>
36
+
37
+#include "../../sr_module.h"
38
+#include "../../mem/mem.h"
39
+#include "../../dprint.h"
40
+#include "../../str.h"
41
+#include "../../pvar.h"
42
+#include "../../ut.h"
43
+#include "../../script_cb.h"
44
+#include "../../parser/digest/digest.h"
45
+#include "../../parser/parse_from.h"
46
+#include "../dialog/dlg_load.h"
47
+#include "../dialog/dlg_hash.h"
48
+
49
+
50
+MODULE_VERSION
51
+
52
+#define FL_USE_CALL_CONTROL       (1<<28) // use call control for a dialog
53
+
54
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
55
+# define INLINE inline
56
+#else
57
+# define INLINE
58
+#endif
59
+
60
+#define CANONICAL_URI_AVP_SPEC "$avp(s:can_uri)"
61
+#define SIGNALING_IP_AVP_SPEC  "$avp(s:signaling_ip)"
62
+#define SIP_APPLICATION_AVP_SPEC "$avp(s:sip_application)"
63
+
64
+// Although `AF_LOCAL' is mandated by POSIX.1g, `AF_UNIX' is portable to
65
+// more systems.  `AF_UNIX' was the traditional name stemming from BSD, so
66
+// even most POSIX systems support it.  It is also the name of choice in
67
+// the Unix98 specification. So if there's no AF_LOCAL fallback to AF_UNIX
68
+#ifndef AF_LOCAL
69
+# define AF_LOCAL AF_UNIX
70
+#endif
71
+
72
+// Solaris does not have the MSG_NOSIGNAL flag for the send(2) syscall
73
+#ifndef MSG_NOSIGNAL
74
+# define MSG_NOSIGNAL 0
75
+#endif
76
+
77
+
78
+
79
+typedef int Bool;
80
+#define True  1
81
+#define False 0
82
+
83
+
84
+typedef struct AVP_Param {
85
+    str spec;
86
+    int_str name;
87
+    unsigned short type;
88
+} AVP_Param;
89
+
90
+typedef struct AVP_List {
91
+    pv_spec_p pv;
92
+    str name;
93
+    struct AVP_List *next;
94
+} AVP_List;
95
+
96
+#define RETRY_INTERVAL 10
97
+#define BUFFER_SIZE    8192
98
+
99
+typedef struct CallControlSocket {
100
+    char *name;             // name
101
+    int  sock;              // socket
102
+    int  timeout;           // how many miliseconds to wait for an answer
103
+    time_t last_failure;    // time of the last failure
104
+    char data[BUFFER_SIZE]; // buffer for the answer data
105
+} CallControlSocket;
106
+
107
+
108
+/* Function prototypes */
109
+static int CallControl(struct sip_msg *msg, char *str1, char *str2);
110
+
111
+static int mod_init(void);
112
+static int child_init(int rank);
113
+static void destroy(void);
114
+static int postprocess_request(struct sip_msg *, unsigned int, void *);
115
+
116
+int parse_param_init(unsigned int type, void *val);
117
+int parse_param_start(unsigned int type, void *val);
118
+int parse_param_stop(unsigned int type, void *val);
119
+
120
+/* Local global variables */
121
+static CallControlSocket callcontrol_socket = {
122
+    "/var/run/callcontrol/socket", // name
123
+    -1,                            // sock
124
+    500,                           // timeout in 500 miliseconds if there is no answer
125
+    0,                             // time of the last failure
126
+    ""                             // data
127
+};
128
+
129
+static int disable = False;
130
+static int diverter_avp_id = 805;
131
+
132
+/* The AVP where the canonical URI is stored (if defined) */
133
+static AVP_Param canonical_uri_avp = {str_init(CANONICAL_URI_AVP_SPEC), {0}, 0};
134
+
135
+/* The AVP where the caller signaling IP is stored (if defined) */
136
+static AVP_Param signaling_ip_avp = {str_init(SIGNALING_IP_AVP_SPEC), {0}, 0};
137
+
138
+/* The AVP where the SIP application type is stored (if defined) */
139
+static AVP_Param sip_application_avp = {str_init(SIP_APPLICATION_AVP_SPEC), {0}, 0};
140
+
141
+
142
+struct dlg_binds dlg_api;
143
+static int dialog_flag = -1;
144
+
145
+AVP_List *cc_init_avps = NULL, *cc_start_avps = NULL, *cc_stop_avps = NULL;
146
+
147
+pv_elem_t *model;
148
+
149
+static cmd_export_t commands[] = {
150
+    {"call_control",  (cmd_function)CallControl, 0, 0, 0, REQUEST_ROUTE },
151
+    {0, 0, 0, 0, 0, 0}
152
+};
153
+
154
+static param_export_t parameters[] = {
155
+    {"init",                PARAM_STRING | USE_FUNC_PARAM, parse_param_init},
156
+    {"start",               PARAM_STRING | USE_FUNC_PARAM, parse_param_start},
157
+    {"stop",                PARAM_STRING | USE_FUNC_PARAM, parse_param_stop},
158
+    {"disable",             INT_PARAM, &disable},
159
+    {"socket_name",         PARAM_STRING, &(callcontrol_socket.name)},
160
+    {"socket_timeout",      INT_PARAM, &(callcontrol_socket.timeout)},
161
+    {"diverter_avp_id",     INT_PARAM, &diverter_avp_id},
162
+    {"canonical_uri_avp",   PARAM_STR, &(canonical_uri_avp.spec)},
163
+    {"signaling_ip_avp",    PARAM_STR, &(signaling_ip_avp.spec)},
164
+    {"sip_application_avp", PARAM_STR, &(sip_application_avp.spec)},
165
+    {0, 0, 0}
166
+};
167
+
168
+struct module_exports exports = {
169
+    "call_control",  // module name
170
+    DEFAULT_DLFLAGS, // dlopen flags
171
+    commands,        // exported functions
172
+    parameters,      // exported parameters
173
+    NULL,            // exported statistics
174
+    NULL,            // exported MI functions
175
+    NULL,            // exported pseudo-variables
176
+    NULL,            // extra processes
177
+    mod_init,        // module init function (before fork. kids will inherit)
178
+    NULL,            // reply processing function
179
+    destroy,         // destroy function
180
+    child_init       // child init function
181
+};
182
+
183
+
184
+
185
+typedef enum CallControlAction {
186
+    CAInitialize = 1,
187
+    CAStart,
188
+    CAStop
189
+} CallControlAction;
190
+
191
+
192
+typedef struct Contact {
193
+    str username;
194
+    str ip;
195
+    str port;
196
+} Contact;
197
+
198
+typedef struct DialogID {
199
+    unsigned int h_entry;
200
+    unsigned int h_id;
201
+} DialogID;
202
+
203
+typedef struct CallInfo {
204
+    CallControlAction action;
205
+    DialogID dialog_id;
206
+    str ruri;
207
+    str diverter;
208
+    str source_ip;
209
+    str callid;
210
+    str from;
211
+    str from_tag;
212
+    str sip_application;
213
+} CallInfo;
214
+
215
+
216
+
217
+#define CHECK_COND(cond) \
218
+    if ((cond) == 0) { \
219
+        LM_ERR("malformed modparam\n"); \
220
+        return -1;                            \
221
+    }
222
+
223
+#define CHECK_ALLOC(p) \
224
+    if (!(p)) {    \
225
+        LM_ERR("no memory left\n"); \
226
+        return -1;    \
227
+    }
228
+
229
+
230
+void
231
+destroy_list(AVP_List *list) {
232
+	AVP_List *cur, *next;
233
+
234
+	cur = list;
235
+	while (cur) {
236
+		next = cur->next;
237
+		pkg_free(cur);
238
+		cur = next;
239
+	}
240
+}
241
+
242
+
243
+int
244
+parse_param(void *val, AVP_List** avps) {
245
+
246
+    char *p;
247
+    str s, content;
248
+    AVP_List *mp = NULL;
249
+
250
+    //LM_DBG("%.*s\n", content.len, content.s);
251
+
252
+    content.s = (char*) val;
253
+    content.len = strlen(content.s);
254
+
255
+
256
+    p = (char*) pkg_malloc (content.len + 1);
257
+    CHECK_ALLOC(p);
258
+
259
+    p[content.len] = '\0';
260
+    memcpy(p, content.s, content.len);
261
+
262
+
263
+    for (;*p != '\0';) {
264
+
265
+        mp = (AVP_List*) pkg_malloc (sizeof(AVP_List));
266
+        CHECK_ALLOC(mp);
267
+        mp->next = *avps;
268
+        mp->pv = (pv_spec_p) pkg_malloc (sizeof(pv_spec_t));
269
+        CHECK_ALLOC(mp->pv);
270
+
271
+        for (; isspace(*p); p++);
272
+        CHECK_COND(*p != '\0');
273
+
274
+        mp->name.s = p;
275
+
276
+        for(; isgraph(*p) && *p != '='; p++)
277
+            CHECK_COND(*p != '\0');
278
+
279
+        mp->name.len = p - mp->name.s;
280
+
281
+        for (; isspace(*p); p++);
282
+        CHECK_COND(*p != '\0' && *p == '=');
283
+        p++;
284
+
285
+        //LM_DBG("%.*s\n", mp->name.len, mp->name.s);
286
+
287
+        for (; isspace(*p); p++);
288
+        CHECK_COND(*p != '\0' && *p == '$');
289
+
290
+        s.s = p;
291
+        s.len = strlen(p);
292
+
293
+        p = pv_parse_spec(&s, mp->pv);
294
+
295
+        for (; isspace(*p); p++);
296
+        *avps = mp;
297
+    }
298
+
299
+    return 0;
300
+}
301
+
302
+
303
+int
304
+parse_param_init(unsigned int type, void *val) {
305
+    if (parse_param(val, &cc_init_avps) == -1)
306
+        return E_CFG;
307
+    return 0;
308
+}
309
+
310
+int
311
+parse_param_start(unsigned int type, void *val) {
312
+    if (parse_param(val, &cc_start_avps) == -1)
313
+        return E_CFG;
314
+    return 0;
315
+}
316
+
317
+int
318
+parse_param_stop(unsigned int type, void *val) {
319
+    if (parse_param(val, &cc_stop_avps) == -1)
320
+        return E_CFG;
321
+    return 0;
322
+}
323
+
324
+
325
+// Functions dealing with strings
326
+//
327
+
328
+// returns string with whitespace trimmed from left end
329
+static inline void
330
+ltrim(str *string)
331
+{
332
+    while (string->len>0 && isspace((int)*(string->s))) {
333
+        string->len--;
334
+        string->s++;
335
+    }
336
+}
337
+
338
+// returns string with whitespace trimmed from right end
339
+static inline void
340
+rtrim(str *string)
341
+{
342
+    char *ptr;
343
+
344
+    ptr = string->s + string->len - 1;
345
+    while (string->len>0 && (*ptr==0 || isspace((int)*ptr))) {
346
+        string->len--;
347
+        ptr--;
348
+    }
349
+}
350
+
351
+// returns string with whitespace trimmed from both ends
352
+static inline void
353
+trim(str *string)
354
+{
355
+    ltrim(string);
356
+    rtrim(string);
357
+}
358
+
359
+
360
+// Message checking and parsing
361
+//
362
+
363
+static Bool
364
+has_to_tag(struct sip_msg *msg)
365
+{
366
+    str tag;
367
+
368
+    if (!msg->to) {
369
+        if (parse_headers(msg, HDR_TO_F, 0)==-1) {
370
+            LOG(L_ERR, "cannot parse 'To' header\n");
371
+            return False;
372
+        }
373
+        if (!msg->to) {
374
+            LOG(L_ERR, "missing 'To' header\n");
375
+            return False;
376
+        }
377
+    }
378
+
379
+    tag = get_to(msg)->tag_value;
380
+
381
+    if (tag.s==NULL || tag.len==0) {
382
+        return False;
383
+    }
384
+
385
+    return True;
386
+}
387
+
388
+
389
+// Get canonical request URI
390
+static str
391
+get_canonical_request_uri(struct sip_msg* msg)
392
+{
393
+    int_str value;
394
+
395
+    if (!search_first_avp(canonical_uri_avp.type | AVP_VAL_STR,
396
+                          canonical_uri_avp.name, &value, NULL) ||
397
+        value.s.s==NULL || value.s.len==0) {
398
+
399
+        return *GET_RURI(msg);
400
+    }
401
+
402
+    return value.s;
403
+}
404
+
405
+
406
+// Get caller signaling IP
407
+static str
408
+get_signaling_ip(struct sip_msg* msg)
409
+{
410
+    int_str value;
411
+
412
+    if (!search_first_avp(signaling_ip_avp.type | AVP_VAL_STR,
413
+                          signaling_ip_avp.name, &value, NULL) ||
414
+        !value.s.s || value.s.len==0) {
415
+
416
+        value.s.s = ip_addr2a(&msg->rcv.src_ip);
417
+        value.s.len = strlen(value.s.s);
418
+    }
419
+
420
+    return value.s;
421
+}
422
+
423
+// Get SIP application type
424
+static str
425
+get_sip_application(struct sip_msg* msg)
426
+{
427
+    int_str value;
428
+
429
+    if (!search_first_avp(sip_application_avp.type | AVP_VAL_STR,
430
+                          sip_application_avp.name, &value, NULL) ||
431
+        !value.s.s || value.s.len==0) {
432
+
433
+        value.s.s = "audio";
434
+        value.s.len = strlen(value.s.s);
435
+    }
436
+
437
+    return value.s;
438
+}
439
+
440
+static str
441
+get_diverter(struct sip_msg *msg)
442
+{
443
+    struct hdr_field *header;
444
+    dig_cred_t *credentials;
445
+    int_str avpname, avpvalue;
446
+    static str diverter;
447
+
448
+    diverter.s   = "None";
449
+    diverter.len = 4;
450
+
451
+    avpname.n = diverter_avp_id;
452
+
453
+    if (search_first_avp(AVP_VAL_STR, avpname, &avpvalue, NULL)) {
454
+        // have a diverted call
455
+        diverter = avpvalue.s;
456
+    } else {
457
+        get_authorized_cred(msg->proxy_auth, &header);
458
+        if (header) {
459
+            credentials = &((auth_body_t*)(header->parsed))->digest;
460
+        } else {
461
+            if (parse_headers(msg, HDR_PROXYAUTH_F, 0) == -1) {
462
+                LOG(L_ERR, "cannot parse Proxy-Authorization header\n");
463
+                return diverter;
464
+            }
465
+            if (!msg->proxy_auth)
466
+                return diverter;
467
+            if (parse_credentials(msg->proxy_auth) != 0) {
468
+                LOG(L_ERR, "cannot parse credentials\n");
469
+                return diverter;
470
+            }
471
+            credentials = &((auth_body_t*)(msg->proxy_auth->parsed))->digest;
472
+        }
473
+
474
+        if (credentials->username.user.len > 0 &&
475
+            credentials->username.domain.len > 0 &&
476
+            credentials->realm.len == 0 &&
477
+            credentials->nonce.len == 0 &&
478
+            credentials->response.len == 0) {
479
+            // this is a call diverted from the failure route
480
+            // and sent back to proxy with append_pa_hf()
481
+            diverter = credentials->username.whole;
482
+        }
483
+    }
484
+
485
+    return diverter;
486
+}
487
+
488
+
489
+static CallInfo*
490
+get_call_info(struct sip_msg *msg, CallControlAction action)
491
+{
492
+    static CallInfo call_info;
493
+    hdr_flags_t headers;
494
+
495
+    memset(&call_info, 0, sizeof(struct CallInfo));
496
+
497
+    switch (action) {
498
+    case CAInitialize:
499
+        headers = HDR_CALLID_F|HDR_FROM_F;
500
+        break;
501
+    case CAStart:
502
+    case CAStop:
503
+        headers = HDR_CALLID_F;
504
+        break;
505
+    default:
506
+        // Invalid action. Should never get here.
507
+        assert(False);
508
+        return NULL;
509
+    }
510
+
511
+    if (parse_headers(msg, headers, 0) == -1) {
512
+        LOG(L_ERR, "cannot parse required headers\n");
513
+        return NULL;
514
+    }
515
+
516
+    if (headers & HDR_CALLID_F) {
517
+        if (msg->callid == NULL) {
518
+            LOG(L_ERR, "missing Call-ID header\n");
519
+            return NULL;
520
+        }
521
+
522
+        call_info.callid = msg->callid->body;
523
+        trim(&call_info.callid);
524
+    }
525
+
526
+    if (headers & HDR_FROM_F) {
527
+        struct to_body *from; // yeah. suggestive structure name ;)