rr: different function parameter name to be different than global variable
[sip-router] / src / modules / rr / rr_mod.c
1 /*
2  * Copyright (C) 2001-2003 FhG Fokus
3  * Copyright (C) 2011 Carsten Bock, carsten@ng-voice.com
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  * \file
24  * \brief Route & Record-Route module
25  * \ingroup rr
26  */
27
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <sys/types.h>
32 #include <regex.h>
33
34 #include "../../core/sr_module.h"
35 #include "../../core/ut.h"
36 #include "../../core/error.h"
37 #include "../../core/pvar.h"
38 #include "../../core/mem/mem.h"
39 #include "../../core/mod_fix.h"
40 #include "../../core/kemi.h"
41 #include "../../core/parser/parse_rr.h"
42 #include "../../core/parser/parse_from.h"
43 #include "../../core/parser/parse_to.h"
44 #include "../outbound/api.h"
45 #include "loose.h"
46 #include "record.h"
47 #include "rr_cb.h"
48 #include "api.h"
49
50 #ifdef ENABLE_USER_CHECK
51 #include <string.h>
52 #include "../../core/str.h"
53 str i_user = {0,0};
54 #endif
55
56 int append_fromtag = 1;         /*!< append from tag by default */
57 int enable_double_rr = 1;       /*!< enable using of 2 RR by default */
58 int enable_full_lr = 0;         /*!< compatibilty mode disabled by default */
59 int add_username = 0;           /*!< do not add username by default */
60 int rr_force_send_socket = 0; /*!< control if socket is forced by rr */
61 int enable_socket_mismatch_warning = 1; /*!< enable socket mismatch warning */
62 static str custom_user_spec = {NULL, 0};
63 pv_spec_t custom_user_avp;
64 int rr_ignore_sips = 0; /*!< ignore sips schema when building record-route */
65 int rr_sockname_mode = 0; /*!< add socket name to R-R header */
66
67 ob_api_t rr_obb;
68
69 MODULE_VERSION
70
71 static int  mod_init(void);static void mod_destroy(void);
72 /* fixup functions */
73 static int direction_fixup(void** param, int param_no);
74 static int it_list_fixup(void** param, int param_no);
75 /* wrapper functions */
76 static int w_loose_route(struct sip_msg *, char *, char *);
77 static int w_loose_route_preloaded(struct sip_msg *, char *, char *);
78 static int w_record_route(struct sip_msg *, char *, char *);
79 static int w_record_route_preset(struct sip_msg *,char *, char *);
80 static int w_record_route_advertised_address(struct sip_msg *, char *, char *);
81 static int w_add_rr_param(struct sip_msg *,char *, char *);
82 static int w_check_route_param(struct sip_msg *,char *, char *);
83 static int w_is_direction(struct sip_msg *,char *, char *);
84 static int w_remove_record_route(sip_msg_t*, char*, char*);
85 static int w_rr_next_hop_route(sip_msg_t *, char *, char *);
86 /* PV functions */
87 static int pv_get_route_uri_f(struct sip_msg *, pv_param_t *, pv_value_t *);
88 static int pv_get_from_tag_initial(sip_msg_t *msg, pv_param_t *param,
89                 pv_value_t *res);
90 static int pv_get_to_tag_initial(sip_msg_t *msg, pv_param_t *param,
91                 pv_value_t *res);
92 static int pv_get_rdir(sip_msg_t *msg, pv_param_t *param, pv_value_t *res);
93 static int pv_parse_rdir_name(pv_spec_p sp, str *in);
94
95 /*!
96  * \brief Exported functions
97  */
98 static cmd_export_t cmds[] = {
99         {"loose_route",          (cmd_function)w_loose_route,           0, 0, 0,
100                         REQUEST_ROUTE},
101         {"loose_route_preloaded", (cmd_function)w_loose_route_preloaded,0, 0, 0,
102                         REQUEST_ROUTE},
103         {"record_route",         (cmd_function)w_record_route,          0, 0, 0,
104                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
105         {"record_route",         (cmd_function)w_record_route,          1, it_list_fixup, 0,
106                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
107         {"record_route_preset",  (cmd_function)w_record_route_preset, 1, it_list_fixup, 0,
108                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
109         {"record_route_preset",  (cmd_function)w_record_route_preset, 2, it_list_fixup, 0,
110                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
111         {"record_route_advertised_address",  (cmd_function)w_record_route_advertised_address, 1, it_list_fixup, 0,
112                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
113         {"add_rr_param",         (cmd_function)w_add_rr_param,  1, it_list_fixup, 0,
114                         REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
115         {"check_route_param",    (cmd_function)w_check_route_param, 1, fixup_regexp_null, fixup_free_regexp_null,
116                         REQUEST_ROUTE},
117         {"is_direction",         (cmd_function)w_is_direction,          1, direction_fixup, 0,
118                         REQUEST_ROUTE},
119         {"remove_record_route",  w_remove_record_route, 0, 0, 0,
120                         REQUEST_ROUTE|FAILURE_ROUTE},
121         {"rr_next_hop_route",    (cmd_function)w_rr_next_hop_route,             0, 0, 0,
122                         ANY_ROUTE},
123         {"load_rr",              (cmd_function)load_rr,                                 0, 0, 0, 0},
124         {0, 0, 0, 0, 0, 0}
125 };
126
127
128 /*!
129  * \brief Exported parameters
130  */
131 static param_export_t params[] ={
132         {"append_fromtag",          INT_PARAM, &append_fromtag},
133         {"enable_double_rr",    INT_PARAM, &enable_double_rr},
134         {"enable_full_lr",              INT_PARAM, &enable_full_lr},
135 #ifdef ENABLE_USER_CHECK
136         {"ignore_user",             PARAM_STR, &i_user},
137 #endif
138         {"add_username",                INT_PARAM, &add_username},
139         {"enable_socket_mismatch_warning",INT_PARAM,&enable_socket_mismatch_warning},
140         {"custom_user_avp",     PARAM_STR, &custom_user_spec},
141         {"force_send_socket",   PARAM_INT, &rr_force_send_socket},
142         {"ignore_sips",         PARAM_INT, &rr_ignore_sips},
143         {"sockname_mode",       PARAM_INT, &rr_sockname_mode},
144         {0, 0, 0 }
145 };
146
147 /*!
148  * \brief Exported Pseudo variables
149  */
150 static pv_export_t mod_pvs[] = {
151         {{"route_uri", (sizeof("route_uri")-1)}, /* URI of the first Route-Header */
152                 PVT_OTHER, pv_get_route_uri_f, 0, 0, 0, 0, 0},
153         {{"fti", (sizeof("fti")-1)}, /* From-Tag as for initial request */
154                 PVT_OTHER, pv_get_from_tag_initial, 0, 0, 0, 0, 0},
155         {{"tti", (sizeof("tti")-1)}, /* To-Tag as for response to initial request */
156                 PVT_OTHER, pv_get_to_tag_initial, 0, 0, 0, 0, 0},
157         { {"rdir", (sizeof("rdir")-1)}, PVT_OTHER, pv_get_rdir, 0,
158                 pv_parse_rdir_name, 0, 0, 0 },
159
160         {{0, 0}, 0, 0, 0, 0, 0, 0, 0}
161 };
162
163
164
165 struct module_exports exports = {
166         "rr",            /* module name */
167         DEFAULT_DLFLAGS, /* dlopen flags */
168         cmds,            /* cmd (cfg function) exports */
169         params,          /* param exports */
170         0,               /* RPC method exports */
171         mod_pvs,         /* pseudo-variables exports */
172         0,               /* response handling function */
173         mod_init,        /* module init function */
174         0,               /* per-child init function */
175         mod_destroy      /* module destroy function */
176 };
177
178
179 static int mod_init(void)
180 {
181         if (ob_load_api(&rr_obb) == 0)
182                 LM_DBG("Bound rr module to outbound module\n");
183         else
184         {
185                 LM_INFO("outbound module not available\n");
186                 memset(&rr_obb, 0, sizeof(ob_api_t));
187         }
188
189 #ifdef ENABLE_USER_CHECK
190         if(i_user.s && rr_obb.use_outbound)
191         {
192                 LM_ERR("cannot use \"ignore_user\" with outbound\n");
193                 return -1;
194         }
195 #endif
196
197         if (add_username != 0 && rr_obb.use_outbound)
198         {
199                 LM_ERR("cannot use \"add_username\" with outbound\n");
200                 return -1;
201         }
202
203         if (custom_user_spec.s) {
204                 if (pv_parse_spec(&custom_user_spec, &custom_user_avp) == 0
205                                 && (custom_user_avp.type != PVT_AVP)) {
206                         LM_ERR("malformed or non AVP custom_user "
207                                         "AVP definition in '%.*s'\n", custom_user_spec.len,custom_user_spec.s);
208                         return -1;
209                 }
210         }
211
212         init_custom_user(custom_user_spec.s ? &custom_user_avp : 0);
213
214         return 0;
215 }
216
217
218 static void mod_destroy(void)
219 {
220         destroy_rrcb_lists();
221 }
222
223
224 static int it_list_fixup(void** param, int param_no)
225 {
226         pv_elem_t *model;
227         str s;
228         if(*param)
229         {
230                 s.s = (char*)(*param); s.len = strlen(s.s);
231                 if(pv_parse_format(&s, &model)<0)
232                 {
233                         LM_ERR("wrong format[%s]\n",(char*)(*param));
234                         return E_UNSPEC;
235                 }
236                 *param = (void*)model;
237         }
238         return 0;
239 }
240
241
242 static int direction_fixup(void** param, int param_no)
243 {
244         char *s;
245         int n;
246
247         if (!append_fromtag) {
248                 LM_ERR("usage of \"is_direction\" function requires parameter"
249                                 "\"append_fromtag\" enabled!!");
250                 return E_CFG;
251         }
252         if (param_no==1) {
253                 n = 0;
254                 s = (char*) *param;
255                 if ( strcasecmp(s,"downstream")==0 ) {
256                         n = RR_FLOW_DOWNSTREAM;
257                 } else if ( strcasecmp(s,"upstream")==0 ) {
258                         n = RR_FLOW_UPSTREAM;
259                 } else {
260                         LM_ERR("unknown direction '%s'\n",s);
261                         return E_CFG;
262                 }
263                 /* free string */
264                 pkg_free(*param);
265                 /* replace it with the flag */
266                 *param = (void*)(unsigned long)n;
267         }
268         return 0;
269 }
270
271 /**
272  * wrapper for loose_route(msg)
273  */
274 static int w_loose_route(struct sip_msg *msg, char *p1, char *p2)
275 {
276         return loose_route(msg);
277 }
278
279 /**
280  * wrapper for loose_route(msg)
281  */
282 static int w_loose_route_preloaded(sip_msg_t *msg, char *p1, char *p2)
283 {
284         int ret;
285         ret = loose_route(msg);
286         if(ret == RR_PRELOADED) {
287                 return 1;
288         }
289         return -1;
290 }
291
292 /**
293  * wrapper for loose_route_(msg)
294  */
295 static int ki_loose_route_preloaded(sip_msg_t *msg)
296 {
297         int ret;
298         ret = loose_route(msg);
299         if(ret == RR_PRELOADED) {
300                 return 1;
301         }
302         return -1;
303 }
304
305 /**
306  * common wrapper for record_route(msg, sparams)
307  */
308 static int ki_record_route_params(sip_msg_t *msg, str *sparams)
309 {
310         if (msg->msg_flags & FL_RR_ADDED) {
311                 LM_ERR("Double attempt to record-route\n");
312                 return -1;
313         }
314
315         if ( record_route( msg, sparams )<0 )
316                 return -1;
317
318         if(get_route_type()!=BRANCH_ROUTE)
319                 msg->msg_flags |= FL_RR_ADDED;
320         return 1;
321 }
322
323 static int ki_record_route(sip_msg_t *msg)
324 {
325         return ki_record_route_params( msg, 0 );
326 }
327
328 /**
329  * wrapper for record_route_preset(msg, addr1, addr2)
330  */
331 static int ki_record_route_preset(sip_msg_t *msg, str *addr1, str *addr2)
332 {
333         if (msg->msg_flags & FL_RR_ADDED) {
334                 LM_ERR("Double attempt to record-route\n");
335                 return -1;
336         }
337         if (addr2 && addr2->len>0 && !enable_double_rr) {
338                 LM_ERR("Attempt to double record-route while 'enable_double_rr' param is disabled\n");
339                 return -1;
340         }
341
342         if ( record_route_preset(msg, addr1)<0 )
343                 return -1;
344
345         if (!addr2 || addr2->len<=0)
346                 goto done;
347
348         if ( record_route_preset(msg, addr2)<0 )
349                 return -1;
350
351 done:
352         msg->msg_flags |= FL_RR_ADDED;
353         return 1;
354
355 }
356
357 /**
358  * wrapper for record_route_preset(msg, addr1)
359  */
360 static int ki_record_route_preset_one(sip_msg_t *msg, str *addr1)
361 {
362         if (msg->msg_flags & FL_RR_ADDED) {
363                 LM_ERR("Double attempt to record-route\n");
364                 return -1;
365         }
366
367         if ( record_route_preset(msg, addr1)<0 ) {
368                 return -1;
369         }
370
371         msg->msg_flags |= FL_RR_ADDED;
372         return 1;
373
374 }
375
376 /**
377  * config wrapper for record_route(msg, params)
378  */
379 static int w_record_route(struct sip_msg *msg, char *key, char *bar)
380 {
381         str s;
382
383         if (msg->msg_flags & FL_RR_ADDED) {
384                 LM_ERR("Double attempt to record-route\n");
385                 return -1;
386         }
387
388         if (key && pv_printf_s(msg, (pv_elem_t*)key, &s)<0) {
389                 LM_ERR("failed to print the format\n");
390                 return -1;
391         }
392
393         return ki_record_route_params( msg, key?&s:0 );
394 }
395
396
397 static int w_record_route_preset(struct sip_msg *msg, char *key, char *key2)
398 {
399         str s;
400
401         if (msg->msg_flags & FL_RR_ADDED) {
402                 LM_ERR("Double attempt to record-route\n");
403                 return -1;
404         }
405         if (key2 && !enable_double_rr) {
406                 LM_ERR("Attempt to double record-route while 'enable_double_rr' param is disabled\n");
407                 return -1;
408         }
409
410         if (pv_printf_s(msg, (pv_elem_t*)key, &s)<0) {
411                 LM_ERR("failed to print the format\n");
412                 return -1;
413         }
414         if ( record_route_preset( msg, &s)<0 )
415                 return -1;
416
417         if (!key2)
418                 goto done;
419
420         if (pv_printf_s(msg, (pv_elem_t*)key2, &s)<0) {
421                 LM_ERR("failed to print the format\n");
422                 return -1;
423         }
424         if ( record_route_preset( msg, &s)<0 )
425                 return -1;
426
427 done:
428         msg->msg_flags |= FL_RR_ADDED;
429         return 1;
430 }
431
432
433 /**
434  * wrapper for record_route(msg, params)
435  */
436 static int w_record_route_advertised_address(struct sip_msg *msg, char *addr, char *bar)
437 {
438         str s;
439
440         if (msg->msg_flags & FL_RR_ADDED) {
441                 LM_ERR("Double attempt to record-route\n");
442                 return -1;
443         }
444
445         if (pv_printf_s(msg, (pv_elem_t*)addr, &s) < 0) {
446                 LM_ERR("failed to print the format\n");
447                 return -1;
448         }
449         if ( record_route_advertised_address( msg, &s ) < 0)
450                 return -1;
451
452         msg->msg_flags |= FL_RR_ADDED;
453         return 1;
454 }
455
456 /**
457  *
458  */
459 static int ki_record_route_advertised_address(sip_msg_t *msg, str *addr)
460 {
461         if (msg->msg_flags & FL_RR_ADDED) {
462                 LM_ERR("Double attempt to record-route\n");
463                 return -1;
464         }
465
466         if ( record_route_advertised_address(msg, addr) < 0)
467                 return -1;
468
469         msg->msg_flags |= FL_RR_ADDED;
470         return 1;
471 }
472
473
474 static int w_add_rr_param(struct sip_msg *msg, char *key, char *foo)
475 {
476         str s;
477
478         if (pv_printf_s(msg, (pv_elem_t*)key, &s)<0) {
479                 LM_ERR("failed to print the format\n");
480                 return -1;
481         }
482         return ((add_rr_param( msg, &s)==0)?1:-1);
483 }
484
485
486 static int ki_add_rr_param(sip_msg_t *msg, str *sparam)
487 {
488         return ((add_rr_param( msg, sparam)==0)?1:-1);
489 }
490
491
492 static int w_check_route_param(struct sip_msg *msg,char *re, char *foo)
493 {
494         return ((check_route_param(msg,(regex_t*)re)==0)?1:-1);
495 }
496
497
498 static int ki_check_route_param(sip_msg_t *msg, str *sre)
499 {
500         int ret;
501         regex_t re;
502
503         if (regcomp(&re, sre->s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)) {
504                 LM_ERR("bad re %s\n", sre->s);
505                 return -1;
506         }
507         ret = check_route_param(msg, &re);
508         regfree(&re);
509
510         return ((ret==0)?1:-1);
511 }
512
513
514
515 static int w_is_direction(struct sip_msg *msg,char *dir, char *foo)
516 {
517         return ((is_direction(msg,(int)(long)dir)==0)?1:-1);
518 }
519
520 static int ki_is_direction(sip_msg_t *msg, str *dir)
521 {
522         int n;
523
524         if (!append_fromtag) {
525                 LM_ERR("usage of \"is_direction\" function requires parameter"
526                                 "\"append_fromtag\" enabled!!");
527                 return E_CFG;
528         }
529
530         if (dir->len==10 && strncasecmp(dir->s, "downstream", 10)==0) {
531                 n = RR_FLOW_DOWNSTREAM;
532         } else if (dir->len==8 && strncasecmp(dir->s, "upstream", 8)==0) {
533                 n = RR_FLOW_UPSTREAM;
534         } else {
535                 LM_ERR("unknown direction '%.*s' - use 'downstream' or 'upstream'\n",
536                                 dir->len, dir->s);
537                 return E_CFG;
538         }
539
540         return ((is_direction(msg,n)==0)?1:-1);
541 }
542
543 /*
544  * Return the URI of the topmost Route-Header.
545  */
546 static int
547 pv_get_route_uri_f(struct sip_msg *msg, pv_param_t *param,
548                 pv_value_t *res)
549 {
550         struct hdr_field* hdr;
551         rr_t* rt;
552         str uri;
553
554         if (!msg) {
555                 LM_ERR("No message?!?\n");
556                 return -1;
557         }
558
559         /* Parse the message until the First-Route-Header: */
560         if (parse_headers(msg, HDR_ROUTE_F, 0) == -1) {
561                 LM_ERR("while parsing message\n");
562                 return -1;
563         }
564
565         if (!msg->route) {
566                 LM_INFO("No route header present.\n");
567                 return -1;
568         }
569         hdr = msg->route;
570
571         /* Parse the contents of the header: */
572         if (parse_rr(hdr) == -1) {
573                 LM_ERR("Error while parsing Route header\n");
574                 return -1;
575         }
576
577
578         /* Retrieve the Route-Header */
579         rt = (rr_t*)hdr->parsed;
580         uri = rt->nameaddr.uri;
581
582         return pv_get_strval(msg, param, res, &uri);
583 }
584
585 static void free_rr_lump(struct lump **list)
586 {
587         struct lump *prev_lump, *lump, *a, *foo, *next;
588         int first_shmem;
589
590         first_shmem=1;
591         next=0;
592         prev_lump=0;
593         for(lump=*list;lump;lump=next) {
594                 next=lump->next;
595                 if (lump->type==HDR_RECORDROUTE_T) {
596                         /* may be called from railure_route */
597                         /* if (lump->flags & (LUMPFLAG_DUPED|LUMPFLAG_SHMEM)){
598                                 LOG(L_CRIT, "BUG: free_rr_lmp: lump %p, flags %x\n",
599                                                 lump, lump->flags);
600                         */      /* ty to continue */
601                         /*}*/
602                         a=lump->before;
603                         while(a) {
604                                 foo=a; a=a->before;
605                                 if (!(foo->flags&(LUMPFLAG_DUPED|LUMPFLAG_SHMEM)))
606                                         free_lump(foo);
607                                 if (!(foo->flags&LUMPFLAG_SHMEM))
608                                         pkg_free(foo);
609                         }
610                         a=lump->after;
611                         while(a) {
612                                 foo=a; a=a->after;
613                                 if (!(foo->flags&(LUMPFLAG_DUPED|LUMPFLAG_SHMEM)))
614                                         free_lump(foo);
615                                 if (!(foo->flags&LUMPFLAG_SHMEM))
616                                         pkg_free(foo);
617                         }
618
619                         if (first_shmem && (lump->flags&LUMPFLAG_SHMEM)) {
620                                 /* This is the first element of the
621                                 shmemzied lump list, we can not unlink it!
622                                 It wound corrupt the list otherwise if we
623                                 are in failure_route. -- No problem, only the
624                                 anchor is left in the list */
625
626                                 LM_DBG("lump %p is left in the list\n",
627                                                 lump);
628
629                                 if (lump->len)
630                                         LM_CRIT("lump %p can not be removed, but len=%d\n",
631                                                 lump, lump->len);
632
633                                 prev_lump=lump;
634                         } else {
635                                 if (prev_lump) prev_lump->next = lump->next;
636                                 else *list = lump->next;
637                                 if (!(lump->flags&(LUMPFLAG_DUPED|LUMPFLAG_SHMEM)))
638                                         free_lump(lump);
639                                 if (!(lump->flags&LUMPFLAG_SHMEM)) {
640                                         pkg_free(lump);
641                                         lump = 0;
642                                 }
643                         }
644                 } else {
645                         /* store previous position */
646                         prev_lump=lump;
647                 }
648                 if (first_shmem && lump && (lump->flags&LUMPFLAG_SHMEM))
649                         first_shmem=0;
650         }
651 }
652
653 /*
654  * Remove Record-Route header from message lumps
655  */
656 static int w_remove_record_route(sip_msg_t* _m, char* _s1, char* _s2)
657 {
658         free_rr_lump(&(_m->add_rm));
659         return 1;
660 }
661
662 /*
663  * Remove Record-Route header from message lumps
664  */
665 static int remove_record_route(sip_msg_t* _m)
666 {
667         free_rr_lump(&(_m->add_rm));
668         return 1;
669 }
670
671
672 /**
673  *
674  */
675 static int pv_get_to_tag_initial(sip_msg_t *msg, pv_param_t *param,
676                 pv_value_t *res)
677 {
678         struct to_body *xto;
679         if(msg==NULL)
680                 return -1;
681
682         if(msg->to==NULL && parse_headers(msg, HDR_TO_F, 0)==-1) {
683                 LM_ERR("cannot parse To header\n");
684                 return pv_get_null(msg, param, res);
685         }
686         if(msg->to==NULL || get_to(msg)==NULL) {
687                 LM_DBG("no To header\n");
688                 return pv_get_null(msg, param, res);
689         }
690         xto = get_to(msg);
691
692         if(is_direction(msg, RR_FLOW_UPSTREAM)==0) {
693                 if(parse_from_header(msg)<0) {
694                         LM_ERR("cannot parse From header\n");
695                         return pv_get_null(msg, param, res);
696                 }
697                 if(msg->from==NULL || get_from(msg)==NULL) {
698                         LM_DBG("no From header\n");
699                         return pv_get_null(msg, param, res);
700                 }
701                 xto = get_from(msg);
702         }
703
704         if (xto->tag_value.s==NULL || xto->tag_value.len<=0) {
705                 LM_DBG("no Tag parameter\n");
706                 return pv_get_null(msg, param, res);
707         }
708         return pv_get_strval(msg, param, res, &xto->tag_value);
709 }
710
711 /**
712  *
713  */
714 static int pv_get_from_tag_initial(sip_msg_t *msg, pv_param_t *param,
715                 pv_value_t *res)
716 {
717         struct to_body *xto;
718         if(msg==NULL)
719                 return -1;
720
721         if(parse_from_header(msg)<0) {
722                 LM_ERR("cannot parse From header\n");
723                 return pv_get_null(msg, param, res);
724         }
725         if(msg->from==NULL || get_from(msg)==NULL) {
726                 LM_DBG("no From header\n");
727                 return pv_get_null(msg, param, res);
728         }
729         xto = get_from(msg);
730
731         if(is_direction(msg, RR_FLOW_UPSTREAM)==0) {
732                 if(msg->to==NULL && parse_headers(msg, HDR_TO_F, 0)==-1) {
733                         LM_ERR("cannot parse To header\n");
734                         return pv_get_null(msg, param, res);
735                 }
736                 if(msg->to==NULL || get_to(msg)==NULL) {
737                         LM_DBG("no To header\n");
738                         return pv_get_null(msg, param, res);
739                 }
740                 xto = get_to(msg);
741         }
742
743         if (xto->tag_value.s==NULL || xto->tag_value.len<=0) {
744                 LM_DBG("no Tag parameter\n");
745                 return pv_get_null(msg, param, res);
746         }
747         return pv_get_strval(msg, param, res, &xto->tag_value);
748 }
749
750 /**
751  *
752  */
753 static int pv_parse_rdir_name(pv_spec_p sp, str *in)
754 {
755         if(sp==NULL || in==NULL || in->len<=0)
756                 return -1;
757
758         switch(in->len)
759         {
760                 case 2:
761                         if(strncmp(in->s, "id", 2)==0)
762                                 sp->pvp.pvn.u.isname.name.n = 0;
763                         else goto error;
764                 break;
765                 case 4:
766                         if(strncmp(in->s, "name", 4)==0)
767                                 sp->pvp.pvn.u.isname.name.n = 1;
768                         else goto error;
769                 break;
770                 default:
771                         goto error;
772         }
773         sp->pvp.pvn.type = PV_NAME_INTSTR;
774         sp->pvp.pvn.u.isname.type = 0;
775
776         return 0;
777
778 error:
779         LM_ERR("unknown PV af key: %.*s\n", in->len, in->s);
780         return -1;
781 }
782
783 static str pv_rr_flow_list[] = {
784                 { "downstream",  10 },
785                 { "upstream",    8  },
786                 { 0, 0 }
787         };
788
789 /**
790  *
791  */
792 static int pv_get_rdir(sip_msg_t *msg, pv_param_t *param, pv_value_t *res)
793 {
794         if(msg==NULL || param==NULL)
795                 return -1;
796
797         switch(param->pvn.u.isname.name.n)
798         {
799                 case 1:
800                         if(is_direction(msg, RR_FLOW_UPSTREAM)==0)
801                                 return pv_get_strval(msg, param, res, &pv_rr_flow_list[1]);
802                         return pv_get_strval(msg, param, res, &pv_rr_flow_list[0]);
803                 default:
804                         if(is_direction(msg, RR_FLOW_UPSTREAM)==0)
805                                 return pv_get_uintval(msg, param, res, RR_FLOW_UPSTREAM);
806                         return pv_get_uintval(msg, param, res, RR_FLOW_DOWNSTREAM);
807         }
808 }
809
810
811 /**
812  *
813  */
814 static int ki_rr_next_hop_route(sip_msg_t *msg)
815 {
816         if(msg->msg_flags & FL_ROUTE_ADDR) {
817                 return 1;
818         }
819         return -1;
820 }
821
822 /**
823  *
824  */
825 static int w_rr_next_hop_route(sip_msg_t *msg, char *p1, char *p2)
826 {
827         return ki_rr_next_hop_route(msg);
828 }
829
830 /**
831  *
832  */
833 /* clang-format off */
834 static sr_kemi_t sr_kemi_rr_exports[] = {
835         { str_init("rr"), str_init("record_route"),
836                 SR_KEMIP_INT, ki_record_route,
837                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
838                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
839         },
840         { str_init("rr"), str_init("record_route_params"),
841                 SR_KEMIP_INT, ki_record_route_params,
842                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
843                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
844         },
845         { str_init("rr"), str_init("loose_route"),
846                 SR_KEMIP_INT, loose_route,
847                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
848                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
849         },
850         { str_init("rr"), str_init("loose_route_preloaded"),
851                 SR_KEMIP_INT, ki_loose_route_preloaded,
852                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
853                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
854         },
855         { str_init("rr"), str_init("remove_record_route"),
856                 SR_KEMIP_INT, remove_record_route,
857                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
858                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
859         },
860         { str_init("rr"), str_init("add_rr_param"),
861                 SR_KEMIP_INT, ki_add_rr_param,
862                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
863                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
864         },
865         { str_init("rr"), str_init("check_route_param"),
866                 SR_KEMIP_INT, ki_check_route_param,
867                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
868                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
869         },
870         { str_init("rr"), str_init("is_direction"),
871                 SR_KEMIP_INT, ki_is_direction,
872                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
873                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
874         },
875         { str_init("rr"), str_init("record_route_preset_one"),
876                 SR_KEMIP_INT, ki_record_route_preset_one,
877                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
878                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
879         },
880         { str_init("rr"), str_init("record_route_preset"),
881                 SR_KEMIP_INT, ki_record_route_preset,
882                 { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
883                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
884         },
885         { str_init("rr"), str_init("record_route_advertised_address"),
886                 SR_KEMIP_INT, ki_record_route_advertised_address,
887                 { SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
888                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
889         },
890         { str_init("rr"), str_init("next_hop_route"),
891                 SR_KEMIP_INT, ki_rr_next_hop_route,
892                 { SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
893                         SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
894         },
895         { {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
896 };
897 /* clang-format on */
898
899 /**
900  *
901  */
902 int mod_register(char *path, int *dlflags, void *p1, void *p2)
903 {
904         sr_kemi_modules_add(sr_kemi_rr_exports);
905         return 0;
906 }