diff --git a/src/Makefile.groups b/src/Makefile.groups index 251a191e771..a8ae0a3109e 100644 --- a/src/Makefile.groups +++ b/src/Makefile.groups @@ -23,7 +23,7 @@ mod_list_extra=avp auth_diameter call_control call_obj dmq domainpolicy msrp \ carrierroute pdb qos sca seas sms sst timer tmrec uac_redirect \ xhttp xhttp_rpc xprint jsonrpcs nosip dmq_usrloc statsd rtjson \ log_custom keepalive ss7ops app_sqlang acc_diameter evrexec \ - sipjson xhttp_prom + sipjson lrkproxy xhttp_prom # - common modules depending on database mod_list_db=acc alias_db auth_db avpops cfg_db db_text db_flatstore \ diff --git a/src/modules/ctl/io_listener.c b/src/modules/ctl/io_listener.c index 93ce89c9483..ac8f64fc90a 100644 --- a/src/modules/ctl/io_listener.c +++ b/src/modules/ctl/io_listener.c @@ -495,7 +495,7 @@ static int handle_stream_read(struct stream_connection* s_c, int idx) DBG("handle_stream read: eof on %s\n", s_c->parent->name); goto close_connection; } - LM_INFO("bytes read: %d\n", bytes_read); + LM_DBG("bytes read: %d\n", bytes_read); r->end+=bytes_read; if (bytes_read && (bytes_readbytes_to_go)){ r->bytes_to_go-=bytes_read; @@ -515,7 +515,7 @@ static int handle_stream_read(struct stream_connection* s_c, int idx) /* error while processing the packet => close the connection */ goto close_connection; } - LM_INFO("bytes processed: %d\n", bytes_processed); + LM_DBG("bytes processed: %d\n", bytes_processed); r->proc+=bytes_processed; r->bytes_to_go=bytes_needed; if (bytes_needed>0){ diff --git a/src/modules/htable/htable.c b/src/modules/htable/htable.c index d05cf5227d1..1bb36657def 100644 --- a/src/modules/htable/htable.c +++ b/src/modules/htable/htable.c @@ -484,7 +484,7 @@ static int ht_rm_items(sip_msg_t* msg, str* hname, str* op, str *val, case 2: if(strncmp(op->s, "re", 2)==0) { isval.s = *val; - if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &ht->name, NULL, + if ((ht->dmqreplicate > 0) && ht_dmq_replicate_action(HT_DMQ_RM_CELL_RE, &ht->name, NULL, AVP_VAL_STR, &isval, mkey)!=0) { LM_ERR("dmq relication failed (op %d)\n", mkey); } @@ -494,7 +494,7 @@ static int ht_rm_items(sip_msg_t* msg, str* hname, str* op, str *val, return 1; } else if(strncmp(op->s, "sw", 2)==0) { isval.s = *val; - if (ht_dmq_replicate_action(HT_DMQ_RM_CELL_SW, &ht->name, NULL, + if ((ht->dmqreplicate > 0) &&ht_dmq_replicate_action(HT_DMQ_RM_CELL_SW, &ht->name, NULL, AVP_VAL_STR, &isval, mkey)!=0) { LM_ERR("dmq relication failed (op %d)\n", mkey); } diff --git a/src/modules/ims_diameter_server/ims_diameter_server.c b/src/modules/ims_diameter_server/ims_diameter_server.c index c7fe941b001..fae5f58ce9a 100644 --- a/src/modules/ims_diameter_server/ims_diameter_server.c +++ b/src/modules/ims_diameter_server/ims_diameter_server.c @@ -280,6 +280,10 @@ int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* comman } LM_DBG("Peer %.*s\n", s_peer.len, s_peer.s); } + if (get_str_fparam(&s_message, msg, (fparam_t*)message) < 0) { + LM_ERR("failed to get Message\n"); + return -1; + } if (get_str_fparam(&s_appid, msg, (fparam_t*)appid) < 0) { LM_ERR("failed to get App-ID\n"); return -1; @@ -306,9 +310,14 @@ int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* comman session = cdpb.AAACreateSession(0); req = cdpb.AAACreateRequest(i_appid, i_commandcode, Flag_Proxyable, session); + if (session) { + cdpb.AAADropSession(session); + session = 0; + } + if (!req) goto error1; - if (addAVPsfromJSON(req, &s_message)) { + if (!addAVPsfromJSON(req, &s_message)) { LM_ERR("Failed to parse JSON Request\n"); return -1; } @@ -322,7 +331,7 @@ int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* comman } else { resp = cdpb.AAASendRecvMessageToPeer(req, &s_peer); LM_DBG("Successfully sent diameter\n"); - if (AAAmsg2json(resp, &responsejson) == 1) { + if (resp && AAAmsg2json(resp, &responsejson) == 1) { return 1; } else { LM_ERR("Failed to convert response to JSON\n"); @@ -337,7 +346,7 @@ int diameter_request(struct sip_msg * msg, char* peer, char* appid, char* comman } else { resp = cdpb.AAASendRecvMessage(req); LM_DBG("Successfully sent diameter\n"); - if (AAAmsg2json(resp, &responsejson) == 1) { + if (resp && AAAmsg2json(resp, &responsejson) == 1) { return 1; } else { LM_ERR("Failed to convert response to JSON\n"); diff --git a/src/modules/lrkproxy/Makefile b/src/modules/lrkproxy/Makefile new file mode 100644 index 00000000000..716fbbc0d00 --- /dev/null +++ b/src/modules/lrkproxy/Makefile @@ -0,0 +1,14 @@ +# +# lrkproxy module makefile +# +# +# WARNING: do not run this directly, it should be run by the main Makefile + +include ../../Makefile.defs +auto_gen= +NAME=lrkproxy.so +LIBS= + +SERLIBPATH=../../lib +include ../../Makefile.modules + diff --git a/src/modules/lrkproxy/README b/src/modules/lrkproxy/README new file mode 100644 index 00000000000..d95b5442f74 --- /dev/null +++ b/src/modules/lrkproxy/README @@ -0,0 +1,316 @@ +lrkproxy Module + +Mojtaba Esfandiari.S + + Nasim Telecom + + Copyright © 2020 Nasim Telecom Inc. + __________________________________________________________________ + + Table of Contents + + 1. Admin Guide + + 1. Overview + 2. LRKProxy Architecture + + 2.1. LRKP_Controlling Layer (LRKP_CL) + 2.2. LRKP_Transport Stateful Layer (LRKP_TSL) + + 3. Multiple LRKProxy usage + 4. Dependencies + + 4.1. Kamailio Modules + 4.2. External Libraries or Applications + 4.3. Parameters + + 4.3.1. lrkproxy_sock (string) + 4.3.2. lrkproxy_disable_tout (integer) + 4.3.3. lrkproxy_tout (integer) + 4.3.4. lrkproxy_retr (integer) + 4.3.5. lrkp_alg (integer) + 4.3.6. hash_table_tout (integer) + 4.3.7. hash_table_size (integer) + + 4.4. Functions + + 4.4.1. set_lrkproxy_set(setid) + 4.4.2. lrkproxy_manage([flags [, ip_address]]) + + List of Examples + + 1.1. Set lrkproxy_sock parameter + 1.2. Set lrkproxy_disable_tout parameter + 1.3. Set lrkproxy_tout parameter + 1.4. Set lrkproxy_retr parameter + 1.5. Set lrkp_alg parameter + 1.6. Set hash_table_tout parameter + 1.7. Set hash_table_size parameter + 1.8. set_lrkproxy_set usage + 1.9. lrkproxy_manage usage + +Chapter 1. Admin Guide + + Table of Contents + + 1. Overview + 2. LRKProxy Architecture + + 2.1. LRKP_Controlling Layer (LRKP_CL) + 2.2. LRKP_Transport Stateful Layer (LRKP_TSL) + + 3. Multiple LRKProxy usage + 4. Dependencies + + 4.1. Kamailio Modules + 4.2. External Libraries or Applications + 4.3. Parameters + + 4.3.1. lrkproxy_sock (string) + 4.3.2. lrkproxy_disable_tout (integer) + 4.3.3. lrkproxy_tout (integer) + 4.3.4. lrkproxy_retr (integer) + 4.3.5. lrkp_alg (integer) + 4.3.6. hash_table_tout (integer) + 4.3.7. hash_table_size (integer) + + 4.4. Functions + + 4.4.1. set_lrkproxy_set(setid) + 4.4.2. lrkproxy_manage([flags [, ip_address]]) + +1. Overview + + This is a module that enables media streams to be relayed via an + lrkproxy. This module works with py_lrkproxy engine in: + https://github.com/mojtabaesfandiari/pylrkproxy This module does + relaying audio streams between peers in PREROUTING netfilter-hooking + section in kernel-space linux. The LRKProxy architecture is composed of + two different layers. These layers are independent of each other. + +2. LRKProxy Architecture + + 2.1. LRKP_Controlling Layer (LRKP_CL) + 2.2. LRKP_Transport Stateful Layer (LRKP_TSL) + +2.1. LRKP_Controlling Layer (LRKP_CL) + + The first layer is developed as User-Space application that allows + User-Space to directly access and manipulate cache data buffer and + packet buffer in Kernel-Space. This layer gets all information about + creating new sessions, active sessions and tear-down sessions which is + gotten from SDP body during signaling plan and relay them to the + LRKP-Transport Stateful Layer (LRKP- TSL). + +2.2. LRKP_Transport Stateful Layer (LRKP_TSL) + + The second layer is developed in Kernel-Space as a main decision point + for RTP admission controller and Quickpath selector to where a received + packet should be forwarded with power of packet mangling framework in + the network stack. + + The LRKP_CL and LRKP-TSL could be run as independence functions on + different machines. We could have one LRKP_CL with multiple LRKP-TSL on + different machines. The LRKP_CL could works with all LRKP-TSL with + different strategies(lrkp_alg parameter). + +3. Multiple LRKProxy usage + + The LRKP_CL Layer can support multiple LRKP_TSL Layer for + balancing/distribution and control/selection purposes. + + The module allows definition of several sets of LRKP_TSL. + Load-balancing will be performed over predefine algorithm by setting + lrkp_alg parameter. + + IMPORTANT: This module does not support balancing inside a set like as + is done RTPProxy module based on the weight of each rtpproxy from the + set. The balancing would be run on different machine + +4. Dependencies + + 4.1. Kamailio Modules + 4.2. External Libraries or Applications + 4.3. Parameters + + 4.3.1. lrkproxy_sock (string) + 4.3.2. lrkproxy_disable_tout (integer) + 4.3.3. lrkproxy_tout (integer) + 4.3.4. lrkproxy_retr (integer) + 4.3.5. lrkp_alg (integer) + 4.3.6. hash_table_tout (integer) + 4.3.7. hash_table_size (integer) + + 4.4. Functions + + 4.4.1. set_lrkproxy_set(setid) + 4.4.2. lrkproxy_manage([flags [, ip_address]]) + +4.1. Kamailio Modules + + The following modules must be loaded before this module: + * tm module - (optional) if you want to have lrkproxy_manage() fully + functional + +4.2. External Libraries or Applications + + The following libraries or applications must be installed before + running Kamailio with this module loaded: + * None. + +4.3. Parameters + +4.3.1. lrkproxy_sock (string) + + Used to define the list of LRKP_TSL instances to connect to. These can + be UNIX sockets or IPv4/IPv6 UDP sockets. Each modparam entry will + insert sockets into a single set with default value set ID '0'. To + define multiple LRKP_TSL, just add the instances in each modparam. + + Default value is "NONE" (disabled). + + Example 1.1. Set lrkproxy_sock parameter +... +# single lrkproxy +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.108:8080") + +# multiple lrkproxies for LB in diffenrent machine +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.108:8080") +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.109:8080") + +... + +4.3.2. lrkproxy_disable_tout (integer) + + Once LRKP_TSL was found unreachable and marked as disabled, the LRKP_CL + module will not attempt to establish communication to LRKP_TSL for + lrkproxy_disable_tout seconds. + + Default value is "60". + + Example 1.2. Set lrkproxy_disable_tout parameter +... +modparam("lrkproxy", "lrkproxy_disable_tout", 20) +... + +4.3.3. lrkproxy_tout (integer) + + Timeout value in waiting for reply from LRKP_TSL. + + Default value is "1". + + Example 1.3. Set lrkproxy_tout parameter +... +modparam("lrkproxy", "lrkproxy_tout", 2) +... + +4.3.4. lrkproxy_retr (integer) + + How many times the LRKP_CL should retry to send and receive after + timeout was generated. + + Default value is "5". + + Example 1.4. Set lrkproxy_retr parameter +... +modparam("lrkproxy", "lrkproxy_retr", 2) +... + +4.3.5. lrkp_alg (integer) + + This parameter set the algorithm of LRKP_TSL selection. lrk_LINER=0, + lrk_RR=1 + + Default value is "0". + + Example 1.5. Set lrkp_alg parameter +... +modparam("lrkproxy", "lrkp_alg", 1) +... + +4.3.6. hash_table_tout (integer) + + Number of seconds after an lrkproxy hash table entry is marked for + deletion. By default, this parameter is set to 3600 (seconds). + + To maintain information about a selected rtp machine node, for a given + call, entries are added in a hashtable of (callid, viabranch) pairs. + When command comes, lookup callid, viabranch pairs. If found, return + chosen node. If not found, choose a new node, insert it in the hastable + and return the chosen node. + + NOTE: In the current implementation, the actual deletion happens on the + fly, while insert/remove/lookup the hastable, only for the entries in + the insert/remove/lookup path. + + NOTE: When configuring this parameter, one should consider maximum call + time VS share memory for unfinished calls. + + Default value is "3600". + + Example 1.6. Set hash_table_tout parameter +... +modparam("lrkproxy", "hash_table_tout", "3600") +... + +4.3.7. hash_table_size (integer) + + Size of the hash table. Default value is 128. + + Default value is "128". + + Example 1.7. Set hash_table_size parameter +... +modparam("lrkproxy", "hash_table_size", 256) +... + +4.4. Functions + +4.4.1. set_lrkproxy_set(setid) + + Sets the Id of the lrkproxy set to be used for the next + lrkproxy_manage() command. The parameter can be an integer or a config + variable holding an integer. + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + BRANCH_ROUTE. + + Example 1.8. set_lrkproxy_set usage +... +set_lrkproxy_set("0"); +lrkproxy_manage(); +... + +4.4.2. lrkproxy_manage([flags [, ip_address]]) + + Manage the LRKProxy session - it combines the functionality of + lrkproxy_offer(), lrkproxy_answer() and unforce_lrkproxy(), detecting + internally based on message type and method which one to execute. + + IMPORTANT:The LRKProxy just has one function relating rtp packets. It + does not support combination of functionality of lrkproxy_offer(), + lrkproxy_answer() and unforce_lrkproxy() and other etc. So you have to + just use lrkproxy_manage. + + Meaning of the parameters is as follows: + * flags - flags to turn on some features. + + internal,external - The shorthand of this flag is "ie". This + can be used to relay media sessions between two different NIC + from internal to external path. + + external,internal - The shorthand of this flag is "ei". This + can be used to relay media sessions between two different NIC + from external to internal path. + * ip_address - new SDP IP address.This optional parameter is under + development. + + This function can be used from ANY_ROUTE. + + Example 1.9. lrkproxy_manage usage +... +lrkproxy_manage(); +//or +lrkproxy_manage("ie"); +//or +lrkproxy_manage("ei"); + +... diff --git a/src/modules/lrkproxy/doc/Makefile b/src/modules/lrkproxy/doc/Makefile new file mode 100644 index 00000000000..c8d8cd5de43 --- /dev/null +++ b/src/modules/lrkproxy/doc/Makefile @@ -0,0 +1,4 @@ +docs = lrkproxy.xml + +docbook_dir = ../../../../doc/docbook +include $(docbook_dir)/Makefile.module diff --git a/src/modules/lrkproxy/doc/lrkproxy.xml b/src/modules/lrkproxy/doc/lrkproxy.xml new file mode 100644 index 00000000000..bfc71580c77 --- /dev/null +++ b/src/modules/lrkproxy/doc/lrkproxy.xml @@ -0,0 +1,33 @@ + + + +%docentities; + +]> + + + + lrkproxy Module + &kamailioname; + + + Mojtaba + Esfandiari.S + Nasim Telecom +
+ esfandiari@nasimtelecom.com +
+
+
+ + 2020 + Nasim Telecom Inc. + +
+ + + +
diff --git a/src/modules/lrkproxy/doc/lrkproxy_admin.xml b/src/modules/lrkproxy/doc/lrkproxy_admin.xml new file mode 100644 index 00000000000..57cc2faab30 --- /dev/null +++ b/src/modules/lrkproxy/doc/lrkproxy_admin.xml @@ -0,0 +1,364 @@ + + + +%docentities; + +]> + + + + + + &adminguide; + +
+ Overview + + This is a module that enables media streams to be relayed via an + lrkproxy. This module works with py_lrkproxy engine in: + https://github.com/mojtabaesfandiari/pylrkproxy + This module does relaying audio streams between peers in + PREROUTING netfilter-hooking section in kernel-space linux. + The LRKProxy architecture is composed of two + different layers. These layers are independent of each + other. + +
+ +
+ LRKProxy Architecture +
+ LRKP_Controlling Layer (LRKP_CL) + + The first layer is developed as User-Space + application that allows User-Space to directly + access and manipulate cache data + buffer and packet buffer in Kernel-Space. This layer + gets all information about creating new sessions, + active sessions and tear-down sessions which is + gotten from SDP body during signaling plan and relay + them to the LRKP-Transport Stateful Layer (LRKP- + TSL). + +
+
+ LRKP_Transport Stateful Layer (LRKP_TSL) + + The second layer is developed in Kernel-Space as + a main decision point for RTP admission controller + and Quickpath selector to where a received packet + should be forwarded with power of packet mangling + framework in the network stack. + +
+ + The LRKP_CL and LRKP-TSL could be run as + independence functions on different machines. We + could have one LRKP_CL with multiple LRKP-TSL + on different machines. The LRKP_CL could works + with all LRKP-TSL with different strategies(lrkp_alg parameter). + +
+
+ Multiple LRKProxy usage + + The LRKP_CL Layer can support multiple LRKP_TSL Layer + for balancing/distribution and control/selection purposes. + + + The module allows definition of several sets of LRKP_TSL. + Load-balancing will be performed over predefine algorithm by setting lrkp_alg parameter. + + + + IMPORTANT: This module does not support balancing inside a set like as is done RTPProxy module based on + the weight of each rtpproxy from the set. The balancing would be run on different machine + +
+ +
+ Dependencies +
+ &kamailio; Modules + + The following modules must be loaded before this module: + + + + tm module - (optional) if you want to + have lrkproxy_manage() fully functional + + + + +
+
+ External Libraries or Applications + + The following libraries or applications must be installed before + running &kamailio; with this module loaded: + + + + None. + + + + +
+
+ Parameters +
+ <varname>lrkproxy_sock</varname> (string) + + Used to define the list of LRKP_TSL instances to connect to. These can + be UNIX sockets or IPv4/IPv6 UDP sockets. Each modparam entry will + insert sockets into a single set with default value set ID '0'. + To define multiple LRKP_TSL, just add the instances in each modparam. + + + + Default value is NONE (disabled). + + + + Set <varname>lrkproxy_sock</varname> parameter + +... +# single lrkproxy +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.108:8080") + +# multiple lrkproxies for LB in diffenrent machine +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.108:8080") +modparam("lrkproxy", "lrkproxy_sock", "udp:192.168.122.109:8080") + +... + + +
+
+ <varname>lrkproxy_disable_tout</varname> (integer) + + Once LRKP_TSL was found unreachable and marked as disabled, the + LRKP_CL module will not attempt to establish communication to LRKP_TSL + for lrkproxy_disable_tout seconds. + + + + Default value is 60. + + + + Set <varname>lrkproxy_disable_tout</varname> parameter + +... +modparam("lrkproxy", "lrkproxy_disable_tout", 20) +... + + +
+
+ <varname>lrkproxy_tout</varname> (integer) + + Timeout value in waiting for reply from LRKP_TSL. + + + + Default value is 1. + + + + Set <varname>lrkproxy_tout</varname> parameter + +... +modparam("lrkproxy", "lrkproxy_tout", 2) +... + + +
+
+ <varname>lrkproxy_retr</varname> (integer) + + How many times the LRKP_CL should retry to send and receive after + timeout was generated. + + + + Default value is 5. + + + + Set <varname>lrkproxy_retr</varname> parameter + +... +modparam("lrkproxy", "lrkproxy_retr", 2) +... + + +
+
+ <varname>lrkp_alg</varname> (integer) + + This parameter set the algorithm of LRKP_TSL selection. + lrk_LINER=0, + lrk_RR=1 + + + + Default value is 0. + + + + Set <varname>lrkp_alg</varname> parameter + +... +modparam("lrkproxy", "lrkp_alg", 1) +... + + +
+ +
+ <varname>hash_table_tout</varname> (integer) + + Number of seconds after an lrkproxy hash table entry is marked for + deletion. By default, this parameter is set to 3600 (seconds). + + + To maintain information about a selected rtp machine node, for a given + call, entries are added in a hashtable of (callid, viabranch) pairs. When + command comes, lookup callid, viabranch pairs. If found, return chosen node. If not + found, choose a new node, insert it in the hastable and return the + chosen node. + + + NOTE: In the current implementation, the actual deletion happens on the + fly, while insert/remove/lookup the hastable, only for the entries in + the insert/remove/lookup path. + + + NOTE: When configuring this parameter, one should consider maximum call + time VS share memory for unfinished calls. + + + + Default value is 3600. + + + + Set <varname>hash_table_tout</varname> parameter + +... +modparam("lrkproxy", "hash_table_tout", "3600") +... + + +
+
+ <varname>hash_table_size</varname> (integer) + + Size of the hash table. Default value is 128. + + + + Default value is 128. + + + + Set <varname>hash_table_size</varname> parameter + +... +modparam("lrkproxy", "hash_table_size", 256) +... + + +
+
+
+ Functions +
+ + <function moreinfo="none">set_lrkproxy_set(setid)</function> + + + Sets the Id of the lrkproxy set to be used for the next + lrkproxy_manage() command. The parameter can be an integer or a config + variable holding an integer. + + + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, + BRANCH_ROUTE. + + + <function>set_lrkproxy_set</function> usage + +... +set_lrkproxy_set("0"); +lrkproxy_manage(); +... + + +
+
+ + <function moreinfo="none">lrkproxy_manage([flags [, ip_address]])</function> + + + Manage the LRKProxy session - it combines the functionality of + lrkproxy_offer(), lrkproxy_answer() and unforce_lrkproxy(), detecting + internally based on message type and method which one to execute. + + + IMPORTANT:The LRKProxy just has one function relating rtp packets. + It does not support combination of functionality of lrkproxy_offer(), + lrkproxy_answer() and unforce_lrkproxy() and other etc. + So you have to just use lrkproxy_manage. + + Meaning of the parameters is as follows: + + + + flags - flags to turn on some features. + + + + internal,external - The shorthand of this flag is "ie". + This can be used to relay media sessions between two different NIC from internal to external path. + + + + + external,internal - The shorthand of this flag is "ei". + This can be used to relay media sessions between two different NIC from external to internal path. + + + + + ip_address - new SDP IP address.This optional parameter is under development. + + + + This function can be used from ANY_ROUTE. + + + <function>lrkproxy_manage</function> usage + +... +lrkproxy_manage(); +//or +lrkproxy_manage("ie"); +//or +lrkproxy_manage("ei"); + +... + + +
+ + +
+
+
diff --git a/src/modules/lrkproxy/lrkproxy.c b/src/modules/lrkproxy/lrkproxy.c new file mode 100644 index 00000000000..2c0405c8a5b --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy.c @@ -0,0 +1,1732 @@ +/* + * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include +#include +#include +#ifndef __USE_BSD +#define __USE_BSD +#endif +#include +#ifndef __FAVOR_BSD +#define __FAVOR_BSD +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../core/flags.h" +#include "../../core/sr_module.h" +#include "../../core/dprint.h" +#include "../../core/data_lump.h" +#include "../../core/data_lump_rpl.h" +#include "../../core/error.h" +#include "../../core/forward.h" +#include "../../core/mem/mem.h" +#include "../../core/parser/parse_from.h" +#include "../../core/parser/parse_to.h" +#include "../../core/parser/parse_uri.h" +#include "../../core/parser/parser_f.h" +#include "../../core/parser/sdp/sdp.h" +#include "../../core/resolve.h" +#include "../../core/timer.h" +#include "../../core/trim.h" +#include "../../core/ut.h" +#include "../../core/pt.h" +#include "../../core/timer_proc.h" +#include "../../core/rpc.h" +#include "../../core/rpc_lookup.h" +#include "../../core/pvar.h" +#include "../../core/lvalue.h" +#include "../../core/msg_translator.h" +#include "../../core/usr_avp.h" +#include "../../core/socket_info.h" +#include "../../core/mod_fix.h" +#include "../../core/dset.h" +#include "../../core/route.h" +#include "../../core/kemi.h" +#include "../../modules/tm/tm_load.h" +#include "lrkproxy.h" +#include "lrkproxy_hash.h" +#include "lrkproxy_funcs.h" + +MODULE_VERSION + + +#if !defined(AF_LOCAL) +#define AF_LOCAL AF_UNIX +#endif +#if !defined(PF_LOCAL) +#define PF_LOCAL PF_UNIX +#endif + +///* NAT UAC test constants */ +//#define NAT_UAC_TEST_C_1918 0x01 +//#define NAT_UAC_TEST_RCVD 0x02 +//#define NAT_UAC_TEST_V_1918 0x04 +//#define NAT_UAC_TEST_S_1918 0x08 +//#define NAT_UAC_TEST_RPORT 0x10 + +#define DEFAULT_LRKP_SET_ID 0 +static str DEFAULT_LRKP_SET_ID_STR = str_init("0"); + +//#define RPC_DEFAULT_NATPING_STATE 1 + +#define RPC_MIN_RECHECK_TICKS 0 +#define RPC_MAX_RECHECK_TICKS (unsigned int)-1 + + +/* Supported version of the LRK proxy command protocol */ +#define SUP_CPROTOVER "20190708" +/* Required additional version of the LRK proxy command protocol */ +#define REQ_CPROTOVER "20190709" +/* Additional version necessary for re-packetization support */ +#define REP_CPROTOVER "20190708" +#define PTL_CPROTOVER "20190708" + +#define CPORT "22333" +#define HASH_SIZE 128 + +static char *gencookie(); +static int lrkp_test(struct lrkp_node*); +static int lrkp_get_config(struct lrkp_node *node); +static int lrkp_set_conntrack_rule(struct lrkproxy_hash_entry *e); + + +static int lrkproxy_force(struct sip_msg *msg, const char *flags, enum lrk_operation op, int more); +static int lrkproxy_unforce(struct sip_msg *msg, const char *flags, enum lrk_operation op, int more); + +static int lrkproxy_manage0(struct sip_msg *msg, char *flags, char *ip); +static int lrkproxy_manage1(struct sip_msg *msg, char *flags, char *ip); +static int lrkproxy_manage2(struct sip_msg *msg, char *flags, char *ip); + +static int change_media_sdp(sip_msg_t *msg, struct lrkproxy_hash_entry *e, const char *flags, enum lrk_operation op); + +static int add_lrkproxy_socks(struct lrkp_set * lrkp_list, char * lrkproxy); +static int fixup_set_id(void ** param, int param_no); +static int set_lrkproxy_set_f(struct sip_msg * msg, char * str1, char * str2); + +static struct lrkp_set * select_lrkp_set(int id_set); + +static int lrkproxy_set_store(modparam_t type, void * val); +static int lrkproxy_add_lrkproxy_set( char * lrk_proxies); + +static int mod_init(void); +static int child_init(int); +static void mod_destroy(void); + +/* Pseudo-Variables */ +//static int pv_get_lrkstat_f(struct sip_msg *, pv_param_t *, pv_value_t *); + +static int lrkproxy_disable_tout = 60; +static int lrkproxy_retr = 5; +static int lrkproxy_tout = 1; +static pid_t mypid; +static unsigned int myseqn = 0; +//static str nolrkproxy_str = str_init("a=nolrkproxy:yes"); +//static str extra_id_pv_param = {NULL, 0}; + +static char ** lrkp_strings=0; +static int lrkp_sets=0; /*used in lrkproxy_set_store()*/ +static int lrkp_set_count = 0; +static unsigned int current_msg_id = (unsigned int)-1; +/* LRK proxy balancing list */ +struct lrkp_set_head * lrkp_set_list =0; +struct lrkp_set * selected_lrkp_set =0; +struct lrkp_set * default_lrkp_set=0; +struct lrkp_node *selected_lrkp_node = 0; +int lrkp_algorithm = LRK_LINER; +static int hash_table_size = 0; +static int hash_table_tout = 3600; + + + +//static char *ice_candidate_priority_avp_param = NULL; +//static int ice_candidate_priority_avp_type; +//static int_str ice_candidate_priority_avp; +//static str lrk_inst_pv_param = {NULL, 0}; +//static pv_spec_t *lrk_inst_pvar = NULL; + +/* array with the sockets used by lrkproxy (per process)*/ +static unsigned int lrkp_no = 0; +static int *lrkp_socks = 0; + + +typedef struct lrkp_set_link { + struct lrkp_set *rset; + pv_spec_t *rpv; +} lrkp_set_link_t; + +/* tm */ +static struct tm_binds tmb; + +/*0-> disabled, 1 ->enabled*/ +//unsigned int *natping_state=0; + +static cmd_export_t cmds[] = { + + {"set_lrkproxy_set", (cmd_function)set_lrkproxy_set_f, 1, + fixup_set_id, 0, + ANY_ROUTE}, + {"lrkproxy_manage", (cmd_function)lrkproxy_manage0, 0, + 0, 0, + ANY_ROUTE}, + {"lrkproxy_manage", (cmd_function)lrkproxy_manage1, 1, + fixup_spve_null, fixup_free_spve_null, + ANY_ROUTE}, + {"lrkproxy_manage", (cmd_function)lrkproxy_manage2, 2, + fixup_spve_spve, fixup_free_spve_spve, + ANY_ROUTE}, + + {0, 0, 0, 0, 0, 0} +}; + +static param_export_t params[] = { + {"lrkproxy_sock", PARAM_STRING|USE_FUNC_PARAM, + (void*)lrkproxy_set_store }, + {"lrkproxy_disable_tout", INT_PARAM, &lrkproxy_disable_tout }, + {"lrkproxy_retr", INT_PARAM, &lrkproxy_retr }, + {"lrkproxy_tout", INT_PARAM, &lrkproxy_tout }, + {"lrkp_alg", INT_PARAM, &lrkp_algorithm }, + {"hash_table_tout", INT_PARAM, &hash_table_tout }, + {"hash_table_size", INT_PARAM, &hash_table_size }, + + {0, 0, 0} +}; + +/** module exports */ +struct module_exports exports= { + "lrkproxy", /* module name */ + DEFAULT_DLFLAGS, /* dlopen flags */ + cmds, /* cmd exports */ + params, /* param exports */ + 0, /* RPC method exports */ + 0, /* exported pseudo-variables */ + 0, /* response handling function */ + mod_init, /* module initialization function */ + child_init, /* per-child init function */ + mod_destroy /* module destroy function */ +}; + + +static int lrkproxy_set_store(modparam_t type, void * val){ + + char * p; + int len; + + p = (char* )val; + + if(p==0 || *p=='\0'){ + return 0; + } + + if(lrkp_sets==0){ + lrkp_strings = (char**)pkg_malloc(sizeof(char*)); + if(!lrkp_strings){ + LM_ERR("no pkg memory left\n"); + return -1; + } + } else {/*realloc to make room for the current set*/ + lrkp_strings = (char**)pkg_reallocxf(lrkp_strings, + (lrkp_sets+1)* sizeof(char*)); + if(!lrkp_strings){ + LM_ERR("no pkg memory left\n"); + return -1; + } + } + + /*allocate for the current set of urls*/ + len = strlen(p); + lrkp_strings[lrkp_sets] = (char*)pkg_malloc((len+1)*sizeof(char)); + + if(!lrkp_strings[lrkp_sets]){ + LM_ERR("no pkg memory left\n"); + return -1; + } + + memcpy(lrkp_strings[lrkp_sets], p, len); + lrkp_strings[lrkp_sets][len] = '\0'; + lrkp_sets++; + + return 0; +} + +struct lrkp_set *get_lrkp_set(str *const set_name) +{ + unsigned int this_set_id; + struct lrkp_set *lrkp_list; + if (lrkp_set_list == NULL) + { + LM_ERR("lrkp set list not configured\n"); + return NULL; + } + /* Only integer set_names are valid at the moment */ + if ((set_name->s == NULL) || (set_name->len == 0)) + { + LM_ERR("Invalid set name '%.*s'\n", set_name->len, set_name->s); + return NULL; + } + if (str2int(set_name, &this_set_id) < 0) + { + LM_ERR("Invalid set name '%.*s' - must be integer\n", set_name->len, set_name->s); + return NULL; + } + + lrkp_list = select_lrkp_set(this_set_id); + + if(lrkp_list==NULL){ /*if a new id_set : add a new set of lrkp*/ + lrkp_list = shm_malloc(sizeof(struct lrkp_set)); + if(!lrkp_list){ + LM_ERR("no shm memory left\n"); + return NULL; + } + memset(lrkp_list, 0, sizeof(struct lrkp_set)); + lrkp_list->id_set = this_set_id; + if (lrkp_set_list->lset_first == NULL) + { + lrkp_set_list->lset_first = lrkp_list; + } else { + lrkp_set_list->lset_last->lset_next = lrkp_list; + } + lrkp_set_list->lset_last = lrkp_list; + lrkp_set_count++; + + if (this_set_id == DEFAULT_LRKP_SET_ID) + { + default_lrkp_set = lrkp_list; + } + } + return lrkp_list; +} + +int insert_lrkp_node(struct lrkp_set *const lrkp_list, const str *const url, const int weight, const int enable) +{ + struct lrkp_node *pnode; + + if ((pnode = shm_malloc(sizeof(struct lrkp_node) + url->len + 1)) == NULL) + { + LM_ERR("out of shm memory\n"); + return -1; + } + + memset(pnode, 0, sizeof(struct lrkp_node) + url->len + 1); + + + struct lrkp_node_conf *node_conf; + node_conf = shm_malloc(sizeof(struct lrkp_node_conf)); + if (!node_conf) + { + LM_ERR("out of shm memory\n"); + return -1; + } + + memset(node_conf, 0, sizeof(struct lrkp_node_conf)); + pnode->lrkp_n_c = node_conf; + + pnode->idx = lrkp_no++; + pnode->ln_weight = weight; + pnode->ln_umode = 0; + pnode->ln_enable = enable; + /* Permanently disable if marked as disabled */ +// pnode->ln_recheck_ticks = disabled ? RPC_MAX_RECHECK_TICKS : 0; + pnode->ln_url.s = (char*)(pnode + 1); + memcpy(pnode->ln_url.s, url->s, url->len); + pnode->ln_url.len = url->len; + + LM_DBG("url is '%.*s'\n", pnode->ln_url.len, pnode->ln_url.s); + + /* Find protocol and store address */ + pnode->ln_address = pnode->ln_url.s; + if (strncasecmp(pnode->ln_address, "udp:", 4) == 0) { + pnode->ln_umode = 1; + pnode->ln_address += 4; + } else if (strncasecmp(pnode->ln_address, "udp6:", 5) == 0) { + pnode->ln_umode = 6; + pnode->ln_address += 5; + } else if (strncasecmp(pnode->ln_address, "unix:", 5) == 0) { + pnode->ln_umode = 0; + pnode->ln_address += 5; + } + + if (lrkp_list->ln_first == NULL) + { + lrkp_list->ln_first = pnode; + } else { + lrkp_list->ln_last->ln_next = pnode; + } + lrkp_list->ln_last = pnode; + lrkp_list->lrkp_node_count++; + + return 0; +} + +static int add_lrkproxy_socks(struct lrkp_set * lrkp_list, + char * lrkproxy){ + /* Make lrk proxies list. */ + char *p, *p1, *p2, *plim; + int weight; + str url; + + p = lrkproxy; + plim = p + strlen(p); + + for(;;) { + weight = 1; + while (*p && isspace((int)*p)) + ++p; + if (p >= plim) + break; + p1 = p; + while (*p && !isspace((int)*p)) + ++p; + if (p <= p1) + break; /* may happen??? */ + /* Have weight specified? If yes, scan it */ + p2 = memchr(p1, '=', p - p1); + if (p2 != NULL) { + weight = strtoul(p2 + 1, NULL, 10); + } else { + p2 = p; + } + + url.s = p1; + url.len = (p2-p1); + insert_lrkp_node(lrkp_list, &url, weight, 0); + } + return 0; +} + +/* 0-succes + * -1 - erorr + * */ +static int lrkproxy_add_lrkproxy_set( char * lrk_proxies) +{ + char *p,*p2; + struct lrkp_set * lrkp_list; + str id_set; + + /* empty definition? */ + p= lrk_proxies; + if(!p || *p=='\0'){ + return 0; + } + + for(;*p && isspace(*p);p++); + if(*p=='\0'){ + return 0; + } + + lrk_proxies = strstr(p, "=="); + if(lrk_proxies){ + if(*(lrk_proxies +2)=='\0'){ + LM_ERR("script error -invalid lrk proxy list!\n"); + return -1; + } + + *lrk_proxies = '\0'; + p2 = lrk_proxies-1; + for(;isspace(*p2); *p2 = '\0',p2--); + id_set.s = p; id_set.len = p2 - p+1; + + if(id_set.len <= 0){ + LM_ERR("script error -invalid set_id value!\n"); + return -1; + } + + lrk_proxies+=2; + }else{ + lrk_proxies = p; + id_set = DEFAULT_LRKP_SET_ID_STR; + } + + for(;*lrk_proxies && isspace(*lrk_proxies);lrk_proxies++); + + if(!(*lrk_proxies)){ + LM_ERR("script error -empty lrkproxy list\n"); + return -1;; + } + + lrkp_list = get_lrkp_set(&id_set); + if (lrkp_list == NULL) + { + LM_ERR("Failed to get or create lrkp_list for '%.*s'\n", id_set.len, id_set.s); + return -1; + } + + if(add_lrkproxy_socks(lrkp_list, lrk_proxies)!= 0){ + return -1; + } + + return 0; +} + + +static int fixup_set_id(void ** param, int param_no) +{ + int int_val, err; + struct lrkp_set* lrkp_list; + lrkp_set_link_t *lrkl = NULL; + str s; + + lrkl = (lrkp_set_link_t*)pkg_malloc(sizeof(lrkp_set_link_t)); + if(lrkl==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(lrkl, 0, sizeof(lrkp_set_link_t)); + s.s = (char*)*param; + s.len = strlen(s.s); + + if(s.s[0] == PV_MARKER) { + int_val = pv_locate_name(&s); + if(int_val<0 || int_val!=s.len) { + LM_ERR("invalid parameter %s\n", s.s); + pkg_free(lrkl); + return -1; + } + lrkl->rpv = pv_cache_get(&s); + if(lrkl->rpv == NULL) { + LM_ERR("invalid pv parameter %s\n", s.s); + pkg_free(lrkl); + return -1; + } + } else { + int_val = str2s(*param, strlen(*param), &err); + if (err == 0) { + pkg_free(*param); + if((lrkp_list = select_lrkp_set(int_val)) ==0){ + LM_ERR("lrkp_proxy set %i not configured\n", int_val); + pkg_free(lrkl); + return E_CFG; + } + lrkl->rset = lrkp_list; + } else { + LM_ERR("bad number <%s>\n", (char *)(*param)); + pkg_free(lrkl); + return E_CFG; + } + } + *param = (void*)lrkl; + return 0; +} + + +static int +mod_init(void) +{ + int i; +// pv_spec_t avp_spec; +// str s; +// unsigned short avp_flags; + +// if(lrkproxy_rpc_init()<0) +// { +// LM_ERR("failed to register RPC commands\n"); +// return -1; +// } + + /* Configure the head of the lrkp_set_list */ + lrkp_set_list = shm_malloc(sizeof(struct lrkp_set_head)); + if (lrkp_set_list == NULL) + { + LM_ERR("no shm memory for lrkp_set_list\n"); + return -1; + } + memset(lrkp_set_list, 0, sizeof(struct lrkp_set_head)); + + + /* storing the list of lrk proxy sets in shared memory*/ + for(i=0;i callid& via-branch relation */ + if (hash_table_size < 1){ + hash_table_size = HASH_SIZE; //the default size 128 entry. + } + + if (!lrkproxy_hash_table_init(hash_table_size)) { + LM_ERR("lrkproxy_hash_table_init(%d) failed!\n", hash_table_size); + return -1; + } else { +// LM_DBG("lrkproxy_hash_table_init(%d) success!\n", hash_table_size); + LM_INFO(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>lrkproxy_hash_table_init(%d) success!\n", hash_table_size); + } + + + + /* load tm module*/ + if (load_tm_api( &tmb ) < 0) + { + LM_DBG("could not load the TM-functions - answer-offer model" + " auto-detection is disabled\n"); + memset(&tmb, 0, sizeof(struct tm_binds)); + } + + return 0; +} + + +static int +child_init(int rank) +{ + int n; + char *cp; + struct addrinfo hints, *res; + struct lrkp_set *lrkp_list; + struct lrkp_node *pnode; + + if(lrkp_set_list==NULL ) + return 0; + + /* do not init sockets for PROC_INIT and main process when fork=yes */ + if(rank==PROC_INIT || (rank==PROC_MAIN && dont_fork==0)) { + return 0; + } + + /* Iterate known LRK proxies - create sockets */ + mypid = getpid(); + + lrkp_socks = (int*)pkg_malloc( sizeof(int)*lrkp_no ); + if (lrkp_socks==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + memset(lrkp_socks, -1, sizeof(int)*lrkp_no); + + for(lrkp_list = lrkp_set_list->lset_first; lrkp_list != 0; + lrkp_list = lrkp_list->lset_next){ + + for (pnode=lrkp_list->ln_first; pnode!=0; pnode = pnode->ln_next){ + char *hostname; + + if (pnode->ln_umode == 0) { + lrkp_socks[pnode->idx] = -1; + goto rptest; + } + + /* + * This is UDP or UDP6. Detect host and port; lookup host; + * do connect() in order to specify peer address + */ + hostname = (char*)pkg_malloc(sizeof(char) * (strlen(pnode->ln_address) + 1)); + if (hostname==NULL) { + LM_ERR("no more pkg memory\n"); + return -1; + } + strcpy(hostname, pnode->ln_address); + + cp = strrchr(hostname, ':'); + if (cp != NULL) { + *cp = '\0'; + cp++; + } + if (cp == NULL || *cp == '\0') + cp = CPORT; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = 0; + hints.ai_family = (pnode->ln_umode == 6) ? AF_INET6 : AF_INET; + hints.ai_socktype = SOCK_DGRAM; + if ((n = getaddrinfo(hostname, cp, &hints, &res)) != 0) { + LM_ERR("%s\n", gai_strerror(n)); + pkg_free(hostname); + return -1; + } + pkg_free(hostname); + + lrkp_socks[pnode->idx] = socket((pnode->ln_umode == 6) + ? AF_INET6 : AF_INET, SOCK_DGRAM, 0); + if ( lrkp_socks[pnode->idx] == -1) { + LM_ERR("can't create socket\n"); + freeaddrinfo(res); + return -1; + } + + if (connect( lrkp_socks[pnode->idx], res->ai_addr, res->ai_addrlen) == -1) { + LM_ERR("can't connect to a LRK proxy\n"); + close( lrkp_socks[pnode->idx] ); + lrkp_socks[pnode->idx] = -1; + freeaddrinfo(res); + return -1; + } + freeaddrinfo(res); +rptest: + pnode->ln_enable = lrkp_test(pnode); + if (pnode->ln_enable) { //get lrk proxy config if it is enable. +// LM_INFO("lrkp_test test is calling here\n"); //enable next line. + lrkp_get_config(pnode); + } + } + } + + return 0; +} + + +static void mod_destroy(void) +{ + struct lrkp_set * crt_list, * last_list; + struct lrkp_node * crt_lrkp, *last_lrkp; + + /*free the shared memory*/ +// if (natping_state) +// shm_free(natping_state); + + if(lrkp_set_list == NULL) + return; + + for(crt_list = lrkp_set_list->lset_first; crt_list != NULL; ){ + + for(crt_lrkp = crt_list->ln_first; crt_lrkp != NULL; ){ + + last_lrkp = crt_lrkp; + crt_lrkp = last_lrkp->ln_next; + shm_free(last_lrkp); + } + + last_list = crt_list; + crt_list = last_list->lset_next; + shm_free(last_list); + } + + shm_free(lrkp_set_list); + + /* destroy the hash table */ + if (!lrkproxy_hash_table_destroy()) { + LM_ERR("lrkproxy_hash_table_destroy() failed!\n"); + } else { + LM_DBG("lrkproxy_hash_table_destroy() success!\n"); + } + +} + + +static char * gencookie(void) +{ + static char cook[34]; + + sprintf(cook, "%d_%u ", (int)mypid, myseqn); + myseqn++; + return cook; +} + +static int lrkp_test(struct lrkp_node *node) +{ + int buflen = 256; + char buf[buflen]; + struct iovec v[2] = {{NULL, 0}, {"P", 1}}; + + memset(buf, 0, buflen); + memcpy(buf, send_lrkp_command(node, v, 2, 0), buflen); + +// if (buf == NULL) { + if (!buf[0]) { + LM_ERR("can't ping the lrk proxy %s, Disable it right now.\n", node->ln_url.s); + return 0; + } + + char *resp = buf + v[0].iov_len + v[1].iov_len + 1; + if (memcmp(resp, "PONG", 4) == 0) +// LM_DBG("Recieve PONG response from lrk proxy server %s, Enable it right now.\n", node->ln_url.s); + LM_INFO("Recieve PONG response from lrk proxy server %s, Enable it right now.\n", node->ln_url.s); + + return 1; + +} + +static int lrkp_get_config(struct lrkp_node *node){ + + int buflen = 256; + char buf[buflen]; + struct iovec v[2] = {{NULL, 0}, {"G", 1}}; + struct lrkp_node_conf *lnconf = NULL; + + memset(buf, 0, buflen); + memcpy(buf, send_lrkp_command(node, v, 2, 0), buflen); + +// if (buf == NULL) { + if (!buf[0]) { + LM_ERR("can't get config of the lrk proxy %s, Disable it right now.\n", node->ln_url.s); + return 0; + } + + lnconf = (struct lrkp_node_conf *)(buf + v[0].iov_len + v[1].iov_len + 1); + + if (lnconf == NULL){ + LM_ERR("can't get config of the lrk proxy %s, Disable it right now.\n", node->ln_url.s); + return 0; + } + + + memcpy(node->lrkp_n_c, lnconf, sizeof(struct lrkp_node_conf)); + +// node->lrkp_n_c = lnconf; + LM_INFO("the lrk proxy %s is configured successfully right now.\n", node->ln_url.s); + LM_INFO("buffer internal:%s\n", node->lrkp_n_c->internal_ip); + LM_INFO("buffer external:%s\n", node->lrkp_n_c->external_ip); + LM_INFO("buffer start_port:%d\n", node->lrkp_n_c->start_port); + LM_INFO("buffer end_port:%d\n", node->lrkp_n_c->end_port); + LM_INFO("buffer current_port:%d\n", node->lrkp_n_c->current_port); + + return 1; + + +} + +static int lrkp_set_conntrack_rule(struct lrkproxy_hash_entry *e) { + int buflen = 254; + char buf[buflen]; + int v_len = 0; + + char src_ipv4[20]; + char src_port[20]; + char dst_ipv4[20]; + char dst_port[20]; + char snat_ipv4[20]; + char snat_port[20]; + char dnat_ipv4[20]; + char dnat_port[20]; + char timeout[20]; + char callid[50]; + + struct iovec v[] = { + {NULL, 0}, /* reserved (cookie) */ + {"S", 1}, /* command & common options */ + {NULL, 0}, /* src_ipv4 */ + {NULL, 0}, /* dst_ipnv4 */ + {NULL, 0}, /* snat_ipv4 */ + {NULL, 0}, /* dnat_ipv4 */ + {NULL, 0}, /* src_port */ + {NULL, 0}, /* dst_port*/ + {NULL, 0}, /* snat_port */ + {NULL, 0}, /* dnat_port*/ + {NULL, 0}, /* timeout to clear conntrack entry*/ + {NULL, 0}, /* callid of session */ + }; + + v_len += v[1].iov_len; + + //set src_ipv4 to buffer. + sprintf(src_ipv4, " %.*s ", e->src_ipv4.len, e->src_ipv4.s); + v[2].iov_base = src_ipv4; + v[2].iov_len = strlen(v[2].iov_base); + v_len += v[2].iov_len; + + //set dst_ipv4 to buffer. + sprintf(dst_ipv4, "%.*s ", e->dst_ipv4.len, e->dst_ipv4.s); + v[3].iov_base = dst_ipv4; + v[3].iov_len = strlen(v[3].iov_base); + v_len += v[3].iov_len; + + //set snat_ipv4 to buffer. + sprintf(snat_ipv4, "%.*s ", e->snat_ipv4.len, e->snat_ipv4.s); + v[4].iov_base = snat_ipv4; + v[4].iov_len = strlen(v[4].iov_base); + v_len += v[4].iov_len; + + //set dnat_ipv4 to buffer. + sprintf(dnat_ipv4, "%.*s ", e->dnat_ipv4.len, e->dnat_ipv4.s); + v[5].iov_base = dnat_ipv4; + v[5].iov_len = strlen(v[5].iov_base); + v_len += v[5].iov_len; + + //set src_port to buffer. + sprintf(src_port, "%.*s ", e->src_port.len, e->src_port.s); + v[6].iov_base = src_port; + v[6].iov_len = strlen(v[6].iov_base); + v_len += v[6].iov_len; + + //set dst_port to buffer. + sprintf(dst_port, "%.*s ", e->dst_port.len, e->dst_port.s); + v[7].iov_base = dst_port; + v[7].iov_len = strlen(v[7].iov_base); + v_len += v[7].iov_len; + + //set snat_port to buffer. + sprintf(snat_port, "%.*s ", e->snat_port.len, e->snat_port.s); + v[8].iov_base = snat_port; + v[8].iov_len = strlen(v[8].iov_base); + v_len += v[8].iov_len; + + //set dnat_port to buffer. + sprintf(dnat_port, "%.*s ", e->dnat_port.len, e->dnat_port.s); + v[9].iov_base = dnat_port; + v[9].iov_len = strlen(v[9].iov_base); + v_len += v[9].iov_len; + + //set timeout to buffer. Set to 60 sec for default. + sprintf(timeout, "%d ", 60); + v[10].iov_base = timeout; + v[10].iov_len = strlen(v[10].iov_base); + v_len += v[10].iov_len; + + //set callid to buffer. + sprintf(callid, "%.*s ", e->callid.len, e->callid.s); + v[11].iov_base = callid; + v[11].iov_len = strlen(v[11].iov_base); + v_len += v[11].iov_len; +// LM_ERR("e->callid.len is:%d right now.\n\n", e->callid.len); + + memset(buf, 0, buflen); + memcpy(buf, send_lrkp_command(e->node, v, 12, v_len), buflen); +// + +// if (buf == NULL) { + if (!buf[0]) { + LM_ERR("can't ping the lrk proxy %s, Disable it right now.\n", e->node->ln_url.s); + return 0; + } + + v_len += v[0].iov_len; + + +// char *resp = buf + v[0].iov_len + v[1].iov_len + v[2].iov_len; + char *resp = buf + v_len; + if (memcmp(resp, "OK", 2) == 0) { + LM_INFO("Recieve OK response from lrk proxy server %s, Rule set successfully.\n", e->node->ln_url.s); + LM_DBG("Recieve OK response from lrk proxy server %s, Rule set successfully.\n", e->node->ln_url.s); + } + return 1; + +} + + +char *send_lrkp_command(struct lrkp_node *node, struct iovec *v, int vcnt, int more) +{ + struct sockaddr_un addr; + int fd, len, i; +// char *cp; + static char buf[256]; + struct pollfd fds[1]; + + memset(buf, 0, 256); + len = 0; +// cp = buf; + if (node->ln_umode == 0) { + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + strncpy(addr.sun_path, node->ln_address, + sizeof(addr.sun_path) - 1); +#ifdef HAVE_SOCKADDR_SA_LEN + addr.sun_len = strlen(addr.sun_path); +#endif + + fd = socket(AF_LOCAL, SOCK_STREAM, 0); + if (fd < 0) { + LM_ERR("can't create socket\n"); + goto badproxy; + } + if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + close(fd); + LM_ERR("can't connect to lrk proxy\n"); + goto badproxy; + } + + do { + len = writev(fd, v + 1, vcnt - 1); + } while (len == -1 && errno == EINTR); + if (len <= 0) { + close(fd); + LM_ERR("can't send command to a lrk proxy %s\n", node->ln_url.s); + goto badproxy; + } + do { + len = read(fd, buf, sizeof(buf) - 1); + } while (len == -1 && errno == EINTR); + close(fd); + if (len <= 0) { + LM_ERR("can't read reply from a lrk proxy %s\n", node->ln_url.s); + goto badproxy; + } + } else { + fds[0].fd = lrkp_socks[node->idx]; + fds[0].events = POLLIN; + fds[0].revents = 0; + /* Drain input buffer */ + while ((poll(fds, 1, 0) == 1) && + ((fds[0].revents & POLLIN) != 0)) { + recv(lrkp_socks[node->idx], buf, sizeof(buf) - 1, 0); + fds[0].revents = 0; + } + v[0].iov_base = gencookie(); + v[0].iov_len = strlen(v[0].iov_base); + for (i = 0; i < lrkproxy_retr; i++) { + do { + len = writev(lrkp_socks[node->idx], v, vcnt); + } while (len == -1 && (errno == EINTR || errno == ENOBUFS)); + if (len <= 0) { + LM_ERR("can't send command to a lrk proxy %s\n", node->ln_url.s); + goto badproxy; + } + while ((poll(fds, 1, lrkproxy_tout * 1000) == 1) && + (fds[0].revents & POLLIN) != 0) { + do { + len = recv(lrkp_socks[node->idx], buf, sizeof(buf) - 1, 0); + } while (len == -1 && errno == EINTR); + if (len <= 0) { + LM_ERR("can't read reply from a lrk proxy %s\n", node->ln_url.s); + goto badproxy; + } + if (len >= (v[0].iov_len - 1) && + memcmp(buf, v[0].iov_base, (v[0].iov_len - 1)) == 0) { //check coocke validation. + char *command = buf + v[0].iov_len; + switch (*command) { + case 'P': + if (len == v[0].iov_len + v[1].iov_len + 4 + 1) + goto out; +// break; + case 'G': + if (len == v[0].iov_len + v[1].iov_len + sizeof(struct lrkp_node_conf) + 1) + goto out; +// break; + case 'S': + if (len == more + v[0].iov_len + 2) + goto out; +// break; + } + + } + fds[0].revents = 0; + } + } + if (i == lrkproxy_tout) { + LM_ERR("timeout waiting reply from a lrk proxy server %s\n", node->ln_url.s); + goto badproxy; + + } + } + out: + return buf; + badproxy: + LM_ERR("lrk proxy <%s> does not respond, disable it\n", node->ln_url.s); + node->ln_enable = 0; +// node->ln_recheck_ticks = get_ticks() + lrkproxy_disable_tout; + return buf; +} + +/* + * select the set with the id_set id + */ +static struct lrkp_set * select_lrkp_set(int id_set ){ + + struct lrkp_set * lrkp_list; + /*is it a valid set_id?*/ + + if(!lrkp_set_list) + { + LM_ERR("lrkproxy set list not initialised\n"); + return NULL; + } + + for(lrkp_list=lrkp_set_list->lset_first; lrkp_list!=NULL && + lrkp_list->id_set!=id_set; lrkp_list=lrkp_list->lset_next); + + return lrkp_list; +} + + +struct lrkp_node *select_lrkp_node(int do_test) +{ +// unsigned sum, sumcut, weight_sum; + unsigned weight_sum; + struct lrkp_node* node; + int was_forced; + int was_forced2; + int was_forced3; + + if(!selected_lrkp_set){ + LM_ERR("script error -no valid set selected\n"); + return NULL; + } + /* Most popular case: 1 proxy, nothing to calculate */ + if (selected_lrkp_set->lrkp_node_count == 1) { + node = selected_lrkp_set->ln_first; +// if (node->rn_disabled && node->rn_recheck_ticks <= get_ticks()) + if (!node->ln_enable) { + node->ln_enable = lrkp_test(node); + if (node->ln_enable) { //get lrk proxy config if it is enable. + lrkp_get_config(node); + return node; + } + } + return node->ln_enable ? node : NULL; +// return NULL; + } + + + /* Check node is enable and test it again*/ + was_forced = 0; +retry: + weight_sum = 0; + for (node=selected_lrkp_set->ln_first; node!=NULL; node=node->ln_next) { + + if (!node->ln_enable) { + /* Try to enable if it's time to try. */ + node->ln_enable = lrkp_test(node); + if (node->ln_enable) //get lrk proxy config if it is enable. + lrkp_get_config(node); + } + +// if (!node->rn_disabled) +// weight_sum += node->rn_weight; + if (node->ln_enable) + weight_sum += node->ln_weight; + } + + if (weight_sum == 0) { + /* No proxies? Force all to be redetected, if not yet */ + if (was_forced) + return NULL; + was_forced = 1; +// for(node=selected_lrkp_set->ln_first; node!=NULL; node=node->ln_next) { +// node->ln_enable = lrkp_test(node); +// } + goto retry; + } + + if (lrkp_algorithm == LRK_LINER) { + was_forced2 = 0; +retry2: + for (node=selected_lrkp_set->ln_first; node != NULL; node = node->ln_next) + if (node->ln_enable) + goto found; + was_forced2 = 1; + if (was_forced2) + return NULL; + + goto retry2; + } + else if(lrkp_algorithm == LRK_RR) { + was_forced3 = 0; +retry3: + if (!selected_lrkp_node) { + selected_lrkp_node = selected_lrkp_set->ln_first; + was_forced3 = 1; + } + for (node = selected_lrkp_node; node != NULL; node = node->ln_next) { + if (!node->ln_enable) + continue; + selected_lrkp_node = node->ln_next; +// if (sumcut < node->ln_weight) + goto found; +// sumcut -= node->ln_weight; + } + + if (was_forced3) + return NULL; + + selected_lrkp_node = NULL; + goto retry3; + } + + found: + if (do_test) { +// //todo... + node->ln_enable = lrkp_test(node); + if (!node->ln_enable) + goto retry; + } + return node; +} + +//static int change_media_sdp(sip_msg_t *msg, struct lrkp_node *n, const char *flags, int type) { +static int change_media_sdp(sip_msg_t *msg, struct lrkproxy_hash_entry *e, const char *flags, enum lrk_operation op) { + struct lump *l; + str body; + str newbody; + + int len; + char *start_sdp_o = NULL; //"o="; + char *start_sdp_s = NULL; //"s="; + char *start_sdp_c = NULL; //"c=IN IP4"; + char *start_sdp_m = NULL; //"m=audio"; + char *ip_selected = NULL; + char *sdp_param_start = NULL; + char *sdp_param_end = NULL; + char *off=NULL; + char sdp_new_o[128]; + char sdp_new_s[128]; + char sdp_new_c[128]; + char sdp_new_m[128]; + + body.s = get_body(msg); + if (body.s == 0) { + LM_ERR("failed to get the message body\n"); + return -1; + } + + body.len = msg->len - (int) (body.s - msg->buf); + if (body.len == 0) { + LM_DBG("message body has zero length\n"); + return -1; + } +// LM_INFO("body:<%.*s>\n", body.len, body.s); + + //allocate new buffer to new sdp buffer. + newbody.len = 1024; + newbody.s = pkg_malloc(newbody.len); + if (newbody.s == NULL) { + LM_ERR("out of pkg memory\n"); + return -1; + } + memset(newbody.s, 0, 1024); + + off = body.s; + start_sdp_o = strstr(off, "o="); + start_sdp_s = strstr(off, "s="); + start_sdp_c = strstr(off, "c=IN IP4"); + start_sdp_m = strstr(off, "m=audio"); + + //if enabled then set direction, + if (e->node->lrkp_n_c->internal_ip && flags) { + if (strstr(flags, "ei")) { + ip_selected = e->node->lrkp_n_c->internal_ip;// lrk_node->internal_ip; + } else if (strstr(flags, "ie")) { + ip_selected = e->node->lrkp_n_c->external_ip; //lrk_node->external_ip; + } else { + LM_INFO("no flags found\n"); + return 0; + } + } else { + ip_selected = e->node->lrkp_n_c->external_ip; //lrk_node->external_ip; + } + + if (op == OP_OFFER) { + e->dst_ipv4.s = ip_selected; + e->dst_ipv4.len = strlen(e->dst_ipv4.s); + + str current_port; + current_port.s = int2str(e->node->lrkp_n_c->current_port, ¤t_port.len); + + if (shm_str_dup(&e->dst_port, ¤t_port) < 0) { + LM_ERR("lrkproxy fail to insert dst_port, calllen=%d dst_port=%.*s\n", + e->callid.len, current_port.len, current_port.s); + lrkproxy_hash_table_free_entry(e); + return 0; + } + +// e->dst_port = e->node->lrkp_n_c->current_port; + } + else if (op == OP_ANSWER){ + e->snat_ipv4.s = ip_selected; + e->snat_ipv4.len = strlen(e->snat_ipv4.s); + + str current_port; + unsigned int snat_port; + + str2int(&e->dst_port, &snat_port); + snat_port += 2; + + current_port.s = int2str(snat_port, ¤t_port.len); + + if (shm_str_dup(&e->snat_port, ¤t_port) < 0) { + LM_ERR("lrkproxy fail to insert snat_port, calllen=%d snat_port=%.*s\n", + e->callid.len, current_port.len, current_port.s); + lrkproxy_hash_table_free_entry(e); + return 0; + } + +// e->snat_port = e->dst_port + 2; + } + + + while (*off != EOB) //while end of body. + { + sdp_param_start = off; + sdp_param_end = sdp_param_start; + while (*sdp_param_end != CR && *sdp_param_end != LF && *sdp_param_end != EOB) sdp_param_end++; + len = (int) (sdp_param_end - sdp_param_start); + if ((int) (start_sdp_o - off) == 0) { + memset(sdp_new_o, 0, 128); + snprintf(sdp_new_o, 128, "o=lrkproxy %s %s IN IP4 %s\r", SUP_CPROTOVER, REQ_CPROTOVER, ip_selected); + strncat(newbody.s, sdp_new_o, strlen(sdp_new_o)); + off += len + 1; + continue; + } + if ((int) (start_sdp_s - off) == 0) { + memset(sdp_new_s, 0, 128); + snprintf(sdp_new_s, 128, "s=lrkproxy Support only Audio Call\r"); + strncat(newbody.s, sdp_new_s, strlen(sdp_new_s)); + off += len + 1; + continue; + } + if ((int) (start_sdp_c - off) == 0) { + memset(sdp_new_c, 0, 128); + snprintf(sdp_new_c, 128, "c=IN IP4 %s\r", ip_selected); + strncat(newbody.s, sdp_new_c, strlen(sdp_new_c)); + off += len + 1; + continue; + } + if ((int)(start_sdp_m - off) == 0){ + memset(sdp_new_m, 0, 128); + char *avp_flags = off; +// int occure = 0; + for (;*avp_flags && !isspace(*avp_flags); avp_flags++); + for (avp_flags++;*avp_flags && !isspace(*avp_flags); avp_flags++); + avp_flags++; + if (op == OP_OFFER) + snprintf(sdp_new_m, 128, "m=audio %.*s %.*s\r",e->dst_port.len, e->dst_port.s, (int)(len - (avp_flags-off)), avp_flags); +// snprintf(sdp_new_m, 128, "m=audio %d %.*s\r",e->node->lrkp_n_c->current_port, (int)(len - (avp_flags-off)), avp_flags); + else if (op == OP_ANSWER) + snprintf(sdp_new_m, 128, "m=audio %.*s %.*s\r",e->snat_port.len, e->snat_port.s, (int)(len - (avp_flags-off)), avp_flags); +// snprintf(sdp_new_m, 128, "m=audio %d %.*s\r",e->node->lrkp_n_c->current_port, (int)(len - (avp_flags-off)), avp_flags); +// printf("%.*s\n\n", len - (avp_flags-off), avp_flags); + strncat(newbody.s,sdp_new_m, strlen(sdp_new_m)); + off += len+1; + continue; + } + + strncat(newbody.s, off, len + 1); + off += len + 1; + } + + +// LM_INFO("%.*s", (int)strlen(newbody.s), newbody.s); + l = del_lump(msg, body.s - msg->buf, body.len, 0); + if (!l) { + LM_ERR("del_lump failed\n"); + return -1; + } + + + if (insert_new_lump_after(l, newbody.s, strlen(newbody.s), 0) == 0) { + LM_ERR("could not insert new lump\n"); + pkg_free(newbody.s); + return -1; + } + + LM_BUG("Insert_new_lump successfully\n"); + + return 1; +} + +/* This function assumes p points to a line of requested type. */ + + static int +set_lrkproxy_set_f(struct sip_msg * msg, char * str1, char * str2) +{ + lrkp_set_link_t *lrkl; + pv_value_t val; + + lrkl = (lrkp_set_link_t*)str1; + + current_msg_id = 0; + selected_lrkp_set = 0; + + if(lrkl->rset != NULL) { + current_msg_id = msg->id; + selected_lrkp_set = lrkl->rset; + } else { + if(pv_get_spec_value(msg, lrkl->rpv, &val)<0) { + LM_ERR("cannot evaluate pv param\n"); + return -1; + } + if(!(val.flags & PV_VAL_INT)) { + LM_ERR("pv param must hold an integer value\n"); + return -1; + } + selected_lrkp_set = select_lrkp_set(val.ri); + if(selected_lrkp_set==NULL) { + LM_ERR("could not locate lrkproxy set %d\n", val.ri); + return -1; + } + current_msg_id = msg->id; + } + return 1; +} + +static int +lrkproxy_manage(struct sip_msg *msg, char *flags, char *ip) +{ + int method; + int nosdp; + tm_cell_t *t = NULL; + + if (msg->cseq==NULL && ((parse_headers(msg, HDR_CSEQ_F, 0)==-1) || + (msg->cseq==NULL))) + { + LM_ERR("no CSEQ header\n"); + return -1; + } + + method = get_cseq(msg)->method_id; + + if (!(method==METHOD_INVITE || method==METHOD_ACK || method==METHOD_CANCEL + || method==METHOD_BYE || method==METHOD_UPDATE)) + return -1; + + if (method==METHOD_CANCEL || method==METHOD_BYE) + return lrkproxy_unforce(msg, flags, OP_DELETE, 1); + + if (msg->msg_flags & FL_SDP_BODY) + nosdp = 0; + else + nosdp = parse_sdp(msg); + + if (msg->first_line.type == SIP_REQUEST) { + if(method==METHOD_ACK && nosdp==0) + return lrkproxy_force(msg, flags, OP_ANSWER, 1); + if(method==METHOD_UPDATE && nosdp==0) + return lrkproxy_force(msg, flags, OP_OFFER, 1); + if(method==METHOD_INVITE && nosdp==0) { + msg->msg_flags |= FL_SDP_BODY; + if(tmb.t_gett!=NULL) { + t = tmb.t_gett(); + if(t!=NULL && t!=T_UNDEFINED && t->uas.request!=NULL) { + t->uas.request->msg_flags |= FL_SDP_BODY; + } + } + if(route_type==FAILURE_ROUTE) + return lrkproxy_unforce(msg, flags, OP_DELETE, 1); + return lrkproxy_force(msg, flags, OP_OFFER, 1); + } + } else if (msg->first_line.type == SIP_REPLY) { + if (msg->first_line.u.reply.statuscode>=300) + return lrkproxy_unforce(msg, flags, OP_DELETE, 2); + if (nosdp==0) { + if (method==METHOD_UPDATE) + return lrkproxy_force(msg, flags, OP_ANSWER, 2); + if (tmb.t_gett==NULL || tmb.t_gett()==NULL + || tmb.t_gett()==T_UNDEFINED) + return lrkproxy_force(msg, flags, OP_ANSWER, 2); + if (tmb.t_gett()->uas.request->msg_flags & FL_SDP_BODY) + return lrkproxy_force(msg, flags, OP_ANSWER, 2); + return lrkproxy_force(msg, flags, OP_OFFER, 2); + } + } + + return -1; +} + +static int +lrkproxy_manage0(struct sip_msg *msg, char *flags, char *ip) +{ + return lrkproxy_manage(msg, 0, 0); +} + +static int +lrkproxy_manage1(struct sip_msg *msg, char *flags, char *ip) +{ + str flag_str; + if(fixup_get_svalue(msg, (gparam_p)flags, &flag_str)<0) + { + LM_ERR("invalid flags parameter\n"); + return -1; + } + return lrkproxy_manage(msg, flag_str.s, 0); +} + +static int +lrkproxy_manage2(struct sip_msg *msg, char *flags, char *ip) +{ + str flag_str; + str ip_str; + if(fixup_get_svalue(msg, (gparam_p)flags, &flag_str)<0) + { + LM_ERR("invalid flags parameter\n"); + return -1; + } + if(fixup_get_svalue(msg, (gparam_p)ip, &ip_str)<0) + { + LM_ERR("invalid IP parameter\n"); + return -1; + } + return lrkproxy_manage(msg, flag_str.s, ip_str.s); +} + + +static int lrkproxy_force(struct sip_msg *msg, const char *flags, enum lrk_operation op, int more) { + +// lrk_sdp_info_t lrk_sdp_info; + struct lrkproxy_hash_entry *entry = NULL; + str viabranch = STR_NULL; + str call_id; + int via_id; + + if (get_callid(msg, &call_id) == -1) { + LM_ERR("can't get Call-Id field\n"); + return -1; + } + + /*We have to choice VIA id, + * for SIP_REQUEST we use VIA1 and for SIP_REPLY we use VIA2 */ + via_id = more; + + if (get_via_branch(msg, via_id, &viabranch) == -1) { + LM_ERR("can't get Call-Id field\n"); + return -1; + } + + if (op == OP_OFFER) { + LM_INFO ("Here is SIP_REQUEST & METHOD_INVITE\n"); + int more_test = 1; + + //select new node based on lrkp_algorithm param. + struct lrkp_node *node = select_lrkp_node(more_test); + if (!node) { + LM_ERR("can't ping any lrk proxy right now.\n"); + return -1; + } + + LM_DBG("selected lrk proxy node: %s\n", node->ln_url.s); + + //check if entry not exist. + if (!lrkproxy_hash_table_lookup(call_id, viabranch)) { + +// lrk_get_sdp_info(msg, &lrk_sdp_info); + + //build new entry for hash table. +// struct lrkproxy_hash_entry *entry = shm_malloc(sizeof(struct lrkproxy_hash_entry)); + entry = shm_malloc(sizeof(struct lrkproxy_hash_entry)); + if (!entry) { + LM_ERR("lrkproxy hash table fail to create entry for calllen=%d callid=%.*s viabranch=%.*s\n", + call_id.len, call_id.len, call_id.s, + viabranch.len, viabranch.s); + return 0; + } + memset(entry, 0, sizeof(struct lrkproxy_hash_entry)); + + // fill the entry + if (call_id.s && call_id.len > 0) { + if (shm_str_dup(&entry->callid, &call_id) < 0) { + LM_ERR("lrkproxy hash table fail to instert call_id, calllen=%d callid=%.*s\n", + call_id.len, call_id.len, call_id.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + + if (viabranch.s && viabranch.len > 0) { + if (shm_str_dup(&entry->viabranch, &viabranch) < 0) { + LM_ERR("lrkproxy hash table fail to insert viabranch, calllen=%d viabranch=%.*s\n", + call_id.len, viabranch.len, viabranch.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + + //fill src_ipv4 and src_port for entry. + str src_ipv4; + if (get_sdp_ipaddr_media(msg, &src_ipv4) == -1) { + LM_ERR("can't get media src_ipv4 from sdp field\n"); + return -1; + } + + if(src_ipv4.s && src_ipv4.len > 0) { + LM_DBG("src_ipv4 from sdp:%.*s\n", src_ipv4.len, src_ipv4.s); + if (shm_str_dup(&entry->src_ipv4, &src_ipv4) < 0) { + LM_ERR("lrkproxy hash table fail to insert src_ipv4, calllen=%d src_ipv4=%.*s\n", + call_id.len, src_ipv4.len, src_ipv4.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + + str src_port; + if (get_sdp_port_media(msg, &src_port) == -1) { + LM_ERR("can't get media src_port from sdp field\n"); + return -1; + } + + + if(src_port.s && src_port.len > 0) { + LM_DBG("src_port from sdp:%.*s\n", src_port.len, src_port.s); + if (shm_str_dup(&entry->src_port, &src_port) < 0) { + LM_ERR("lrkproxy hash table fail to insert src_port, calllen=%d src_port=%.*s\n", + call_id.len, src_port.len, src_port.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + +// entry-> + entry->node = node; + entry->next = NULL; + entry->tout = get_ticks() + hash_table_tout; + + // insert the key<->entry from the hashtable + if (!lrkproxy_hash_table_insert(call_id, viabranch, entry)) { + LM_ERR( + "lrkproxy hash table fail to insert node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->ln_url.len, node->ln_url.s, call_id.len, + call_id.len, call_id.s, viabranch.len, viabranch.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } else { + LM_INFO("lrkproxy hash table insert node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->ln_url.len, node->ln_url.s, call_id.len, + call_id.len, call_id.s, viabranch.len, viabranch.s); + + LM_DBG("lrkproxy hash table insert node=%.*s for calllen=%d callid=%.*s viabranch=%.*s\n", + node->ln_url.len, node->ln_url.s, call_id.len, + call_id.len, call_id.s, viabranch.len, viabranch.s); + } + } + + if (flags) + change_media_sdp(msg, entry, flags, op); + else + change_media_sdp(msg, entry, NULL, op); + + if (node->lrkp_n_c->current_port >= node->lrkp_n_c->end_port) + node->lrkp_n_c->current_port = node->lrkp_n_c->start_port; + else + node->lrkp_n_c->current_port += 4; + + } else if (op == OP_ANSWER) { + LM_INFO ("Here is SIP_REPLY of METHOD_INVITE\n"); + + + entry = lrkproxy_hash_table_lookup(call_id, viabranch); + if (!entry){ + LM_ERR("No found entry in hash table\n"); + //todo... + return 0; + } + + //fill other data for entry + str dnat_ipv4; + if (get_sdp_ipaddr_media(msg, &dnat_ipv4) == -1) { + LM_ERR("can't get media dnat_ipv4 from sdp field\n"); + return -1; + } + + if(dnat_ipv4.s && dnat_ipv4.len > 0) { + LM_DBG("dnat_ipv4 from sdp:%.*s\n", dnat_ipv4.len, dnat_ipv4.s); + if (shm_str_dup(&entry->dnat_ipv4, &dnat_ipv4) < 0) { + LM_ERR("lrkproxy hash table fail to insert dnat_ipv4, calllen=%d dnat_ipv4=%.*s\n", + call_id.len, dnat_ipv4.len, dnat_ipv4.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + + str dnat_port; + if (get_sdp_port_media(msg, &dnat_port) == -1) { + LM_ERR("can't get media port from sdp field\n"); + return -1; + } + + + if(dnat_port.s && dnat_port.len > 0) { + LM_DBG("port from sdp:%.*s\n", dnat_port.len, dnat_port.s); + if (shm_str_dup(&entry->dnat_port, &dnat_port) < 0) { + LM_ERR("lrkproxy hash table fail to insert dnat_port, calllen=%d dnat_port=%.*s\n", + call_id.len, dnat_port.len, dnat_port.s); + lrkproxy_hash_table_free_entry(entry); + return 0; + } + } + + + if (flags) + change_media_sdp(msg, entry, flags, op); + else + change_media_sdp(msg, entry, NULL, op); + + + LM_INFO("selected node: %s\n",entry->node->ln_url.s); + LM_INFO("call_is: %.*s\n",entry->callid.len, entry->callid.s); + LM_INFO("viabranch: %.*s\n",entry->viabranch.len, entry->viabranch.s); + LM_INFO("src_ipv4: %.*s\n",entry->src_ipv4.len, entry->src_ipv4.s); + LM_INFO("src_port: %.*s\n",entry->src_port.len, entry->src_port.s); + LM_INFO("dst_ipv4: %.*s\n",entry->dst_ipv4.len, entry->dst_ipv4.s); + LM_INFO("dst_port: %.*s\n",entry->dst_port.len, entry->dst_port.s); + + LM_INFO("dnat_ipv4: %.*s\n",entry->dnat_ipv4.len, entry->dnat_ipv4.s); + LM_INFO("dnat_port: %.*s\n",entry->dnat_port.len, entry->dnat_port.s); + LM_INFO("snat_ipv4: %.*s\n",entry->snat_ipv4.len, entry->snat_ipv4.s); + LM_INFO("snat_port: %.*s\n",entry->snat_port.len, entry->snat_port.s); + + + lrkp_set_conntrack_rule(entry); + + } + return 1; +} + +static int lrkproxy_unforce(struct sip_msg *msg, const char *flags, enum lrk_operation op, int more){ +// LM_INFO ("Here is lrkproxy_unforce\n"); +// struct lrkproxy_hash_entry *entry = NULL; + str viabranch = STR_NULL; + str call_id; + int via_id; + + if (get_callid(msg, &call_id) == -1) { + LM_ERR("can't get Call-Id field\n"); + return -1; + } + + /*We have to choice VIA id, + * for SIP_REQUEST we use VIA1 and for SIP_REPLY we use VIA2 */ + via_id = more; + + if (get_via_branch(msg, via_id, &viabranch) == -1) { + LM_ERR("can't get Call-Id field\n"); + return -1; + } + + if (op == OP_DELETE) { + /* Delete the key<->value from the hashtable */ + if (!lrkproxy_hash_table_remove(call_id, viabranch, op)) { + LM_ERR("lrkproxy hash table failed to remove entry for callen=%d callid=%.*s viabranch=%.*s\n", + call_id.len, call_id.len, call_id.s, + viabranch.len, viabranch.s); + } else { + LM_DBG("lrkproxy hash table remove entry for callen=%d callid=%.*s viabranch=%.*s\n", + call_id.len, call_id.len, call_id.s, + viabranch.len, viabranch.s); + } + } + LM_INFO("lrkproxy hash table remove entry for callen=%d callid=%.*s viabranch=%.*s successfully\n", + call_id.len, call_id.len, call_id.s, + viabranch.len, viabranch.s); + return 1; +} diff --git a/src/modules/lrkproxy/lrkproxy.h b/src/modules/lrkproxy/lrkproxy.h new file mode 100644 index 00000000000..2cf855e419c --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#ifndef _LRKPROXY_H +#define _LRKPROXY_H + +#include +#include "../../core/str.h" + +/* Handy macros */ +#define STR2IOVEC(sx, ix) do {(ix).iov_base = (sx).s; (ix).iov_len = (sx).len;} while(0) +#define SZ2IOVEC(sx, ix) do {(ix).iov_base = (sx); (ix).iov_len = strlen(sx);} while(0) + +#define CR '\r' +#define LF '\n' +#define EOB '\0' + +enum lrk_operation { + OP_OFFER = 1, + OP_ANSWER, + OP_DELETE, + OP_PING, + OP_GETINFO, + OP_SETCONNT, + + OP_ANY, +}; + + +enum lrk_alg{ + LRK_LINER=0, + LRK_RR +}; + +struct lrkp_node_conf +{ + int start_port; + int end_port; + int current_port; + char internal_ip[20]; + char external_ip[20]; +}; + +struct lrkp_node { + unsigned int idx; /* overall index */ + str ln_url; /* unparsed, deletable */ + int ln_umode; + char *ln_address; /* substring of rn_url */ + int ln_enable; /* found unaccessible? */ + unsigned ln_weight; /* for load balancing */ +// unsigned int ln_recheck_ticks; +// int ln_rep_supported; +// int ln_ptl_supported; + struct lrkp_node_conf *lrkp_n_c; + struct lrkp_node *ln_next; +}; + + + +struct lrkp_set{ + unsigned int id_set; + unsigned weight_sum; + unsigned int lrkp_node_count; + int set_disabled; + unsigned int set_recheck_ticks; + struct lrkp_node *ln_first; + struct lrkp_node *ln_last; + struct lrkp_set *lset_next; +}; + + + +struct lrkp_set_head{ + struct lrkp_set *lset_first; + struct lrkp_set *lset_last; +}; +/* Functions from nathelper */ +//struct lrkp_node *lrkp_node(str, int); +struct lrkp_node *select_lrkp_node(int); +char *send_lrkp_command(struct lrkp_node *, struct iovec *, int, int); + +struct lrkp_set *get_lrkp_set(str *set_name); +int insert_lrkp_node(struct lrkp_set *const lrkp_list, const str *const url, + const int weight, const int enable); + + +#endif //_LRKPROXY_H diff --git a/src/modules/lrkproxy/lrkproxy_funcs.c b/src/modules/lrkproxy/lrkproxy_funcs.c new file mode 100644 index 00000000000..08a41f27cfe --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy_funcs.c @@ -0,0 +1,479 @@ +/* + * Copyright (C) 2001-2003 FhG Fokus + * Copyright (C) 2014-2015 Sipwise GmbH, http://www.sipwise.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include "lrkproxy_funcs.h" +#include "../../core/dprint.h" +#include "../../core/config.h" +#include "../../core/ut.h" +#include "../../core/forward.h" +#include "../../core/resolve.h" +#include "../../core/globals.h" +#include "../../core/udp_server.h" +#include "../../core/pt.h" +#include "../../core/parser/msg_parser.h" +#include "../../core/trim.h" +#include "../../core/parser/parse_from.h" +#include "../../core/parser/contact/parse_contact.h" +#include "../../core/parser/parse_uri.h" +#include "../../core/parser/parse_content.h" +#include "../../core/parser/parser_f.h" +#include "../../core/parser/sdp/sdp_helpr_funcs.h" + +#define READ(val) \ + (*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24)) +#define advance(_ptr,_n,_str,_error) \ + do{\ + if ((_ptr)+(_n)>(_str).s+(_str).len)\ + goto _error;\ + (_ptr) = (_ptr) + (_n);\ + }while(0); +#define one_of_16( _x , _t ) \ + (_x==_t[0]||_x==_t[15]||_x==_t[8]||_x==_t[2]||_x==_t[3]||_x==_t[4]\ + ||_x==_t[5]||_x==_t[6]||_x==_t[7]||_x==_t[1]||_x==_t[9]||_x==_t[10]\ + ||_x==_t[11]||_x==_t[12]||_x==_t[13]||_x==_t[14]) +#define one_of_8( _x , _t ) \ + (_x==_t[0]||_x==_t[7]||_x==_t[1]||_x==_t[2]||_x==_t[3]||_x==_t[4]\ + ||_x==_t[5]||_x==_t[6]) + + + +/** + * return: + * -1: error + * 1: text or sdp + * 2: multipart + * 3: trickle ice sdp fragment + */ +int check_content_type(struct sip_msg *msg) +{ + static unsigned int appl[16] = { + 0x6c707061/*appl*/,0x6c707041/*Appl*/,0x6c705061/*aPpl*/, + 0x6c705041/*APpl*/,0x6c507061/*apPl*/,0x6c507041/*ApPl*/, + 0x6c505061/*aPPl*/,0x6c505041/*APPl*/,0x4c707061/*appL*/, + 0x4c707041/*AppL*/,0x4c705061/*aPpL*/,0x4c705041/*APpL*/, + 0x4c507061/*apPL*/,0x4c507041/*ApPL*/,0x4c505061/*aPPL*/, + 0x4c505041/*APPL*/}; + static unsigned int icat[16] = { + 0x74616369/*icat*/,0x74616349/*Icat*/,0x74614369/*iCat*/, + 0x74614349/*ICat*/,0x74416369/*icAt*/,0x74416349/*IcAt*/, + 0x74414369/*iCAt*/,0x74414349/*ICAt*/,0x54616369/*icaT*/, + 0x54616349/*IcaT*/,0x54614369/*iCaT*/,0x54614349/*ICaT*/, + 0x54416369/*icAT*/,0x54416349/*IcAT*/,0x54414369/*iCAT*/, + 0x54414349/*ICAT*/}; + static unsigned int ion_[8] = { + 0x006e6f69/*ion_*/,0x006e6f49/*Ion_*/,0x006e4f69/*iOn_*/, + 0x006e4f49/*IOn_*/,0x004e6f69/*ioN_*/,0x004e6f49/*IoN_*/, + 0x004e4f69/*iON_*/,0x004e4f49/*ION_*/}; + static unsigned int sdp_[8] = { + 0x00706473/*sdp_*/,0x00706453/*Sdp_*/,0x00704473/*sDp_*/, + 0x00704453/*SDp_*/,0x00506473/*sdP_*/,0x00506453/*SdP_*/, + 0x00504473/*sDP_*/,0x00504453/*SDP_*/}; + str str_type; + unsigned int x; + char *p; + + if (!msg->content_type) + { + LM_WARN("the header Content-TYPE is absent!" + "let's assume the content is text/plain ;-)\n"); + return 1; + } + + trim_len(str_type.len,str_type.s,msg->content_type->body); + if (str_type.len>=15 && (*str_type.s=='m' || *str_type.s=='M') + && strncasecmp(str_type.s, "multipart/mixed", 15) == 0) { + return 2; + } + p = str_type.s; + advance(p,4,str_type,error_1); + x = READ(p-4); + if (!one_of_16(x,appl)) + goto other; + advance(p,4,str_type,error_1); + x = READ(p-4); + if (!one_of_16(x,icat)) + goto other; + advance(p,3,str_type,error_1); + x = READ(p-3) & 0x00ffffff; + if (!one_of_8(x,ion_)) + goto other; + + /* skip spaces and tabs if any */ + while (*p==' ' || *p=='\t') + advance(p,1,str_type,error_1); + if (*p!='/') + { + LM_ERR("no / found after primary type\n"); + goto error; + } + advance(p,1,str_type,error_1); + while ((*p==' ' || *p=='\t') && p+1 found valid\n", (int)(p-str_type.s), str_type.s); + return 1; + } else { + LM_ERR("bad end for type!\n"); + return -1; + } + + error_1: + LM_ERR("body ended :-(!\n"); + error: + return -1; + other: + LM_ERR("invalid type for a message\n"); + return -1; +} + + +/* + * Get message body and check Content-Type header field + */ +int extract_body(struct sip_msg *msg, str *body ) +{ + char c; + int ret; + str mpdel; + char *rest, *p1, *p2; + struct hdr_field hf; + unsigned int mime; + + body->s = get_body(msg); + if (body->s==0) { + LM_ERR("failed to get the message body\n"); + goto error; + } + + /* + * Better use the content-len value - no need of any explicit + * parcing as get_body() parsed all headers and Conten-Length + * body header is automaticaly parsed when found. + */ + if (msg->content_length==0) { + LM_ERR("failed to get the content length in message\n"); + goto error; + } + + body->len = get_content_length(msg); + if (body->len==0) { + LM_ERR("message body has length zero\n"); + goto error; + } + + if (body->len + body->s > msg->buf + msg->len) { + LM_ERR("content-length exceeds packet-length by %d\n", + (int)((body->len + body->s) - (msg->buf + msg->len))); + goto error; + } + + /* no need for parse_headers(msg, EOH), get_body will + * parse everything */ + /*is the content type correct?*/ + if((ret = check_content_type(msg))==-1) + { + LM_ERR("content type mismatching\n"); + goto error; + } + + if(ret!=2) + goto done; + + /* multipart body */ + if(get_mixed_part_delimiter(&msg->content_type->body,&mpdel) < 0) { + goto error; + } + p1 = find_sdp_line_delimiter(body->s, body->s+body->len, mpdel); + if (p1 == NULL) { + LM_ERR("empty multipart content\n"); + return -1; + } + p2=p1; + c = 0; + for(;;) + { + p1 = p2; + if (p1 == NULL || p1 >= body->s+body->len) + break; /* No parts left */ + p2 = find_next_sdp_line_delimiter(p1, body->s+body->len, + mpdel, body->s+body->len); + /* p2 is text limit for application parsing */ + rest = eat_line(p1 + mpdel.len + 2, p2 - p1 - mpdel.len - 2); + if ( rest > p2 ) { + LM_ERR("Unparsable <%.*s>\n", (int)(p1-p1), p1); + return -1; + } + while( rest>16) == TYPE_APPLICATION) + && ((mime&0x00ff) == SUBTYPE_SDP)) { + c = 1; + } + } + } /* end of while */ + if(c==1) + { + if (rest < p2 && *rest == '\r') rest++; + if (rest < p2 && *rest == '\n') rest++; + if (rest < p2 && p2[-1] == '\n') p2--; + if (rest < p2 && p2[-1] == '\r') p2--; + body->s = rest; + body->len = p2-rest; + goto done; + } + } + + error: + return -1; + + done: + /*LM_DBG("DEBUG:extract_body:=|%.*s|\n",body->len,body->s);*/ + return ret; /* mirrors return type of check_content_type */ +} + +/* + * Some helper functions taken verbatim from tm module. + */ + +/* + * Extract Call-ID value + * assumes the callid header is already parsed + * (so make sure it is, before calling this function or + * it might fail even if the message _has_ a callid) + */ +int +get_callid(struct sip_msg* _m, str* _cid) +{ + + if ((parse_headers(_m, HDR_CALLID_F, 0) == -1)) { + LM_ERR("failed to parse call-id header\n"); + return -1; + } + + if (_m->callid == NULL) { + LM_ERR("call-id not found\n"); + return -1; + } + + _cid->s = _m->callid->body.s; + _cid->len = _m->callid->body.len; + trim(_cid); + return 0; +} + +/* + * Extract tag from To header field of a response + */ +int +get_to_tag(struct sip_msg* _m, str* _tag) +{ + + if (parse_to_header(_m) < 0) { + LM_ERR("To header field missing\n"); + return -1; + } + + if (get_to(_m)->tag_value.len) { + _tag->s = get_to(_m)->tag_value.s; + _tag->len = get_to(_m)->tag_value.len; + } else { + _tag->s = NULL; /* fixes gcc 4.0 warnings */ + _tag->len = 0; + } + + return 0; +} + +/* + * Extract tag from From header field of a request + */ +int +get_from_tag(struct sip_msg* _m, str* _tag) +{ + + if (parse_from_header(_m)<0) { + LM_ERR("failed to parse From header\n"); + return -1; + } + + if (get_from(_m)->tag_value.len) { + _tag->s = get_from(_m)->tag_value.s; + _tag->len = get_from(_m)->tag_value.len; + } else { + _tag->s = NULL; /* fixes gcc 4.0 warnings */ + _tag->len = 0; + } + + return 0; +} + +/* + * Extract URI from the Contact header field + */ +int +get_contact_uri(struct sip_msg* _m, struct sip_uri *uri, contact_t** _c) +{ + + if ((parse_headers(_m, HDR_CONTACT_F, 0) == -1) || !_m->contact) + return -1; + if (!_m->contact->parsed && parse_contact(_m->contact) < 0) { + LM_ERR("failed to parse Contact body\n"); + return -1; + } + *_c = ((contact_body_t*)_m->contact->parsed)->contacts; + if (*_c == NULL) + /* no contacts found */ + return -1; + + if (parse_uri((*_c)->uri.s, (*_c)->uri.len, uri) < 0 || uri->host.len <= 0) { + LM_ERR("failed to parse Contact URI [%.*s]\n", + (*_c)->uri.len, ((*_c)->uri.s)?(*_c)->uri.s:""); + return -1; + } + return 0; +} + +/* + * Extract branch from Via header + */ +int +get_via_branch(struct sip_msg* msg, int vianum, str* _branch) +{ + struct via_body *via; + struct via_param *p; + + if (parse_via_header(msg, vianum, &via) < 0) + return -1; + + for (p = via->param_lst; p; p = p->next) + { + if (p->name.len == strlen("branch") + && strncasecmp(p->name.s, "branch", strlen("branch")) == 0) { + _branch->s = p->value.s; + _branch->len = p->value.len; + return 0; + } + } + return -1; +} + +int get_sdp_ipaddr_media(struct sip_msg *msg, str *ip_addr) { + sdp_session_cell_t *sdp_session; + sdp_stream_cell_t *sdp_stream; + sdp_info_t *sdp = (sdp_info_t *) msg->body; + if (!sdp) { + LM_INFO("sdp null\n"); + return -1; + } + + + int sdp_session_num = 0; + sdp_session = get_sdp_session(msg, sdp_session_num); + + if (!sdp_session) { + LM_INFO("can not get the sdp session\n"); + return 0; + } + + if (sdp_session->ip_addr.s && sdp_session->ip_addr.len > 0) { + LM_INFO("sdp_session->ip_addr:%.*s\n", sdp_session->ip_addr.len, sdp_session->ip_addr.s); + ip_addr->s = sdp_session->ip_addr.s; + ip_addr->len = sdp_session->ip_addr.len; + trim(ip_addr); + } + else { + int sdp_stream_num = 0; + sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num); + if (!sdp_stream) { + LM_INFO("can not get the sdp stream\n"); + return 0; + } + if (sdp_stream->ip_addr.s && sdp_stream->ip_addr.len > 0) { + LM_INFO("sdp_stream->ip_addr:%.*s\n", sdp_stream->ip_addr.len, sdp_stream->ip_addr.s); + ip_addr->s = sdp_stream->ip_addr.s; + ip_addr->len = sdp_stream->ip_addr.len; + trim(ip_addr); + } + } + + + return 0; +} + + +int get_sdp_port_media(struct sip_msg *msg, str *port){ +// sdp_session_cell_t *sdp_session; + sdp_stream_cell_t *sdp_stream; + int sdp_session_num = 0; + + sdp_info_t *sdp = (sdp_info_t *)msg->body; + if(!sdp) { + LM_INFO("sdp null\n"); + return -1; + } + +// sdp_session = get_sdp_session(msg, sdp_session_num); +// if(!sdp_session) { +// LM_INFO("can not get the sdp session\n"); +// return 0; +// } else { +// LM_INFO("NEW_IP_ADDRESS:>%.*s>\n", sdp_session->ip_addr.len, sdp_session->ip_addr.s); +// lrk_sdp_info->ip_addr.s = sdp_session->ip_addr; + int sdp_stream_num = 0; + sdp_stream = get_sdp_stream(msg, sdp_session_num, sdp_stream_num); + if (!sdp_stream) { + LM_INFO("can not get the sdp stream\n"); + return -1; + } else { +// LM_INFO ("PORT:<%.*s>\n", sdp_stream->port.len, sdp_stream->port.s); +// str2int(&sdp_stream->port, lrk_sdp_info->port) + port->s = sdp_stream->port.s; + port->len = sdp_stream->port.len; + trim(port); + } +// } + return 0; + +} + diff --git a/src/modules/lrkproxy/lrkproxy_funcs.h b/src/modules/lrkproxy/lrkproxy_funcs.h new file mode 100644 index 00000000000..d644235226f --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy_funcs.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2001-2003 FhG Fokus + * Copyright (C) 2014-2015 Sipwise GmbH, http://www.sipwise.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#ifndef _LRKPROXY_FUNCS_H +#define _LRKPROXY_FUNCS_H + + +#include "../../core/str.h" +#include "../../core/parser/msg_parser.h" +#include "../../core/parser/contact/contact.h" + +int extract_body(struct sip_msg * , str *); +int check_content_type(struct sip_msg * ); +int get_callid(struct sip_msg *, str *); +int get_to_tag(struct sip_msg *, str *); +int get_from_tag(struct sip_msg *, str *); +int get_contact_uri(struct sip_msg *, struct sip_uri *, contact_t **); +int get_via_branch(struct sip_msg *, int, str *); +int get_sdp_ipaddr_media(struct sip_msg *msg, str *ip_addr); +int get_sdp_port_media(struct sip_msg *msg, str *port); + + +#endif //_LRKPROXY_FUNCS_H diff --git a/src/modules/lrkproxy/lrkproxy_hash.c b/src/modules/lrkproxy/lrkproxy_hash.c new file mode 100644 index 00000000000..460db1d56e9 --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy_hash.c @@ -0,0 +1,522 @@ +/* + * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com + * Copyright (C) 2014-2015 Sipwise GmbH, http://www.sipwise.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + + +#include "lrkproxy.h" +#include "lrkproxy_hash.h" + +#include "../../core/str.h" +#include "../../core/dprint.h" +#include "../../core/mem/shm_mem.h" +#include "../../core/timer.h" + +static void lrkproxy_hash_table_free_row_lock(gen_lock_t *row_lock); + +static struct lrkproxy_hash_table *lrkproxy_hash_table; + +/* get from sipwise rtpengine */ +static int str_cmp_str(const str a, const str b) { + if (a.len < b.len) + return -1; + if (a.len > b.len) + return 1; + if (a.len == 0 && b.len == 0) + return 0; + return memcmp(a.s, b.s, a.len); +} + +/* get from sipwise rtpengine */ +static int str_equal(str a, str b) { + return (str_cmp_str(a, b) == 0); +} + +/* get from sipwise rtpengine */ +static unsigned int str_hash(str s) { + unsigned int ret = 5381; + str it = s; + + while (it.len > 0) { + ret = (ret << 5) + ret + *it.s; + it.s++; + it.len--; + } + + return ret % lrkproxy_hash_table->size; +} + +/* lrkproxy hash API */ +int lrkproxy_hash_table_init(int size) { + int i; + int hash_table_size; + + + hash_table_size = size; + + +// LM_DBG(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>lrkproxy_hash_table size = %d\n", hash_table_size); + LM_INFO(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>lrkproxy_hash_table size = %d\n", hash_table_size); + + // init hashtable + lrkproxy_hash_table = shm_malloc(sizeof(struct lrkproxy_hash_table)); + if (!lrkproxy_hash_table) { + LM_ERR("no shm left to create lrkproxy_hash_table\n"); + return 0; + } + memset(lrkproxy_hash_table, 0, sizeof(struct lrkproxy_hash_table)); + lrkproxy_hash_table->size = hash_table_size; + + // init hashtable row_locks + lrkproxy_hash_table->row_locks = shm_malloc(hash_table_size * sizeof(gen_lock_t*)); + if (!lrkproxy_hash_table->row_locks) { + LM_ERR("no shm left to create lrkproxy_hash_table->row_locks\n"); + lrkproxy_hash_table_destroy(); + return 0; + } + memset(lrkproxy_hash_table->row_locks, 0, hash_table_size * sizeof(gen_lock_t*)); + + // init hashtable row_entry_list + lrkproxy_hash_table->row_entry_list = shm_malloc(lrkproxy_hash_table->size * sizeof(struct lrkproxy_hash_entry*)); + if (!lrkproxy_hash_table->row_entry_list) { + LM_ERR("no shm left to create lrkproxy_hash_table->row_entry_list\n"); + lrkproxy_hash_table_destroy(); + return 0; + } + memset(lrkproxy_hash_table->row_entry_list, 0, lrkproxy_hash_table->size * sizeof(struct lrkproxy_hash_entry*)); + + // init hashtable row_totals + lrkproxy_hash_table->row_totals = shm_malloc(hash_table_size * sizeof(unsigned int)); + if (!lrkproxy_hash_table->row_totals) { + LM_ERR("no shm left to create lrkproxy_hash_table->row_totals\n"); + lrkproxy_hash_table_destroy(); + return 0; + } + memset(lrkproxy_hash_table->row_totals, 0, hash_table_size * sizeof(unsigned int)); + + // init hashtable row_locks[i], row_entry_list[i] and row_totals[i] + for (i = 0; i < hash_table_size; i++) { + // alloc hashtable row_locks[i] + lrkproxy_hash_table->row_locks[i] = lock_alloc(); + if (!lrkproxy_hash_table->row_locks[i]) { + LM_ERR("no shm left to create lrkproxy_hash_table->row_locks[%d]\n", i); + lrkproxy_hash_table_destroy(); + return 0; + } + + // init hashtable row_locks[i] + if (!lock_init(lrkproxy_hash_table->row_locks[i])) { + LM_ERR("fail to init lrkproxy_hash_table->row_locks[%d]\n", i); + lrkproxy_hash_table_destroy(); + return 0; + } + + // init hashtable row_entry_list[i] + lrkproxy_hash_table->row_entry_list[i] = shm_malloc(sizeof(struct lrkproxy_hash_entry)); + if (!lrkproxy_hash_table->row_entry_list[i]) { + LM_ERR("no shm left to create lrkproxy_hash_table->row_entry_list[%d]\n", i); + lrkproxy_hash_table_destroy(); + return 0; + } + memset(lrkproxy_hash_table->row_entry_list[i], 0, sizeof(struct lrkproxy_hash_entry)); + + lrkproxy_hash_table->row_entry_list[i]->tout = -1; + lrkproxy_hash_table->row_entry_list[i]->next = NULL; + + // init hashtable row_totals[i] + lrkproxy_hash_table->row_totals[i] = 0; + } + + return 1; +} + +int lrkproxy_hash_table_destroy() { + int i; + + // check lrkproxy hashtable + if (!lrkproxy_hash_table) { + LM_ERR("NULL lrkproxy_hash_table\n"); + return 1; + } + + // check lrkproxy hashtable->row_locks + if (!lrkproxy_hash_table->row_locks) { + LM_ERR("NULL lrkproxy_hash_table->row_locks\n"); + shm_free(lrkproxy_hash_table); + lrkproxy_hash_table = NULL; + return 1; + } + + // destroy hashtable content + for (i = 0; i < lrkproxy_hash_table->size; i++) { + // lock + if (!lrkproxy_hash_table->row_locks[i]) { + LM_ERR("NULL lrkproxy_hash_table->row_locks[%d]\n", i); + continue; + } else { + lock_get(lrkproxy_hash_table->row_locks[i]); + } + + // check lrkproxy hashtable->row_entry_list + if (!lrkproxy_hash_table->row_entry_list) { + LM_ERR("NULL lrkproxy_hash_table->row_entry_list\n"); + } else { + // destroy hashtable row_entry_list[i] + lrkproxy_hash_table_free_row_entry_list(lrkproxy_hash_table->row_entry_list[i]); + lrkproxy_hash_table->row_entry_list[i] = NULL; + } + + // unlock + lock_release(lrkproxy_hash_table->row_locks[i]); + + // destroy hashtable row_locks[i] + lrkproxy_hash_table_free_row_lock(lrkproxy_hash_table->row_locks[i]); + lrkproxy_hash_table->row_locks[i] = NULL; + } + + // destroy hashtable row_entry_list + if (!lrkproxy_hash_table->row_entry_list) { + LM_ERR("NULL lrkproxy_hash_table->row_entry_list\n"); + } else { + shm_free(lrkproxy_hash_table->row_entry_list); + lrkproxy_hash_table->row_entry_list = NULL; + } + + // destroy hashtable row_totals + if (!lrkproxy_hash_table->row_totals) { + LM_ERR("NULL lrkproxy_hash_table->row_totals\n"); + } else { + shm_free(lrkproxy_hash_table->row_totals); + lrkproxy_hash_table->row_totals = NULL; + } + + // destroy hashtable row_locks + if (!lrkproxy_hash_table->row_locks) { + // should not be the case; just for code symmetry + LM_ERR("NULL lrkproxy_hash_table->row_locks\n"); + } else { + shm_free(lrkproxy_hash_table->row_locks); + lrkproxy_hash_table->row_locks = NULL; + } + + // destroy hashtable + if (!lrkproxy_hash_table) { + // should not be the case; just for code symmetry + LM_ERR("NULL lrkproxy_hash_table\n"); + } else { + shm_free(lrkproxy_hash_table); + lrkproxy_hash_table = NULL; + } + + return 1; +} + + +void lrkproxy_hash_table_free_entry(struct lrkproxy_hash_entry *entry) { + if (!entry) { + LM_ERR("try to free a NULL entry\n"); + return ; + } + + // free callid + if (entry->callid.s) { + shm_free(entry->callid.s); + } + + // free viabranch + if (entry->viabranch.s) { + shm_free(entry->viabranch.s); + } + + // free entry + shm_free(entry); + + return ; +} + +void lrkproxy_hash_table_free_row_entry_list(struct lrkproxy_hash_entry *row_entry_list) { + struct lrkproxy_hash_entry *entry, *last_entry; + + if (!row_entry_list) { + LM_ERR("try to free a NULL row_entry_list\n"); + return ; + } + + entry = row_entry_list; + while (entry) { + last_entry = entry; + entry = entry->next; + lrkproxy_hash_table_free_entry(last_entry); + last_entry = NULL; + } + + return ; +} + +int lrkproxy_hash_table_insert(str callid, str viabranch, struct lrkproxy_hash_entry *value) { + struct lrkproxy_hash_entry *entry, *last_entry; + struct lrkproxy_hash_entry *new_entry = (struct lrkproxy_hash_entry *) value; + unsigned int hash_index; + + // sanity checks + if (!lrkproxy_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); + return 0; + } + + // get entry list + hash_index = str_hash(callid); + entry = lrkproxy_hash_table->row_entry_list[hash_index]; + last_entry = entry; + + // lock + if (lrkproxy_hash_table->row_locks[hash_index]) { + lock_get(lrkproxy_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL lrkproxy_hash_table->row_locks[%d]\n", hash_index); + return 0; + } + + while (entry) { + // if found, don't add new entry + if (str_equal(entry->callid, new_entry->callid) && + str_equal(entry->viabranch, new_entry->viabranch)) { + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + LM_NOTICE("callid=%.*s, viabranch=%.*s already in hashtable, ignore new value\n", + entry->callid.len, entry->callid.s, + entry->viabranch.len, entry->viabranch.s); + return 0; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + lrkproxy_hash_table_free_entry(entry); + + // set pointers + entry = last_entry; + + // update total + lrkproxy_hash_table->row_totals[hash_index]--; + } + + // next entry in the list + last_entry = entry; + entry = entry->next; + } + + last_entry->next = new_entry; + + // update total + lrkproxy_hash_table->row_totals[hash_index]++; + + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + + return 1; +} + +int lrkproxy_hash_table_remove(str callid, str viabranch, enum lrk_operation op) { + struct lrkproxy_hash_entry *entry, *last_entry; + unsigned int hash_index; + int found = 0; + + // sanity checks + if (!lrkproxy_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); + return 0; + } + + // get first entry from entry list; jump over unused list head + hash_index = str_hash(callid); + entry = lrkproxy_hash_table->row_entry_list[hash_index]; + last_entry = entry; + + // lock + if (lrkproxy_hash_table->row_locks[hash_index]) { + lock_get(lrkproxy_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL lrkproxy_hash_table->row_locks[%d]\n", hash_index); + return 0; + } + + while (entry) { + // if callid found, delete entry + if ((str_equal(entry->callid, callid) && str_equal(entry->viabranch, viabranch)) || + (str_equal(entry->callid, callid) && viabranch.len == 0 && op == OP_DELETE)) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + lrkproxy_hash_table_free_entry(entry); + + // set pointers + entry = last_entry; + + // update total + lrkproxy_hash_table->row_totals[hash_index]--; + + found = 1; + + if (!(viabranch.len == 0 && op == OP_DELETE)) { + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + return found; + } + + // try to also delete other viabranch entries for callid + last_entry = entry; + entry = entry->next; + continue; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + lrkproxy_hash_table_free_entry(entry); + + // set pointers + entry = last_entry; + + // update total + lrkproxy_hash_table->row_totals[hash_index]--; + } + + last_entry = entry; + entry = entry->next; + } + + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + + return found; +} +//struct lrkp_node *lrkproxy_hash_table_lookup(str callid, str viabranch, enum lrk_operation op) { +//struct lrkproxy_hash_entry *lrkproxy_hash_table_lookup(str callid, str viabranch, enum lrk_operation op) { +struct lrkproxy_hash_entry *lrkproxy_hash_table_lookup(str callid, str viabranch) { + struct lrkproxy_hash_entry *entry, *last_entry; + unsigned int hash_index; +// struct lrkp_node *node; + + // sanity checks + if (!lrkproxy_hash_table_sanity_checks()) { + LM_ERR("sanity checks failed\n"); + return 0; + } + + // get first entry from entry list; jump over unused list head + hash_index = str_hash(callid); + entry = lrkproxy_hash_table->row_entry_list[hash_index]; + last_entry = entry; + + // lock + if (lrkproxy_hash_table->row_locks[hash_index]) { + lock_get(lrkproxy_hash_table->row_locks[hash_index]); + } else { + LM_ERR("NULL lrkproxy_hash_table->row_locks[%d]\n", hash_index); + return 0; + } + + while (entry) { + // if callid found, return entry +// if ((str_equal(entry->callid, callid) && str_equal(entry->viabranch, viabranch)) || +// (str_equal(entry->callid, callid) && viabranch.len == 0 && op == OP_DELETE)) { + if (str_equal(entry->callid, callid) && str_equal(entry->viabranch, viabranch)) { +// node = entry->node; + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + return entry; +// return node; + } + + // if expired entry discovered, delete it + if (entry->tout < get_ticks()) { + // set pointers; exclude entry + last_entry->next = entry->next; + + // free current entry; entry points to unknown + lrkproxy_hash_table_free_entry(entry); + + // set pointers + entry = last_entry; + + // update total + lrkproxy_hash_table->row_totals[hash_index]--; + } + + last_entry = entry; + entry = entry->next; + } + + // unlock + lock_release(lrkproxy_hash_table->row_locks[hash_index]); + + return NULL; +} + + +static void lrkproxy_hash_table_free_row_lock(gen_lock_t *row_lock) { + if (!row_lock) { + LM_ERR("try to free a NULL lock\n"); + return ; + } + + lock_destroy(row_lock); + lock_dealloc(row_lock); + + return ; +} + +int lrkproxy_hash_table_sanity_checks() { + // check lrkproxy hashtable + if (!lrkproxy_hash_table) { + LM_ERR("NULL lrkproxy_hash_table\n"); + return 0; + } + + // check lrkproxy hashtable->row_locks + if (!lrkproxy_hash_table->row_locks) { + LM_ERR("NULL lrkproxy_hash_table->row_locks\n"); + return 0; + } + + // check lrkproxy hashtable->row_entry_list + if (!lrkproxy_hash_table->row_entry_list) { + LM_ERR("NULL lrkproxy_hash_table->row_entry_list\n"); + return 0; + } + + // check lrkproxy hashtable->row_totals + if (!lrkproxy_hash_table->row_totals) { + LM_ERR("NULL lrkproxy_hash_table->row_totals\n"); + return 0; + } + + return 1; +} + diff --git a/src/modules/lrkproxy/lrkproxy_hash.h b/src/modules/lrkproxy/lrkproxy_hash.h new file mode 100644 index 00000000000..0943021b526 --- /dev/null +++ b/src/modules/lrkproxy/lrkproxy_hash.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2003-2008 Sippy Software, Inc., http://www.sippysoft.com + * Copyright (C) 2014-2015 Sipwise GmbH, http://www.sipwise.com + * Copyright (C) 2020 Mojtaba Esfandiari.S, Nasim-Telecom + * + * This file is part of Kamailio, a free SIP server. + * + * Kamailio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version + * + * Kamailio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef LRKPROXY_HASH_H +#define LRKPROXY_HASH_H + +#include "../../core/str.h" +#include "../../core/locking.h" + + +/* table entry */ +struct lrkproxy_hash_entry { + str src_ipv4; //media ip address of initiator call in INVITE SIP message. + str dst_ipv4; //media ip address of selected node in 200Ok SIP message. + str snat_ipv4; //change media ip address to selected node. + str dnat_ipv4; //change media ip address to orgin destination party. + str src_port; //media port of initiator call in INVITE SIP message + str dst_port; //media port of selected node in 200Ok SIP message. + str snat_port; //change media port to selected node. + str dnat_port; //change media port to orgin destination party. + + str callid; // call callid + str viabranch; // call viabranch + struct lrkp_node *node; // call selected node + + unsigned int tout; // call timeout + struct lrkproxy_hash_entry *next; // call next +}; + +/* table */ +struct lrkproxy_hash_table { + struct lrkproxy_hash_entry **row_entry_list; // vector of size pointers to entry + gen_lock_t **row_locks; // vector of size pointers to locks + unsigned int *row_totals; // vector of size numbers of entries in the hashtable rows + unsigned int size; // hash table size +}; + + + +int lrkproxy_hash_table_init(int hsize); +int lrkproxy_hash_table_destroy(); +int lrkproxy_hash_table_insert(str callid, str viabranch, struct lrkproxy_hash_entry *value); +int lrkproxy_hash_table_remove(str callid, str viabranch, enum lrk_operation); +struct lrkproxy_hash_entry *lrkproxy_hash_table_lookup(str callid, str viabranch); +//struct lrkproxy_hash_entry *lrkproxy_hash_table_lookup(str callid, str viabranch, enum lrk_operation); +//struct lrkp_node *lrkproxy_hash_table_lookup(str callid, str viabranch, enum lrk_operation); +//void lrkproxy_hash_table_print(); +//unsigned int lrkproxy_hash_table_total(); + +void lrkproxy_hash_table_free_entry(struct lrkproxy_hash_entry *entry); +void lrkproxy_hash_table_free_row_entry_list(struct lrkproxy_hash_entry *row_entry_list); + +int lrkproxy_hash_table_sanity_checks(); + +#endif //LRKPROXY_HASH_H diff --git a/src/modules/pv/pv_branch.c b/src/modules/pv/pv_branch.c index 51fb30287f5..d3e34c681a7 100644 --- a/src/modules/pv/pv_branch.c +++ b/src/modules/pv/pv_branch.c @@ -93,6 +93,12 @@ int pv_get_branchx_helper(sip_msg_t *msg, pv_param_t *param, if(br->location_ua_len==0) return pv_get_null(msg, param, res); return pv_get_strlval(msg, param, res, br->location_ua, br->location_ua_len); + case 9: /* otcpid */ + return pv_get_uintval(msg, param, res, br->otcpid); + case 10: /* instance */ + if(br->instance_len==0) + return pv_get_null(msg, param, res); + return pv_get_strlval(msg, param, res, br->instance, br->instance_len); default: /* 0 - uri */ return pv_get_strlval(msg, param, res, br->uri, br->len); @@ -283,6 +289,22 @@ int pv_set_branchx_helper(sip_msg_t *msg, pv_param_t *param, case 8: /* location_ua */ /* do nothing - cannot set the location_ua */ break; + case 9: /* otcpid */ + if(val==NULL || (val->flags&PV_VAL_NULL)) + { + br->otcpid = 0; + break; + } + if(!(val->flags&PV_VAL_INT)) + { + LM_ERR("int value required to set branch flags\n"); + return -1; + } + br->otcpid = val->ri; + break; + case 10: /* instance */ + /* do nothing - cannot set the instance */ + break; default: /* 0 - uri */ if(val==NULL || (val->flags&PV_VAL_NULL)) @@ -335,42 +357,53 @@ int pv_parse_branchx_name(pv_spec_p sp, str *in) switch(in->len) { - case 3: - if(strncmp(in->s, "uri", 3)==0) - sp->pvp.pvn.u.isname.name.n = 0; + case 1: + if(*in->s=='q' || *in->s=='Q') + sp->pvp.pvn.u.isname.name.n = 3; else goto error; break; - case 7: - if(strncmp(in->s, "dst_uri", 7)==0) - sp->pvp.pvn.u.isname.name.n = 1; + case 3: + if(strncmp(in->s, "uri", 3)==0) + sp->pvp.pvn.u.isname.name.n = 0; else goto error; break; - case 4: + case 4: if(strncmp(in->s, "path", 4)==0) sp->pvp.pvn.u.isname.name.n = 2; else if (strncmp(in->s, "ruid", 4)==0) sp->pvp.pvn.u.isname.name.n = 7; else goto error; break; - case 1: - if(*in->s=='q' || *in->s=='Q') - sp->pvp.pvn.u.isname.name.n = 3; + case 5: + if(strncmp(in->s, "count", 5)==0) + sp->pvp.pvn.u.isname.name.n = 5; + else if(strncmp(in->s, "flags", 5)==0) + sp->pvp.pvn.u.isname.name.n = 6; + else goto error; + break; + case 6: + if(strncmp(in->s, "otcpid", 6)==0) + sp->pvp.pvn.u.isname.name.n = 9; + else goto error; + break; + case 7: + if(strncmp(in->s, "dst_uri", 7)==0) + sp->pvp.pvn.u.isname.name.n = 1; + else goto error; + break; + case 8: + if(strncmp(in->s, "instance", 8)==0) + sp->pvp.pvn.u.isname.name.n = 10; else goto error; break; - case 11: + case 11: if(strncmp(in->s, "send_socket", 11)==0) sp->pvp.pvn.u.isname.name.n = 4; else if(strncmp(in->s, "location_ua", 11)==0) sp->pvp.pvn.u.isname.name.n = 8; else goto error; break; - case 5: - if(strncmp(in->s, "count", 5)==0) - sp->pvp.pvn.u.isname.name.n = 5; - else if(strncmp(in->s, "flags", 5)==0) - sp->pvp.pvn.u.isname.name.n = 6; - else goto error; - break; + default: goto error; } @@ -804,6 +837,7 @@ int sbranch_set_ruri(sip_msg_t *msg) set_force_socket(msg, br->force_send_socket); msg->reg_id = br->reg_id; + msg->otcpid = br->otcpid; set_ruri_q(br->q); old_bflags = 0; getbflagsval(0, &old_bflags); @@ -824,7 +858,9 @@ int sbranch_append(sip_msg_t *msg) str path = {0}; str ruid = {0}; str location_ua = {0}; + str instance = {0}; branch_t *br; + branch_t *newbr; br = &_pv_sbranch; if(br->len==0) @@ -849,14 +885,19 @@ int sbranch_append(sip_msg_t *msg) location_ua.s = br->location_ua; location_ua.len = br->location_ua_len; } + if(br->instance_len) { + instance.s = br->instance; + instance.len = br->instance_len; + } - if (append_branch(msg, &uri, &duri, &path, br->q, br->flags, - br->force_send_socket, 0 /*instance*/, br->reg_id, - &ruid, &location_ua) - == -1) { + newbr = ksr_push_branch(msg, &uri, &duri, &path, br->q, br->flags, + br->force_send_socket, &instance, br->reg_id, + &ruid, &location_ua); + if(newbr==NULL) { LM_ERR("failed to append static branch\n"); return -1; } + newbr->otcpid = br->otcpid; return 0; } diff --git a/src/modules/rtp_media_server/Makefile b/src/modules/rtp_media_server/Makefile index 490b7590dc9..5386a3065a2 100644 --- a/src/modules/rtp_media_server/Makefile +++ b/src/modules/rtp_media_server/Makefile @@ -9,5 +9,4 @@ BCUNITLIBS=-lbcunit MS2LIBS=-lmediastreamer LIBS=$(ORTPLIBS) $(BCUNITLIBS) $(MS2LIBS) -DEFS+=-DKAMAILIO_MOD_INTERFACE include ../../Makefile.modules diff --git a/src/modules/textops/README b/src/modules/textops/README index 49a34750c91..b811e08c1ed 100644 --- a/src/modules/textops/README +++ b/src/modules/textops/README @@ -41,63 +41,64 @@ Ovidiu Sas 4.1. search(re) 4.2. search_body(re) - 4.3. search_hf(hf, re, flags) - 4.4. search_append(re, txt) - 4.5. search_append_body(re, txt) - 4.6. replace(re, txt) - 4.7. replace_body(re, txt) - 4.8. replace_hdrs(re, txt) - 4.9. replace_all(re, txt) - 4.10. replace_body_all(re, txt) - 4.11. replace_body_atonce(re, txt) - 4.12. replace_str(match, repl, mode) - 4.13. replace_body_str(match, repl, mode) - 4.14. replace_hdrs_str(match, repl, mode) - 4.15. subst('/re/repl/flags') - 4.16. subst_uri('/re/repl/flags') - 4.17. subst_user('/re/repl/flags') - 4.18. subst_body('/re/repl/flags') - 4.19. subst_hf(hf, subexp, flags) - 4.20. set_body(txt,content_type) - 4.21. set_reply_body(txt,content_type) - 4.22. filter_body(content_type) - 4.23. append_to_reply(txt) - 4.24. append_hf(txt[, hdr]) - 4.25. insert_hf(txt[, hdr]) - 4.26. append_urihf(prefix, suffix) - 4.27. is_present_hf(hf_name) - 4.28. is_present_hf_pv(hf_name) - 4.29. is_present_hf_re(hf_name_re) - 4.30. is_present_hf_re_pv(hf_name_re) - 4.31. append_time() - 4.32. append_time_to_request() - 4.33. is_method(name) - 4.34. remove_hf(hname) - 4.35. remove_hf_pv(hname) - 4.36. remove_hf_re(re) - 4.37. remove_hf_re_pv(re) - 4.38. remove_hf_exp(expmatch, expskip) - 4.39. remove_hf_exp_pv(expmatch, expskip) - 4.40. has_body(), has_body(mime) - 4.41. is_audio_on_hold() - 4.42. is_privacy(privacy_type) - 4.43. in_list(subject, list, separator) - 4.44. in_list_prefix(subject, list, separator) - 4.45. cmp_str(str1, str2) - 4.46. cmp_istr(str1, str2) - 4.47. starts_with(str1, str2) - 4.48. ends_with(str1, str2) - 4.49. set_body_multipart([txt,content_type][,boundary]) - 4.50. append_body_part(txt,content_type[, + 4.3. search_str(text. re) + 4.4. search_hf(hf, re, flags) + 4.5. search_append(re, txt) + 4.6. search_append_body(re, txt) + 4.7. replace(re, txt) + 4.8. replace_body(re, txt) + 4.9. replace_hdrs(re, txt) + 4.10. replace_all(re, txt) + 4.11. replace_body_all(re, txt) + 4.12. replace_body_atonce(re, txt) + 4.13. replace_str(match, repl, mode) + 4.14. replace_body_str(match, repl, mode) + 4.15. replace_hdrs_str(match, repl, mode) + 4.16. subst('/re/repl/flags') + 4.17. subst_uri('/re/repl/flags') + 4.18. subst_user('/re/repl/flags') + 4.19. subst_body('/re/repl/flags') + 4.20. subst_hf(hf, subexp, flags) + 4.21. set_body(txt,content_type) + 4.22. set_reply_body(txt,content_type) + 4.23. filter_body(content_type) + 4.24. append_to_reply(txt) + 4.25. append_hf(txt[, hdr]) + 4.26. insert_hf(txt[, hdr]) + 4.27. append_urihf(prefix, suffix) + 4.28. is_present_hf(hf_name) + 4.29. is_present_hf_pv(hf_name) + 4.30. is_present_hf_re(hf_name_re) + 4.31. is_present_hf_re_pv(hf_name_re) + 4.32. append_time() + 4.33. append_time_to_request() + 4.34. is_method(name) + 4.35. remove_hf(hname) + 4.36. remove_hf_pv(hname) + 4.37. remove_hf_re(re) + 4.38. remove_hf_re_pv(re) + 4.39. remove_hf_exp(expmatch, expskip) + 4.40. remove_hf_exp_pv(expmatch, expskip) + 4.41. has_body(), has_body(mime) + 4.42. is_audio_on_hold() + 4.43. is_privacy(privacy_type) + 4.44. in_list(subject, list, separator) + 4.45. in_list_prefix(subject, list, separator) + 4.46. cmp_str(str1, str2) + 4.47. cmp_istr(str1, str2) + 4.48. starts_with(str1, str2) + 4.49. ends_with(str1, str2) + 4.50. set_body_multipart([txt,content_type][,boundary]) + 4.51. append_body_part(txt,content_type[, content_disposition]) - 4.51. append_body_part_hex(txt,content_type[, + 4.52. append_body_part_hex(txt,content_type[, content_disposition]) - 4.52. get_body_part(content_type, opv) - 4.53. get_body_part_raw(content_type, opv) - 4.54. remove_body_part(content_type) - 4.55. regex_substring(itext, regexp, mindex, mcount, dpv) + 4.53. get_body_part(content_type, opv) + 4.54. get_body_part_raw(content_type, opv) + 4.55. remove_body_part(content_type) + 4.56. regex_substring(itext, regexp, mindex, mcount, dpv) 2. Developer Guide @@ -109,60 +110,61 @@ Ovidiu Sas 1.1. search usage 1.2. search_body usage - 1.3. search_hf usage - 1.4. search_append usage - 1.5. search_append_body usage - 1.6. replace usage - 1.7. replace_body usage - 1.8. replace_hdrs usage - 1.9. replace_all usage - 1.10. replace_body_all usage - 1.11. replace_body_atonce usage - 1.12. replace_str usage - 1.13. replace_body_str usage - 1.14. replace_hdrs_str usage - 1.15. subst usage - 1.16. subst_uri usage - 1.17. subst usage - 1.18. subst_body usage - 1.19. subst_hf usage - 1.20. set_body usage - 1.21. set_reply_body usage - 1.22. filter_body usage - 1.23. append_to_reply usage - 1.24. append_hf usage - 1.25. insert_hf usage - 1.26. append_urihf usage - 1.27. is_present_hf usage - 1.28. is_present_hf_pv usage - 1.29. is_present_hf_re usage - 1.30. is_present_hf_re_pv usage - 1.31. append_time usage - 1.32. append_time_to_request usage - 1.33. is_method usage - 1.34. remove_hf usage - 1.35. remove_hf_pv usage - 1.36. remove_hf_re usage - 1.37. remove_hf_re_pv usage - 1.38. remove_hf_exp usage - 1.39. remove_hf_exp_pv usage - 1.40. has_body usage - 1.41. is_audio_on_hold usage - 1.42. is_privacy usage - 1.43. in_list() usage + 1.3. search_str usage + 1.4. search_hf usage + 1.5. search_append usage + 1.6. search_append_body usage + 1.7. replace usage + 1.8. replace_body usage + 1.9. replace_hdrs usage + 1.10. replace_all usage + 1.11. replace_body_all usage + 1.12. replace_body_atonce usage + 1.13. replace_str usage + 1.14. replace_body_str usage + 1.15. replace_hdrs_str usage + 1.16. subst usage + 1.17. subst_uri usage + 1.18. subst usage + 1.19. subst_body usage + 1.20. subst_hf usage + 1.21. set_body usage + 1.22. set_reply_body usage + 1.23. filter_body usage + 1.24. append_to_reply usage + 1.25. append_hf usage + 1.26. insert_hf usage + 1.27. append_urihf usage + 1.28. is_present_hf usage + 1.29. is_present_hf_pv usage + 1.30. is_present_hf_re usage + 1.31. is_present_hf_re_pv usage + 1.32. append_time usage + 1.33. append_time_to_request usage + 1.34. is_method usage + 1.35. remove_hf usage + 1.36. remove_hf_pv usage + 1.37. remove_hf_re usage + 1.38. remove_hf_re_pv usage + 1.39. remove_hf_exp usage + 1.40. remove_hf_exp_pv usage + 1.41. has_body usage + 1.42. is_audio_on_hold usage + 1.43. is_privacy usage 1.44. in_list() usage - 1.45. cmp_str usage + 1.45. in_list() usage 1.46. cmp_str usage - 1.47. starts_with usage - 1.48. ends_with usage - 1.49. set_body_multipart usage - 1.50. append_body_part usage - 1.51. append_body_part with headers - 1.52. append_body_part_hex usage - 1.53. get_body_part usage - 1.54. get_body_part_raw usage - 1.55. remove_body_part usage - 1.56. _regex_substring usage + 1.47. cmp_str usage + 1.48. starts_with usage + 1.49. ends_with usage + 1.50. set_body_multipart usage + 1.51. append_body_part usage + 1.52. append_body_part with headers + 1.53. append_body_part_hex usage + 1.54. get_body_part usage + 1.55. get_body_part_raw usage + 1.56. remove_body_part usage + 1.57. _regex_substring usage Chapter 1. Admin Guide @@ -179,61 +181,62 @@ Chapter 1. Admin Guide 4.1. search(re) 4.2. search_body(re) - 4.3. search_hf(hf, re, flags) - 4.4. search_append(re, txt) - 4.5. search_append_body(re, txt) - 4.6. replace(re, txt) - 4.7. replace_body(re, txt) - 4.8. replace_hdrs(re, txt) - 4.9. replace_all(re, txt) - 4.10. replace_body_all(re, txt) - 4.11. replace_body_atonce(re, txt) - 4.12. replace_str(match, repl, mode) - 4.13. replace_body_str(match, repl, mode) - 4.14. replace_hdrs_str(match, repl, mode) - 4.15. subst('/re/repl/flags') - 4.16. subst_uri('/re/repl/flags') - 4.17. subst_user('/re/repl/flags') - 4.18. subst_body('/re/repl/flags') - 4.19. subst_hf(hf, subexp, flags) - 4.20. set_body(txt,content_type) - 4.21. set_reply_body(txt,content_type) - 4.22. filter_body(content_type) - 4.23. append_to_reply(txt) - 4.24. append_hf(txt[, hdr]) - 4.25. insert_hf(txt[, hdr]) - 4.26. append_urihf(prefix, suffix) - 4.27. is_present_hf(hf_name) - 4.28. is_present_hf_pv(hf_name) - 4.29. is_present_hf_re(hf_name_re) - 4.30. is_present_hf_re_pv(hf_name_re) - 4.31. append_time() - 4.32. append_time_to_request() - 4.33. is_method(name) - 4.34. remove_hf(hname) - 4.35. remove_hf_pv(hname) - 4.36. remove_hf_re(re) - 4.37. remove_hf_re_pv(re) - 4.38. remove_hf_exp(expmatch, expskip) - 4.39. remove_hf_exp_pv(expmatch, expskip) - 4.40. has_body(), has_body(mime) - 4.41. is_audio_on_hold() - 4.42. is_privacy(privacy_type) - 4.43. in_list(subject, list, separator) - 4.44. in_list_prefix(subject, list, separator) - 4.45. cmp_str(str1, str2) - 4.46. cmp_istr(str1, str2) - 4.47. starts_with(str1, str2) - 4.48. ends_with(str1, str2) - 4.49. set_body_multipart([txt,content_type][,boundary]) - 4.50. append_body_part(txt,content_type[, content_disposition]) - 4.51. append_body_part_hex(txt,content_type[, + 4.3. search_str(text. re) + 4.4. search_hf(hf, re, flags) + 4.5. search_append(re, txt) + 4.6. search_append_body(re, txt) + 4.7. replace(re, txt) + 4.8. replace_body(re, txt) + 4.9. replace_hdrs(re, txt) + 4.10. replace_all(re, txt) + 4.11. replace_body_all(re, txt) + 4.12. replace_body_atonce(re, txt) + 4.13. replace_str(match, repl, mode) + 4.14. replace_body_str(match, repl, mode) + 4.15. replace_hdrs_str(match, repl, mode) + 4.16. subst('/re/repl/flags') + 4.17. subst_uri('/re/repl/flags') + 4.18. subst_user('/re/repl/flags') + 4.19. subst_body('/re/repl/flags') + 4.20. subst_hf(hf, subexp, flags) + 4.21. set_body(txt,content_type) + 4.22. set_reply_body(txt,content_type) + 4.23. filter_body(content_type) + 4.24. append_to_reply(txt) + 4.25. append_hf(txt[, hdr]) + 4.26. insert_hf(txt[, hdr]) + 4.27. append_urihf(prefix, suffix) + 4.28. is_present_hf(hf_name) + 4.29. is_present_hf_pv(hf_name) + 4.30. is_present_hf_re(hf_name_re) + 4.31. is_present_hf_re_pv(hf_name_re) + 4.32. append_time() + 4.33. append_time_to_request() + 4.34. is_method(name) + 4.35. remove_hf(hname) + 4.36. remove_hf_pv(hname) + 4.37. remove_hf_re(re) + 4.38. remove_hf_re_pv(re) + 4.39. remove_hf_exp(expmatch, expskip) + 4.40. remove_hf_exp_pv(expmatch, expskip) + 4.41. has_body(), has_body(mime) + 4.42. is_audio_on_hold() + 4.43. is_privacy(privacy_type) + 4.44. in_list(subject, list, separator) + 4.45. in_list_prefix(subject, list, separator) + 4.46. cmp_str(str1, str2) + 4.47. cmp_istr(str1, str2) + 4.48. starts_with(str1, str2) + 4.49. ends_with(str1, str2) + 4.50. set_body_multipart([txt,content_type][,boundary]) + 4.51. append_body_part(txt,content_type[, content_disposition]) + 4.52. append_body_part_hex(txt,content_type[, content_disposition]) - 4.52. get_body_part(content_type, opv) - 4.53. get_body_part_raw(content_type, opv) - 4.54. remove_body_part(content_type) - 4.55. regex_substring(itext, regexp, mindex, mcount, dpv) + 4.53. get_body_part(content_type, opv) + 4.54. get_body_part_raw(content_type, opv) + 4.55. remove_body_part(content_type) + 4.56. regex_substring(itext, regexp, mindex, mcount, dpv) 1. Overview @@ -274,59 +277,60 @@ From: medabeda 4.1. search(re) 4.2. search_body(re) - 4.3. search_hf(hf, re, flags) - 4.4. search_append(re, txt) - 4.5. search_append_body(re, txt) - 4.6. replace(re, txt) - 4.7. replace_body(re, txt) - 4.8. replace_hdrs(re, txt) - 4.9. replace_all(re, txt) - 4.10. replace_body_all(re, txt) - 4.11. replace_body_atonce(re, txt) - 4.12. replace_str(match, repl, mode) - 4.13. replace_body_str(match, repl, mode) - 4.14. replace_hdrs_str(match, repl, mode) - 4.15. subst('/re/repl/flags') - 4.16. subst_uri('/re/repl/flags') - 4.17. subst_user('/re/repl/flags') - 4.18. subst_body('/re/repl/flags') - 4.19. subst_hf(hf, subexp, flags) - 4.20. set_body(txt,content_type) - 4.21. set_reply_body(txt,content_type) - 4.22. filter_body(content_type) - 4.23. append_to_reply(txt) - 4.24. append_hf(txt[, hdr]) - 4.25. insert_hf(txt[, hdr]) - 4.26. append_urihf(prefix, suffix) - 4.27. is_present_hf(hf_name) - 4.28. is_present_hf_pv(hf_name) - 4.29. is_present_hf_re(hf_name_re) - 4.30. is_present_hf_re_pv(hf_name_re) - 4.31. append_time() - 4.32. append_time_to_request() - 4.33. is_method(name) - 4.34. remove_hf(hname) - 4.35. remove_hf_pv(hname) - 4.36. remove_hf_re(re) - 4.37. remove_hf_re_pv(re) - 4.38. remove_hf_exp(expmatch, expskip) - 4.39. remove_hf_exp_pv(expmatch, expskip) - 4.40. has_body(), has_body(mime) - 4.41. is_audio_on_hold() - 4.42. is_privacy(privacy_type) - 4.43. in_list(subject, list, separator) - 4.44. in_list_prefix(subject, list, separator) - 4.45. cmp_str(str1, str2) - 4.46. cmp_istr(str1, str2) - 4.47. starts_with(str1, str2) - 4.48. ends_with(str1, str2) - 4.49. set_body_multipart([txt,content_type][,boundary]) - 4.50. append_body_part(txt,content_type[, content_disposition]) - 4.51. append_body_part_hex(txt,content_type[, content_disposition]) - 4.52. get_body_part(content_type, opv) - 4.53. get_body_part_raw(content_type, opv) - 4.54. remove_body_part(content_type) - 4.55. regex_substring(itext, regexp, mindex, mcount, dpv) + 4.3. search_str(text. re) + 4.4. search_hf(hf, re, flags) + 4.5. search_append(re, txt) + 4.6. search_append_body(re, txt) + 4.7. replace(re, txt) + 4.8. replace_body(re, txt) + 4.9. replace_hdrs(re, txt) + 4.10. replace_all(re, txt) + 4.11. replace_body_all(re, txt) + 4.12. replace_body_atonce(re, txt) + 4.13. replace_str(match, repl, mode) + 4.14. replace_body_str(match, repl, mode) + 4.15. replace_hdrs_str(match, repl, mode) + 4.16. subst('/re/repl/flags') + 4.17. subst_uri('/re/repl/flags') + 4.18. subst_user('/re/repl/flags') + 4.19. subst_body('/re/repl/flags') + 4.20. subst_hf(hf, subexp, flags) + 4.21. set_body(txt,content_type) + 4.22. set_reply_body(txt,content_type) + 4.23. filter_body(content_type) + 4.24. append_to_reply(txt) + 4.25. append_hf(txt[, hdr]) + 4.26. insert_hf(txt[, hdr]) + 4.27. append_urihf(prefix, suffix) + 4.28. is_present_hf(hf_name) + 4.29. is_present_hf_pv(hf_name) + 4.30. is_present_hf_re(hf_name_re) + 4.31. is_present_hf_re_pv(hf_name_re) + 4.32. append_time() + 4.33. append_time_to_request() + 4.34. is_method(name) + 4.35. remove_hf(hname) + 4.36. remove_hf_pv(hname) + 4.37. remove_hf_re(re) + 4.38. remove_hf_re_pv(re) + 4.39. remove_hf_exp(expmatch, expskip) + 4.40. remove_hf_exp_pv(expmatch, expskip) + 4.41. has_body(), has_body(mime) + 4.42. is_audio_on_hold() + 4.43. is_privacy(privacy_type) + 4.44. in_list(subject, list, separator) + 4.45. in_list_prefix(subject, list, separator) + 4.46. cmp_str(str1, str2) + 4.47. cmp_istr(str1, str2) + 4.48. starts_with(str1, str2) + 4.49. ends_with(str1, str2) + 4.50. set_body_multipart([txt,content_type][,boundary]) + 4.51. append_body_part(txt,content_type[, content_disposition]) + 4.52. append_body_part_hex(txt,content_type[, content_disposition]) + 4.53. get_body_part(content_type, opv) + 4.54. get_body_part_raw(content_type, opv) + 4.55. remove_body_part(content_type) + 4.56. regex_substring(itext, regexp, mindex, mcount, dpv) 4.1. search(re) @@ -335,6 +339,9 @@ From: medabeda Meaning of the parameters is as follows: * re - Regular expression. + Note: it performs Posix regex matching and the 're' parameter is + compiled with the flags REG_EXTENDED|REG_ICASE|REG_NEWLINE. + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. @@ -358,7 +365,24 @@ if ( search("[Ss][Ii][Pp]") ) { /*....*/ }; if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ }; ... -4.3. search_hf(hf, re, flags) +4.3. search_str(text. re) + + Searches for the re in the body of the message. + + Meaning of the parameters is as follows: + * text - text to perform regex searching over it. + * re - regular expression to match over the 'text' parameter. + + Both parameters can contain variables. + + This function can be used from ANY_ROUTE. + + Example 1.3. search_str usage +... +if ( search_str("$ru", ";transport=tcp") ) { /*....*/ }; +... + +4.4. search_hf(hf, re, flags) Searches for the re in the body of a header field. @@ -372,12 +396,12 @@ if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ }; This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.3. search_hf usage + Example 1.4. search_hf usage ... if ( search_hf("From", ":test@", "a") ) { /*....*/ }; ... -4.4. search_append(re, txt) +4.5. search_append(re, txt) Searches for the first match of re and appends txt after it. @@ -388,12 +412,12 @@ if ( search_hf("From", ":test@", "a") ) { /*....*/ }; This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.4. search_append usage + Example 1.5. search_append usage ... search_append("[Oo]pen[Ss]er", " SIP Proxy"); ... -4.5. search_append_body(re, txt) +4.6. search_append_body(re, txt) Searches for the first match of re in the body of the message and appends txt after it. @@ -405,12 +429,12 @@ search_append("[Oo]pen[Ss]er", " SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.5. search_append_body usage + Example 1.6. search_append_body usage ... search_append_body("[Oo]pen[Ss]er", " SIP Proxy"); ... -4.6. replace(re, txt) +4.7. replace(re, txt) Replaces the first occurrence of re with txt. @@ -421,12 +445,12 @@ search_append_body("[Oo]pen[Ss]er", " SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.6. replace usage + Example 1.7. replace usage ... replace("openser", "Kamailio SIP Proxy"); ... -4.7. replace_body(re, txt) +4.8. replace_body(re, txt) Replaces the first occurrence of re in the body of the message with txt. @@ -438,12 +462,12 @@ replace("openser", "Kamailio SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.7. replace_body usage + Example 1.8. replace_body usage ... replace_body("openser", "Kamailio SIP Proxy"); ... -4.8. replace_hdrs(re, txt) +4.9. replace_hdrs(re, txt) Replaces the first occurrence of re in the SIP headers of the message with txt. @@ -454,12 +478,12 @@ replace_body("openser", "Kamailio SIP Proxy"); This function can be used from ANY_ROUTE. - Example 1.8. replace_hdrs usage + Example 1.9. replace_hdrs usage ... replace_hdrs("Kamailio", "Kamailio SIP Proxy"); ... -4.9. replace_all(re, txt) +4.10. replace_all(re, txt) Replaces all occurrence of re with txt. @@ -470,12 +494,12 @@ replace_hdrs("Kamailio", "Kamailio SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.9. replace_all usage + Example 1.10. replace_all usage ... replace_all("openser", "Kamailio SIP Proxy"); ... -4.10. replace_body_all(re, txt) +4.11. replace_body_all(re, txt) Replaces all occurrence of re in the body of the message with txt. Matching is done on a per-line basis. @@ -487,12 +511,12 @@ replace_all("openser", "Kamailio SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.10. replace_body_all usage + Example 1.11. replace_body_all usage ... replace_body_all("openser", "Kamailio SIP Proxy"); ... -4.11. replace_body_atonce(re, txt) +4.12. replace_body_atonce(re, txt) Replaces all occurrence of re in the body of the message with txt. Matching is done over the whole body. @@ -504,14 +528,14 @@ replace_body_all("openser", "Kamailio SIP Proxy"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.11. replace_body_atonce usage + Example 1.12. replace_body_atonce usage ... # strip the whole body from the message: if(has_body() && replace_body_atonce("^.+$", "")) remove_hf("Content-Type"); ... -4.12. replace_str(match, repl, mode) +4.13. replace_str(match, repl, mode) Replaces the first or all occurrence of 'match' with 'repl' by doing string comparison for matching. It is applied over headers and message @@ -524,12 +548,12 @@ if(has_body() && replace_body_atonce("^.+$", "")) This function can be used from ANY_ROUTE. - Example 1.12. replace_str usage + Example 1.13. replace_str usage ... replace_str("Kamailio", "Kamailio SIP Proxy", "a"); ... -4.13. replace_body_str(match, repl, mode) +4.14. replace_body_str(match, repl, mode) Replaces the first or all occurrence of 'match' with 'repl' by doing string comparison for matching. It is applied over the message body. @@ -541,12 +565,12 @@ replace_str("Kamailio", "Kamailio SIP Proxy", "a"); This function can be used from ANY_ROUTE. - Example 1.13. replace_body_str usage + Example 1.14. replace_body_str usage ... replace_body_str("Kamailio", "Kamailio SIP Proxy", "a"); ... -4.14. replace_hdrs_str(match, repl, mode) +4.15. replace_hdrs_str(match, repl, mode) Replaces the first or all occurrence of 'match' with 'repl' by doing string comparison for matching. It is applied over the part with @@ -559,12 +583,12 @@ replace_body_str("Kamailio", "Kamailio SIP Proxy", "a"); This function can be used from ANY_ROUTE. - Example 1.14. replace_hdrs_str usage + Example 1.15. replace_hdrs_str usage ... replace_hdrs_str("Kamailio", "Kamailio SIP Proxy", "a"); ... -4.15. subst('/re/repl/flags') +4.16. subst('/re/repl/flags') Replaces re with repl (sed or perl like). @@ -579,7 +603,7 @@ replace_hdrs_str("Kamailio", "Kamailio SIP Proxy", "a"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.15. subst usage + Example 1.16. subst usage ... # replace the uri in to: with the message uri (just an example) if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1\u\2/ig') ) {}; @@ -590,7 +614,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') ) ... -4.16. subst_uri('/re/repl/flags') +4.17. subst_uri('/re/repl/flags') Runs the re substitution on the message uri (like subst but works only on the uri) @@ -606,7 +630,7 @@ if ( subst('/^To:(.*)sip:[^@]*@[a-zA-Z0-9.]+(.*)$/t:\1$avp(sip_address)\2/ig') ) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.16. subst_uri usage + Example 1.17. subst_uri usage ... # adds 3463 prefix to numeric uris, and save the original uri (\0 match) # as a parameter: orig_uri (just an example) @@ -618,7 +642,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$ ... -4.17. subst_user('/re/repl/flags') +4.18. subst_user('/re/repl/flags') Runs the re substitution on the message uri (like subst_uri but works only on the user portion of the uri) @@ -634,7 +658,7 @@ if (subst_uri('/^sip:([0-9]+)@(.*)$/sip:$avp(uri_prefix)\1@\2;orig_uri=\0/i')){$ This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.17. subst usage + Example 1.18. subst usage ... # adds 3463 prefix to uris ending with 3642 (just an example) if (subst_user('/3642$/36423463/')){$ @@ -645,7 +669,7 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$ ... -4.18. subst_body('/re/repl/flags') +4.19. subst_body('/re/repl/flags') Replaces re with repl (sed or perl like) in the body of the message. @@ -660,13 +684,13 @@ if (subst_user('/(.*)3642$/$avp(user_prefix)\13642/')){$ This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.18. subst_body usage + Example 1.19. subst_body usage ... if ( subst_body('/^o=(.*) /o=$fU /') ) {}; ... -4.19. subst_hf(hf, subexp, flags) +4.20. subst_hf(hf, subexp, flags) Perl-like substitutions in the body of a header field. @@ -681,12 +705,12 @@ if ( subst_body('/^o=(.*) /o=$fU /') ) {}; This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.19. subst_hf usage + Example 1.20. subst_hf usage ... if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ }; ... -4.20. set_body(txt,content_type) +4.21. set_body(txt,content_type) Set body to a SIP message. @@ -698,12 +722,12 @@ if ( subst_hf("From", "/:test@/:best@/", "a") ) { /*....*/ }; This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.20. set_body usage + Example 1.21. set_body usage ... set_body("test", "text/plain"); ... -4.21. set_reply_body(txt,content_type) +4.22. set_reply_body(txt,content_type) Set body to a SIP reply to be generated by Kamailio. @@ -715,12 +739,12 @@ set_body("test", "text/plain"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.21. set_reply_body usage + Example 1.22. set_reply_body usage ... set_reply_body("test", "text/plain"); ... -4.22. filter_body(content_type) +4.23. filter_body(content_type) Filters multipart/mixed body by leaving out all other body parts except the first body part of given type. @@ -731,7 +755,7 @@ set_reply_body("test", "text/plain"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.22. filter_body usage + Example 1.23. filter_body usage ... if (has_body("multipart/mixed")) { if (filter_body("application/sdp") { @@ -743,7 +767,7 @@ if (has_body("multipart/mixed")) { } ... -4.23. append_to_reply(txt) +4.24. append_to_reply(txt) Append txt as header to the reply that is going to be generated by Kamailio (e.g., via sl_send_reply(...)). @@ -756,13 +780,13 @@ if (has_body("multipart/mixed")) { This function can be used from REQUEST_ROUTE, BRANCH_ROUTE, FAILURE_ROUTE, ERROR_ROUTE. - Example 1.23. append_to_reply usage + Example 1.24. append_to_reply usage ... append_to_reply("Foo: bar\r\n"); append_to_reply("Foo: $rm at $Ts\r\n"); ... -4.24. append_hf(txt[, hdr]) +4.25. append_hf(txt[, hdr]) Appends 'txt' as header at the end of the all headers, or after last header named 'hdr' if the second parameter is provided. @@ -777,13 +801,13 @@ append_to_reply("Foo: $rm at $Ts\r\n"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.24. append_hf usage + Example 1.25. append_hf usage ... append_hf("P-hint: VOICEMAIL\r\n"); append_hf("From-username: $fU\r\n", "Call-ID"); ... -4.25. insert_hf(txt[, hdr]) +4.26. insert_hf(txt[, hdr]) Inserts 'txt' as header before the first header field, or before first header named 'hdr'if the second parameter is provided. @@ -798,7 +822,7 @@ append_hf("From-username: $fU\r\n", "Call-ID"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.25. insert_hf usage + Example 1.26. insert_hf usage ... insert_hf("P-hint: VOICEMAIL\r\n"); insert_hf("To-username: $tU\r\n"); @@ -806,7 +830,7 @@ insert_hf("P-hint: VOICEMAIL\r\n", "Call-ID"); insert_hf("To-username: $tU\r\n", "Call-ID"); ... -4.26. append_urihf(prefix, suffix) +4.27. append_urihf(prefix, suffix) Append header field name with original Request-URI in middle. @@ -817,12 +841,12 @@ insert_hf("To-username: $tU\r\n", "Call-ID"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.26. append_urihf usage + Example 1.27. append_urihf usage ... append_urihf("CC-Diversion: ", "\r\n"); ... -4.27. is_present_hf(hf_name) +4.28. is_present_hf(hf_name) Return true if a header field is present in message. @@ -838,22 +862,22 @@ Note This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.27. is_present_hf usage + Example 1.28. is_present_hf usage ... if (is_present_hf("From")) xlog("From HF Present"); ... -4.28. is_present_hf_pv(hf_name) +4.29. is_present_hf_pv(hf_name) Same as is_present_hf() function, but the parameter can contain variables. - Example 1.28. is_present_hf_pv usage + Example 1.29. is_present_hf_pv usage ... if (is_present_hf_pv("$var(hname)")) xinfo("Header $var(hname) is present\n"); ... -4.29. is_present_hf_re(hf_name_re) +4.30. is_present_hf_re(hf_name_re) Return true if a header field whose name matches regular expression 'hf_name_re' is present in message. @@ -865,24 +889,24 @@ if (is_present_hf_pv("$var(hname)")) xinfo("Header $var(hname) is present\n"); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.29. is_present_hf_re usage + Example 1.30. is_present_hf_re usage ... if (is_present_hf_re("^P-")) xlog("There are headers starting with P-\n"); ... -4.30. is_present_hf_re_pv(hf_name_re) +4.31. is_present_hf_re_pv(hf_name_re) Same as is_present_hf_re() function, but the parameter can contain variables. - Example 1.30. is_present_hf_re_pv usage + Example 1.31. is_present_hf_re_pv usage ... if (is_present_hf_re_pv_("^$var(prefix)")) xlog("There are headers starting with $var(prefix)\n"); ... -4.31. append_time() +4.32. append_time() Adds a time header to the reply of the request. You must use it before functions that are likely to send a reply, e.g., save() from @@ -901,12 +925,12 @@ if (is_present_hf_re_pv_("^$var(prefix)")) This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.31. append_time usage + Example 1.32. append_time usage ... append_time(); ... -4.32. append_time_to_request() +4.33. append_time_to_request() Adds a time header to the request. Header format is: “Date: %a, %d %b %Y %H:%M:%S GMT”, with the legend: @@ -923,13 +947,13 @@ append_time(); This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. - Example 1.32. append_time_to_request usage + Example 1.33. append_time_to_request usage ... if(!is_present_hf("Date")) append_time_to_request(); ... -4.33. is_method(name) +4.34. is_method(name) Check if the method of the message matches the name. If name is a known method (invite, cancel, ack, bye, options, info, update, register, @@ -954,7 +978,7 @@ if(!is_present_hf("Date")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, and BRANCH_ROUTE. - Example 1.33. is_method usage + Example 1.34. is_method usage ... if(is_method("INVITE")) { @@ -966,7 +990,7 @@ if(is_method("OPTION|UPDATE")) } ... -4.34. remove_hf(hname) +4.35. remove_hf(hname) Remove from message all headers with name “hname”. Header matching is case-insensitive. Matches and removes also the compact header forms. @@ -981,7 +1005,7 @@ if(is_method("OPTION|UPDATE")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.34. remove_hf usage + Example 1.35. remove_hf usage ... if(remove_hf("User-Agent")) { @@ -993,16 +1017,16 @@ remove_hf("Contact"); remove_hf("m"); ... -4.35. remove_hf_pv(hname) +4.36. remove_hf_pv(hname) Same as remove_hf() function, but the parameter can contain variables. - Example 1.35. remove_hf_pv usage + Example 1.36. remove_hf_pv usage ... remove_hf_pv("$var(hname)"); ... -4.36. remove_hf_re(re) +4.37. remove_hf_re(re) Remove from message all headers with name matching regular expression “re” @@ -1014,7 +1038,7 @@ remove_hf_pv("$var(hname)"); This function can be used from ANY_ROUTE. - Example 1.36. remove_hf_re usage + Example 1.37. remove_hf_re usage ... if(remove_hf_re("^P-")) { @@ -1022,12 +1046,12 @@ if(remove_hf_re("^P-")) } ... -4.37. remove_hf_re_pv(re) +4.38. remove_hf_re_pv(re) Same as remove_hf_re() function, but the parameter can contain variables. - Example 1.37. remove_hf_re_pv usage + Example 1.38. remove_hf_re_pv usage ... if(remove_hf_re_pv("^$var(prefix)")) { @@ -1035,7 +1059,7 @@ if(remove_hf_re_pv("^$var(prefix)")) } ... -4.38. remove_hf_exp(expmatch, expskip) +4.39. remove_hf_exp(expmatch, expskip) Remove from message all headers with name matching regular expression “expmatch”, but not matching regular expression “expskip”. @@ -1050,7 +1074,7 @@ if(remove_hf_re_pv("^$var(prefix)")) This function can be used from ANY_ROUTE. - Example 1.38. remove_hf_exp usage + Example 1.39. remove_hf_exp usage ... if(remove_hf_exp("^P-", "^P-Keep-")) { @@ -1059,12 +1083,12 @@ if(remove_hf_exp("^P-", "^P-Keep-")) } ... -4.39. remove_hf_exp_pv(expmatch, expskip) +4.40. remove_hf_exp_pv(expmatch, expskip) Same as remove_hf_exp() function, but the parameters can contain variabes. - Example 1.39. remove_hf_exp_pv usage + Example 1.40. remove_hf_exp_pv usage ... if(remove_hf_exp_pv("^$var(match)", "^$var(keep)")) { @@ -1073,7 +1097,7 @@ if(remove_hf_exp_pv("^$var(match)", "^$var(keep)")) } ... -4.40. has_body(), has_body(mime) +4.41. has_body(), has_body(mime) The function returns true if the SIP message has a body attached. The checked includes also the “Content-Length” header presence and value. @@ -1088,7 +1112,7 @@ if(remove_hf_exp_pv("^$var(match)", "^$var(keep)")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.40. has_body usage + Example 1.41. has_body usage ... if(has_body("application/sdp")) { @@ -1096,7 +1120,7 @@ if(has_body("application/sdp")) } ... -4.41. is_audio_on_hold() +4.42. is_audio_on_hold() The function returns true if the SIP message has a body attached and at least one audio stream in on hold. The return code of the function @@ -1107,7 +1131,7 @@ if(has_body("application/sdp")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.41. is_audio_on_hold usage + Example 1.42. is_audio_on_hold usage ... if(is_audio_on_hold()) { @@ -1123,7 +1147,7 @@ if(is_audio_on_hold()) } ... -4.42. is_privacy(privacy_type) +4.43. is_privacy(privacy_type) The function returns true if the SIP message has a Privacy header field that includes the given privacy_type among its privacy values. See @@ -1133,7 +1157,7 @@ if(is_audio_on_hold()) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.42. is_privacy usage + Example 1.43. is_privacy usage ... if(is_privacy("id")) { @@ -1141,7 +1165,7 @@ if(is_privacy("id")) } ... -4.43. in_list(subject, list, separator) +4.44. in_list(subject, list, separator) Function checks if subject string is found in list string where list items are separated by separator string. Subject and list strings may @@ -1150,7 +1174,7 @@ if(is_privacy("id")) Function can be used from all kinds of routes. - Example 1.43. in_list() usage + Example 1.44. in_list() usage ... $var(subject) = "fi"; $var(list) = "dk,fi,no,se"; @@ -1159,7 +1183,7 @@ if (in_list("$var(subject)", "$var(list)", ",")) { } ... -4.44. in_list_prefix(subject, list, separator) +4.45. in_list_prefix(subject, list, separator) Function checks if any element in list string is a prefix for subject string where list items are separated by separator string. Subject and @@ -1168,7 +1192,7 @@ if (in_list("$var(subject)", "$var(list)", ",")) { Function can be used from all kinds of routes. - Example 1.44. in_list() usage + Example 1.45. in_list() usage ... $var(subject) = "final"; $var(list) = "dk,fi,no,se"; @@ -1177,7 +1201,7 @@ if (in_list_prefix("$var(subject)", "$var(list)", ",")) { } ... -4.45. cmp_str(str1, str2) +4.46. cmp_str(str1, str2) The function returns true if the two parameters matches as string case sensitive comparison. @@ -1185,7 +1209,7 @@ if (in_list_prefix("$var(subject)", "$var(list)", ",")) { This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.45. cmp_str usage + Example 1.46. cmp_str usage ... if(cmp_str("$rU", "kamailio")) { @@ -1193,7 +1217,7 @@ if(cmp_str("$rU", "kamailio")) } ... -4.46. cmp_istr(str1, str2) +4.47. cmp_istr(str1, str2) The function returns true if the two parameters matches as string case insensitive comparison. @@ -1201,7 +1225,7 @@ if(cmp_str("$rU", "kamailio")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.46. cmp_str usage + Example 1.47. cmp_str usage ... if(cmp_istr("$rU@you", "kamailio@YOU")) { @@ -1209,7 +1233,7 @@ if(cmp_istr("$rU@you", "kamailio@YOU")) } ... -4.47. starts_with(str1, str2) +4.48. starts_with(str1, str2) The function returns true if the first string starts with the second string. @@ -1217,7 +1241,7 @@ if(cmp_istr("$rU@you", "kamailio@YOU")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.47. starts_with usage + Example 1.48. starts_with usage ... if (starts_with("$rU", "+358")) { @@ -1225,7 +1249,7 @@ if (starts_with("$rU", "+358")) } ... -4.48. ends_with(str1, str2) +4.49. ends_with(str1, str2) The function returns true if the first string ends with the second string. The parameters can contain variables. @@ -1233,7 +1257,7 @@ if (starts_with("$rU", "+358")) This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE and BRANCH_ROUTE. - Example 1.48. ends_with usage + Example 1.49. ends_with usage ... if (ends_with("$rU", "8800")) { @@ -1241,7 +1265,7 @@ if (ends_with("$rU", "8800")) } ... -4.49. set_body_multipart([txt,content_type][,boundary]) +4.50. set_body_multipart([txt,content_type][,boundary]) Set multipart body to a SIP message. If called with no parameters, will convert present body to multipart. @@ -1262,7 +1286,7 @@ if (ends_with("$rU", "8800")) Note: it may be required that msg_apply_changes() from textopsx module has to be executed if there are other operations over the new body. - Example 1.49. set_body_multipart usage + Example 1.50. set_body_multipart usage ... set_body_multipart("test", "text/plain", "delimiter"); msg_apply_changes(); @@ -1285,7 +1309,7 @@ text --delimiter ... -4.50. append_body_part(txt,content_type[, content_disposition]) +4.51. append_body_part(txt,content_type[, content_disposition]) Append a part on multipart body SIP message. Will use "unique-boundary-1" as boundary. @@ -1306,7 +1330,7 @@ text Note: it may be required that msg_apply_changes() from textopsx module has to be executed if there are other operations over the new body. - Example 1.50. append_body_part usage + Example 1.51. append_body_part usage ... $var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"; append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext", "signal;handling @@ -1329,7 +1353,7 @@ Content-Disposition: signal;handling=required appended after the value of the content-type parameter, separated by `\r\n` (at the very end do not add the '\r\n'). - Example 1.51. append_body_part with headers + Example 1.52. append_body_part with headers ... $var(b) = "7e Od 04 55 75 69 20 4d 61 6b 65 43 61 6c 6c"; append_body_part("$var(b)", "application/vnd.cirpack.isdn-ext\r\nX-Header: xyz", @@ -1349,7 +1373,7 @@ Content-Disposition: signal;handling=required --unique-boundary-1 ... -4.51. append_body_part_hex(txt,content_type[, content_disposition]) +4.52. append_body_part_hex(txt,content_type[, content_disposition]) Append a part on multipart body SIP message, with the content provided in hexa format. Will use "unique-boundary-1" as boundary. @@ -1373,7 +1397,7 @@ Content-Disposition: signal;handling=required Note: it may be required that msg_apply_changes() from textopsx module has to be executed if there are other operations over the new body. - Example 1.52. append_body_part_hex usage + Example 1.53. append_body_part_hex usage ... $var(b) = "6b 61 6d 61 69 6c 69 6f"; append_body_part_hex("$var(b)", "application/my-custom-ext"); @@ -1393,7 +1417,7 @@ kamailio If other headers are wanted to be added for a body part, see the docs for append_body_part(...) function. -4.52. get_body_part(content_type, opv) +4.53. get_body_part(content_type, opv) Return the content of a multipart body SIP message, storing it in opv. @@ -1406,12 +1430,12 @@ kamailio This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE. - Example 1.53. get_body_part usage + Example 1.54. get_body_part usage ... get_body_part("application/vnd.cirpack.isdn-ext", "$var(pbody)"); ... -4.53. get_body_part_raw(content_type, opv) +4.54. get_body_part_raw(content_type, opv) Return the content of a multipart body SIP message, including headers and boundary string, storing it in opv. @@ -1425,12 +1449,12 @@ get_body_part("application/vnd.cirpack.isdn-ext", "$var(pbody)"); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, ONREPLY_ROUTE. - Example 1.54. get_body_part_raw usage + Example 1.55. get_body_part_raw usage ... get_body_part("application/vnd.cirpack.isdn-ext", "$var(hbody)"); ... -4.54. remove_body_part(content_type) +4.55. remove_body_part(content_type) Remove a part on a multipart body SIP message. @@ -1448,13 +1472,13 @@ get_body_part("application/vnd.cirpack.isdn-ext", "$var(hbody)"); Note: it may be required that msg_apply_changes() from textopsx module has to be executed if there are other operations over the new body. - Example 1.55. remove_body_part usage + Example 1.56. remove_body_part usage ... remove_body_part("application/vnd.cirpack.isdn-ext"); msg_apply_changes(); ... -4.55. regex_substring(itext, regexp, mindex, mcount, dpv) +4.56. regex_substring(itext, regexp, mindex, mcount, dpv) Search in text with given regular expression then sets dpv pseudo-variable with the matched token at provided index. @@ -1474,7 +1498,7 @@ msg_apply_changes(); Note that the regular expression extended is used. More info at: https://www.regular-expressions.info/posix.html. - Example 1.56. _regex_substring usage + Example 1.57. _regex_substring usage ... regex_substring("___ abc123def ___ ghi456 ___", "([a-z]*)([0-9]+)([a-z]* )", diff --git a/src/modules/textops/doc/textops_admin.xml b/src/modules/textops/doc/textops_admin.xml index e9acba38694..479b8f1cd17 100644 --- a/src/modules/textops/doc/textops_admin.xml +++ b/src/modules/textops/doc/textops_admin.xml @@ -90,6 +90,10 @@ From: medabeda + + Note: it performs Posix regex matching and the 're' parameter + is compiled with the flags REG_EXTENDED|REG_ICASE|REG_NEWLINE. + This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE. @@ -128,6 +132,42 @@ if ( search("[Ss][Ii][Pp]") ) { /*....*/ }; ... if ( search_body("[Ss][Ii][Pp]") ) { /*....*/ }; ... + + + + +
+ + <function moreinfo="none">search_str(text. re)</function> + + + Searches for the re in the body of the message. + + Meaning of the parameters is as follows: + + + text - text to perform regex searching + over it. + + + + re - regular expression to match over + the 'text' parameter. + + + + + Both parameters can contain variables. + + + This function can be used from ANY_ROUTE. + + + <function>search_str</function> usage + +... +if ( search_str("$ru", ";transport=tcp") ) { /*....*/ }; +...
diff --git a/src/modules/textops/textops.c b/src/modules/textops/textops.c index 6f3c6f9b5e2..1b045dc89c5 100644 --- a/src/modules/textops/textops.c +++ b/src/modules/textops/textops.c @@ -148,6 +148,7 @@ static int is_present_hf_re_pv_f(sip_msg_t* msg, char* key, char* foo); static int is_audio_on_hold_f(struct sip_msg *msg, char *str1, char *str2 ); static int regex_substring_f(struct sip_msg *msg, char *input, char *regex, char *matched_index, char *match_count, char *dst); +static int w_search_str(sip_msg_t *msg, char *ptext, char *pre); static int fixup_substre(void**, int); static int hname_fixup(void** param, int param_no); static int free_hname_fixup(void** param, int param_no); @@ -314,6 +315,9 @@ static cmd_export_t cmds[]={ {"cmp_istr", (cmd_function)cmp_istr_f, 2, fixup_spve_spve, 0, ANY_ROUTE}, + {"search_str", (cmd_function)w_search_str, 2, + fixup_spve_spve, 0, + ANY_ROUTE}, {"starts_with", (cmd_function)starts_with_f, 2, fixup_spve_spve, 0, ANY_ROUTE}, @@ -4593,6 +4597,61 @@ static int fixup_subst_hf(void** param, int param_no) return 0; } +/** + * + */ +static int ki_search_str(sip_msg_t *msg, str *stext, str *sre) +{ + int ret; + regex_t re; + regmatch_t pmatch; + + + if(sre==NULL || sre->len<=0) { + return 2; + } + + if(stext==NULL || stext->len<=0) { + return -2; + } + + memset(&re, 0, sizeof(regex_t)); + if (regcomp(&re, sre->s, REG_EXTENDED|REG_ICASE|REG_NEWLINE)!=0) { + LM_ERR("failed to compile regex: %.*s\n", sre->len, sre->s); + return -2; + } + + if (regexec(&re, stext->s, 1, &pmatch, 0)!=0) { + ret = -1; + } else { + ret = 1; + } + + regfree(&re); + + return ret; +} + +/** + * + */ +static int w_search_str(sip_msg_t *msg, char *ptext, char *pre) +{ + str stext; + str sre; + + if(fixup_get_svalue(msg, (gparam_t*)ptext, &stext)!=0) { + LM_ERR("cannot get first parameter\n"); + return -2; + } + if(fixup_get_svalue(msg, (gparam_t*)pre, &sre)!=0) { + LM_ERR("cannot get second parameter\n"); + return -2; + } + + return ki_search_str(msg, &stext, &sre); +} + /** * */ @@ -4945,6 +5004,11 @@ static sr_kemi_t sr_kemi_textops_exports[] = { { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } }, + { str_init("textops"), str_init("search_str"), + SR_KEMIP_INT, ki_search_str, + { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, + SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE } + }, { str_init("textops"), str_init("starts_with"), SR_KEMIP_INT, ki_starts_with, { SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE, diff --git a/src/modules/topos/README b/src/modules/topos/README index 1dcff2ad07c..39a113ce368 100644 --- a/src/modules/topos/README +++ b/src/modules/topos/README @@ -10,7 +10,13 @@ Daniel-Constantin Mierla +Frederic Gaisnon + + + Copyright © 2016 FhG FOKUS + + Copyright © 2021 MomentTech __________________________________________________________________ Table of Contents @@ -112,8 +118,8 @@ Chapter 1. Admin Guide It also works for SIP MESSAGE or other requests that do not create a dialog -- record_route() must be used for them as well, the headers are not going to be in the messages sent to the network, they are needed to - know local addresses used to communicate with each side. At this moment - it is not designed to work for presence (SUBSCRIBE-based) dialogs. The + know local addresses used to communicate with each side. This module is + designed to work for presence (SUBSCRIBE-based) dialogs too. The REGISTER and PUBLISH requests are skipped from processing by this module, expected to be terminated on a local SIP server. @@ -225,7 +231,10 @@ modparam("topos", "branch_expire", 300) mind that the module does not update the dialog timestamp after the initial call setup on re-INVITEs or other in-dialog messages. So set a large enough value (according your longest call duration) to prevent - problems in re-writing messages. + problems in re-writing messages. This key is only relevant for INVITE + dialog. SUBSCRIBE dialog records lifetime are based on value set in + expires header. Moreover each re-SUBSCRIBEs update the dialog + timestamp. Default value is 10800 (3 hours). diff --git a/src/modules/topos/doc/topos.xml b/src/modules/topos/doc/topos.xml index 38d3c0cea63..55a72868a93 100644 --- a/src/modules/topos/doc/topos.xml +++ b/src/modules/topos/doc/topos.xml @@ -23,11 +23,20 @@ Mierla miconda@gmail.com + + Frederic + Gaisnon + frederic.gaisnon@gmail.com + 2016 &fhg; + + 2021 + MomentTech + diff --git a/src/modules/topos/doc/topos_admin.xml b/src/modules/topos/doc/topos_admin.xml index 959e7e0f3e5..1cabfccf076 100644 --- a/src/modules/topos/doc/topos_admin.xml +++ b/src/modules/topos/doc/topos_admin.xml @@ -30,8 +30,8 @@ a dialog -- record_route() must be used for them as well, the headers are not going to be in the messages sent to the network, they are needed to know local addresses used to communicate with each side. - At this moment it is not designed to work for presence (SUBSCRIBE-based) - dialogs. The REGISTER and PUBLISH requests are skipped from processing + This module is designed to work for presence (SUBSCRIBE-based) dialogs too. + The REGISTER and PUBLISH requests are skipped from processing by this module, expected to be terminated on a local SIP server.
@@ -199,6 +199,9 @@ modparam("topos", "branch_expire", 300) after the initial call setup on re-INVITEs or other in-dialog messages. So set a large enough value (according your longest call duration) to prevent problems in re-writing messages. + This key is only relevant for INVITE dialog. + SUBSCRIBE dialog records lifetime are based on value set in expires + header. Moreover each re-SUBSCRIBEs update the dialog timestamp. diff --git a/src/modules/topos/tps_msg.c b/src/modules/topos/tps_msg.c index 3130a98f8b3..8ee2fb355f0 100644 --- a/src/modules/topos/tps_msg.c +++ b/src/modules/topos/tps_msg.c @@ -905,6 +905,11 @@ int tps_request_received(sip_msg_t *msg, int dialog) goto error; } } + if((get_cseq(msg)->method_id)&(METHOD_SUBSCRIBE)) { + if(tps_storage_update_dialog(msg, &mtsd, &stsd, TPS_DBU_CONTACT|TPS_DBU_TIME)<0) { + goto error; + } + } } return 0; diff --git a/src/modules/topos/tps_storage.c b/src/modules/topos/tps_storage.c index e23352962ea..c0bf33be357 100644 --- a/src/modules/topos/tps_storage.c +++ b/src/modules/topos/tps_storage.c @@ -41,6 +41,7 @@ #include "../../core/parser/contact/parse_contact.h" #include "../../core/parser/parse_from.h" #include "../../core/parser/parse_to.h" +#include "../../core/parser/parse_expires.h" #include "../../lib/srdb1/db.h" #include "../../core/utils/sruid.h" @@ -336,8 +337,11 @@ int tps_storage_fill_contact(sip_msg_t *msg, tps_data_t *td, str *uuid, int dir, td->cp += pv_val.rs.len; } } - *td->cp = '@'; - td->cp++; + + if (!((ctmode == 1) && (dir==TPS_DIR_DOWNSTREAM) && (curi.user.len <= 0))) { + *td->cp = '@'; + td->cp++; + } if (_tps_contact_host.len) { // using configured hostname in the contact header memcpy(td->cp, _tps_contact_host.s, _tps_contact_host.len); @@ -465,8 +469,8 @@ int tps_storage_link_msg(sip_msg_t *msg, tps_data_t *td, int dir) /* extract the contact address */ if(parse_headers(msg, HDR_CONTACT_F, 0)<0 || msg->contact==NULL) { - if(td->s_method_id != METHOD_INVITE) { - /* no mandatory contact unless is INVITE - done */ + if((td->s_method_id != METHOD_INVITE) && (td->s_method_id != METHOD_SUBSCRIBE)){ + /* no mandatory contact unless is INVITE or SUBSCRIBE - done */ return 0; } if(msg->first_line.type==SIP_REPLY) { @@ -504,6 +508,13 @@ int tps_storage_link_msg(sip_msg_t *msg, tps_data_t *td, int dir) } } + if (td->s_method_id == METHOD_SUBSCRIBE) { + if(msg->expires && (msg->expires->body.len > 0) && (msg->expires->parsed || (parse_expires(msg->expires) >= 0))) { + td->expires = ((exp_body_t *)msg->expires->parsed)->val; + } + } + + LM_DBG("downstream: %s - acontact: [%.*s] - bcontact: [%.*s]\n", (dir==TPS_DIR_DOWNSTREAM)?"yes":"no", td->a_contact.len, (td->a_contact.len>0)?td->a_contact.s:"", @@ -1036,6 +1047,8 @@ int tps_db_load_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, db_key_t db_cols[TPS_NR_KEYS]; db1_res_t* db_res = NULL; str sinv = str_init("INVITE"); + str ssub = str_init("SUBSCRIBE"); + int bInviteDlg = 1; int nr_keys; int nr_cols; int n; @@ -1047,6 +1060,10 @@ int tps_db_load_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, nr_keys = 0; nr_cols = 0; + if((get_cseq(msg)->method_id == METHOD_SUBSCRIBE) || ((get_cseq(msg)->method_id == METHOD_NOTIFY) && (msg->event->len > 0))) { + bInviteDlg = 0; + } + if(mode==0) { /* load same transaction using Via branch */ db_keys[nr_keys]=&tt_col_x_vbranch; @@ -1075,7 +1092,7 @@ int tps_db_load_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, db_ops[nr_keys]=OP_EQ; db_vals[nr_keys].type = DB1_STR; db_vals[nr_keys].nul = 0; - db_vals[nr_keys].val.str_val = sinv; + db_vals[nr_keys].val.str_val = bInviteDlg ? sinv : ssub; nr_keys++; } @@ -1407,7 +1424,7 @@ int tps_storage_update_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, if(msg==NULL || md==NULL || sd==NULL) return -1; - if(md->s_method_id != METHOD_INVITE) { + if((md->s_method_id != METHOD_INVITE) && (md->s_method_id != METHOD_SUBSCRIBE)) { return 0; } @@ -1514,6 +1531,14 @@ int tps_db_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, } } } + if ((mode & TPS_DBU_TIME) && ((sd->b_tag.len > 0) + && ((md->direction == TPS_DIR_UPSTREAM) && (msg->first_line.type==SIP_REQUEST)) + && (msg->first_line.u.request.method_value == METHOD_SUBSCRIBE))) { + db_ucols[nr_ucols] = &td_col_rectime; + db_uvals[nr_ucols].type = DB1_DATETIME; + db_uvals[nr_ucols].val.time_val = time(NULL); + nr_ucols++; + } if(nr_ucols==0) { return 0; @@ -1543,7 +1568,7 @@ int tps_storage_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, if(msg==NULL || md==NULL || sd==NULL) return -1; - if(md->s_method_id != METHOD_INVITE) { + if((md->s_method_id != METHOD_INVITE) && (md->s_method_id != METHOD_SUBSCRIBE)) { return 0; } if(msg->first_line.type==SIP_REPLY) { @@ -1575,7 +1600,7 @@ int tps_db_end_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd) if(msg==NULL || md==NULL || sd==NULL || _tps_db_handle==NULL) return -1; - if(md->s_method_id != METHOD_BYE) { + if((md->s_method_id != METHOD_BYE) && !((md->s_method_id == METHOD_SUBSCRIBE) && (md->expires == 0))) { return 0; } diff --git a/src/modules/topos/tps_storage.h b/src/modules/topos/tps_storage.h index aeda1962ec1..6183ba6b476 100644 --- a/src/modules/topos/tps_storage.h +++ b/src/modules/topos/tps_storage.h @@ -41,6 +41,7 @@ #define TPS_DBU_RPLATTRS (1<<1) #define TPS_DBU_ARR (1<<2) #define TPS_DBU_BRR (1<<3) +#define TPS_DBU_TIME (1<<4) #define TPS_DBU_ALL (0xffffffff) #define TPS_DATA_SIZE 8192 @@ -79,6 +80,7 @@ typedef struct tps_data { int32_t iflags; int32_t direction; uint32_t s_method_id; + int32_t expires; } tps_data_t; int tps_storage_dialog_find(sip_msg_t *msg, tps_data_t *td); diff --git a/src/modules/topos_redis/README b/src/modules/topos_redis/README index c1b038dffc8..619902729f9 100644 --- a/src/modules/topos_redis/README +++ b/src/modules/topos_redis/README @@ -10,9 +10,15 @@ Daniel-Constantin Mierla +Frederic Gaisnon + + + Copyright © 2017 kamailio.org Copyright © 2017 flowroute.com + + Copyright © 2021 MomentTech __________________________________________________________________ Table of Contents diff --git a/src/modules/topos_redis/doc/topos_redis.xml b/src/modules/topos_redis/doc/topos_redis.xml index f6a5314d825..4634eb7ebdc 100644 --- a/src/modules/topos_redis/doc/topos_redis.xml +++ b/src/modules/topos_redis/doc/topos_redis.xml @@ -23,6 +23,11 @@ Mierla miconda@gmail.com + + Frederic + Gaisnon + frederic.gaisnon@gmail.com + 2017 @@ -32,6 +37,10 @@ 2017 flowroute.com + + 2021 + MomentTech + diff --git a/src/modules/topos_redis/topos_redis_storage.c b/src/modules/topos_redis/topos_redis_storage.c index 47205c8f133..93f02da0fd3 100644 --- a/src/modules/topos_redis/topos_redis_storage.c +++ b/src/modules/topos_redis/topos_redis_storage.c @@ -265,7 +265,12 @@ int tps_redis_insert_dialog(tps_data_t *td) argvlen[argc] = rkey.len; argc++; - lval = (unsigned long)_tps_api.get_dialog_expire(); + if(td->s_method.len==9 && strncmp(td->s_method.s, "SUBSCRIBE", 9)==0) { + lval = (unsigned long)td->expires; + } else { + lval = (unsigned long)_tps_api.get_dialog_expire(); + } + if(lval==0) { return 0; } @@ -297,7 +302,7 @@ int tps_redis_clean_dialogs(void) /** * */ -int tps_redis_insert_invite_branch(tps_data_t *td) +int tps_redis_insert_initial_method_branch(tps_data_t *td) { char* argv[TPS_REDIS_NR_KEYS]; size_t argvlen[TPS_REDIS_NR_KEYS]; @@ -328,8 +333,9 @@ int tps_redis_insert_invite_branch(tps_data_t *td) rp = _tps_redis_cbuf; rkey.len = snprintf(rp, TPS_REDIS_DATA_SIZE-128, - "%.*sINVITE:%.*s:%.*s", + "%.*s%.*s:%.*s:%.*s", _tps_redis_bprefix.len, _tps_redis_bprefix.s, + td->s_method.len, td->s_method.s, td->a_callid.len, td->a_callid.s, td->b_tag.len, td->b_tag.s); if(rkey.len<0 || rkey.len>=TPS_REDIS_DATA_SIZE-128) { @@ -360,8 +366,8 @@ int tps_redis_insert_invite_branch(tps_data_t *td) } return -1; } - LM_DBG("inserting invite branch record for [%.*s] with argc %d\n", - rkey.len, rkey.s, argc); + LM_DBG("inserting %.*s branch record for [%.*s] with argc %d\n", + td->s_method.len, td->s_method.s,rkey.len, rkey.s, argc); freeReplyObject(rrpl); @@ -552,7 +558,7 @@ int tps_redis_clean_branches(void) /** * */ -int tps_redis_load_invite_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd) +int tps_redis_load_initial_method_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd) { char* argv[TPS_REDIS_NR_KEYS]; size_t argvlen[TPS_REDIS_NR_KEYS]; @@ -588,8 +594,9 @@ int tps_redis_load_invite_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd) rp = _tps_redis_cbuf; rkey.len = snprintf(rp, TPS_REDIS_DATA_SIZE, - "%.*sINVITE:%.*s:%.*s", + "%.*s%.*s:%.*s:%.*s", _tps_redis_bprefix.len, _tps_redis_bprefix.s, + md->s_method.len, md->s_method.s, md->a_callid.len, md->a_callid.s, md->b_tag.len, md->b_tag.s); if(rkey.len<0 || rkey.len>=TPS_REDIS_DATA_SIZE) { @@ -733,9 +740,9 @@ int tps_redis_load_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, /* load same transaction using Via branch */ xvbranch1 = &md->x_vbranch1; } else { - /* load corresponding INVITE transaction using call-id + to-tag */ - if(tps_redis_load_invite_branch(msg, md, &id)<0) { - LM_ERR("failed to load the INVITE branch value\n"); + /* load corresponding INVITE or SUBSCRIBE transaction using call-id + to-tag */ + if(tps_redis_load_initial_method_branch(msg, md, &id)<0) { + LM_ERR("failed to load the %.*s branch value\n", md->s_method.len, md->s_method.s); return -1; } xvbranch1 = &id.x_vbranch1; @@ -1122,11 +1129,18 @@ int tps_redis_update_branch(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, } if(md->s_method.len==6 && strncmp(md->s_method.s, "INVITE", 6)==0) { - if(tps_redis_insert_invite_branch(md)<0) { + if(tps_redis_insert_initial_method_branch(md)<0) { LM_ERR("failed to insert INVITE extra branch data\n"); return -1; } } + if(md->s_method.len==9 && strncmp(md->s_method.s, "SUBSCRIBE", 9)==0) { + if(tps_redis_insert_initial_method_branch(md)<0) { + LM_ERR("failed to insert SUBSCRIBE extra branch data\n"); + return -1; + } + } + rsrv = _tps_redis_api.get_server(&_topos_redis_serverid); if(rsrv==NULL) { LM_ERR("cannot find redis server [%.*s]\n", @@ -1209,6 +1223,7 @@ int tps_redis_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, redisc_server_t *rsrv = NULL; redisReply *rrpl = NULL; int32_t liflags; + unsigned long lval = 0; if(sd->a_uuid.len<=0 && sd->b_uuid.len<=0) { LM_INFO("no uuid for this message\n"); @@ -1297,6 +1312,11 @@ int tps_redis_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, } } + if (mode & TPS_DBU_TIME) { + lval = (unsigned long)time(NULL); + TPS_REDIS_SET_ARGN(lval, rp, &rval, argc, &td_key_rectime, argv, argvlen); + } + if(argc<=2) { return 0; } @@ -1313,6 +1333,37 @@ int tps_redis_update_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd, rkey.len, rkey.s, argc); freeReplyObject(rrpl); + if (mode & TPS_DBU_TIME) { + /* reset expire for the key */ + argc = 0; + + argv[argc] = "EXPIRE"; + argvlen[argc] = 6; + argc++; + + argv[argc] = rkey.s; + argvlen[argc] = rkey.len; + argc++; + + lval = (unsigned long)md->expires; + if(lval==0) { + return 0; + } + TPS_REDIS_SET_ARGNV(lval, rp, &rval, argc, argv, argvlen); + + rrpl = _tps_redis_api.exec_argv(rsrv, argc, (const char **)argv, argvlen); + if(rrpl==NULL) { + LM_ERR("failed to execute expire redis command\n"); + if(rsrv->ctxRedis->err) { + LM_ERR("redis error: %s\n", rsrv->ctxRedis->errstr); + } + return -1; + } + LM_DBG("expire %lu set on dialog record for [%.*s] with argc %d\n", lval, + rkey.len, rkey.s, argc); + freeReplyObject(rrpl); + } + return 0; } @@ -1333,7 +1384,7 @@ int tps_redis_end_dialog(sip_msg_t *msg, tps_data_t *md, tps_data_t *sd) int32_t liflags; unsigned long lval = 0; - if(md->s_method_id != METHOD_BYE) { + if((md->s_method_id != METHOD_BYE) && !((md->s_method_id == METHOD_SUBSCRIBE) && (md->expires == 0))) { return 0; } diff --git a/src/modules/uac_redirect/README b/src/modules/uac_redirect/README index 6ca8d1d451c..88e9e22859f 100644 --- a/src/modules/uac_redirect/README +++ b/src/modules/uac_redirect/README @@ -31,6 +31,7 @@ Bogdan-Andrei Iancu 4.5. acc_db_table (string) 4.6. bflags (int) 4.7. flags_hdr_mode (int) + 4.8. q_value (int) 5. Functions @@ -50,11 +51,12 @@ Bogdan-Andrei Iancu 1.5. Set acc_db_table parameter 1.6. Set bflags module parameter 1.7. Set flags_hdr_mode parameter - 1.8. set_deny_filter usage - 1.9. set_accept_filter usage - 1.10. get_redirects usage + 1.8. Set q_value parameter + 1.9. set_deny_filter usage + 1.10. set_accept_filter usage 1.11. get_redirects usage - 1.12. Redirection script example + 1.12. get_redirects usage + 1.13. Redirection script example Chapter 1. Admin Guide @@ -76,6 +78,7 @@ Chapter 1. Admin Guide 4.5. acc_db_table (string) 4.6. bflags (int) 4.7. flags_hdr_mode (int) + 4.8. q_value (int) 5. Functions @@ -149,6 +152,7 @@ Chapter 1. Admin Guide 4.5. acc_db_table (string) 4.6. bflags (int) 4.7. flags_hdr_mode (int) + 4.8. q_value (int) 4.1. default_filter (string) @@ -273,6 +277,20 @@ branch_route[1] { modparam("uac_redirect","flags_hdr_mode",2) ... +4.8. q_value (int) + + Specifies the q-value to asign to contacts without one. Because + Kamailio doesn't support float parameter types, the value in the + parameter is divided by 1000 and stored as float. For example, if you + want q value to be 0.38, use value 380 here. + + The default value is 10 (0.01). + + Example 1.8. Set q_value parameter +... +modparam("uac_redirect","q_value",0) +... + 5. Functions 5.1. set_deny_filter(filter,flags) @@ -295,7 +313,7 @@ modparam("uac_redirect","flags_hdr_mode",2) This function can be used from FAILURE_ROUTE. - Example 1.8. set_deny_filter usage + Example 1.9. set_deny_filter usage ... set_deny_filter(".*@domain2.net","reset_all"); set_deny_filter(".*@domain1.net",""); @@ -316,7 +334,7 @@ set_deny_filter(".*@domain1.net",""); This function can be used from FAILURE_ROUTE. - Example 1.9. set_accept_filter usage + Example 1.10. set_accept_filter usage ... set_accept_filter(".*@domain2.net","reset_added"); set_accept_filter(".*@domain1.net",""); @@ -345,7 +363,7 @@ set_accept_filter(".*@domain1.net",""); This function can be used from FAILURE_ROUTE. - Example 1.10. get_redirects usage + Example 1.11. get_redirects usage ... # max 2 contacts per branch, but no overall limit get_redirects("*:2"); @@ -369,14 +387,14 @@ get_redirects("*"); This function can be used from FAILURE_ROUTE. - Example 1.11. get_redirects usage + Example 1.12. get_redirects usage ... get_redirects("4:1","Redirected"); ... 6. Script Example - Example 1.12. Redirection script example + Example 1.13. Redirection script example loadmodule "modules/sl/sl.so" loadmodule "modules/usrloc/usrloc.so" loadmodule "modules/registrar/registrar.so" diff --git a/src/modules/uac_redirect/doc/uac_redirect_admin.xml b/src/modules/uac_redirect/doc/uac_redirect_admin.xml index b044d38c250..eb66416d059 100644 --- a/src/modules/uac_redirect/doc/uac_redirect_admin.xml +++ b/src/modules/uac_redirect/doc/uac_redirect_admin.xml @@ -337,6 +337,28 @@ branch_route[1] { ... modparam("uac_redirect","flags_hdr_mode",2) +... + + + +
+ <varname>q_value</varname> (int) + + Specifies the q-value to asign to contacts without one. Because + Kamailio doesn't support float parameter types, the value in the + parameter is divided by 1000 and stored as float. For example, if + you want q value to be 0.38, use value 380 here. + + + + The default value is 10 (0.01). + + + + Set <varname>q_value</varname> parameter + +... +modparam("uac_redirect","q_value",0) ... diff --git a/src/modules/uac_redirect/rd_funcs.c b/src/modules/uac_redirect/rd_funcs.c index 5b105d1011c..7d8e7fd1d49 100644 --- a/src/modules/uac_redirect/rd_funcs.c +++ b/src/modules/uac_redirect/rd_funcs.c @@ -33,9 +33,9 @@ extern sruid_t _redirect_sruid; +extern int _redirect_q_value; #define MAX_CONTACTS_PER_REPLY 16 -#define DEFAULT_Q_VALUE 10 static int shmcontact2dset(struct sip_msg *req, struct sip_msg *shrpl, long max, struct acc_param *reason, unsigned int bflags); @@ -147,7 +147,7 @@ static int sort_contacts(hdr_field_t *chdr, contact_t **ct_array, /* does the contact has a q val? */ q_para = ct_list->q; if (q_para==0 || q_para->body.len==0) { - q = DEFAULT_Q_VALUE; + q = _redirect_q_value; } else { if (str2q( &q, q_para->body.s, q_para->body.len)!=0) { LM_ERR("invalid q param\n"); diff --git a/src/modules/uac_redirect/uac_redirect.c b/src/modules/uac_redirect/uac_redirect.c index 57ec038b391..2c4802beabb 100644 --- a/src/modules/uac_redirect/uac_redirect.c +++ b/src/modules/uac_redirect/uac_redirect.c @@ -52,6 +52,9 @@ int flags_hdr_mode = 0; #define ACCEPT_RULE_STR "accept" #define DENY_RULE_STR "deny" +#define DEFAULT_Q_VALUE 10 + +int _redirect_q_value = DEFAULT_Q_VALUE; /* sruid to get internal uid */ sruid_t _redirect_sruid; @@ -88,6 +91,7 @@ static param_export_t params[] = { {"acc_db_table", PARAM_STRING, &acc_db_table }, {"bflags", INT_PARAM, &bflags }, {"flags_hdr_mode", INT_PARAM, &flags_hdr_mode }, + {"q_value", INT_PARAM, &_redirect_q_value }, {0, 0, 0} }; diff --git a/src/modules/usrloc/ul_rpc.c b/src/modules/usrloc/ul_rpc.c index 63c45381b5f..d45a8e2783c 100644 --- a/src/modules/usrloc/ul_rpc.c +++ b/src/modules/usrloc/ul_rpc.c @@ -402,7 +402,7 @@ static void ul_rpc_lookup(rpc_t* rpc, void* ctx) /* look for table */ dom = rpc_find_domain( &table ); if (dom == NULL) { - rpc->fault(ctx, 500, "Domain not found"); + rpc->fault(ctx, 500, "Domain table not found"); return; } @@ -476,7 +476,7 @@ static void ul_rpc_rm_aor(rpc_t* rpc, void* ctx) /* look for table */ dom = rpc_find_domain( &table ); if (dom == NULL) { - rpc->fault(ctx, 500, "Domain not found"); + rpc->fault(ctx, 500, "Domain table not found"); return; } @@ -520,7 +520,7 @@ static void ul_rpc_rm_contact(rpc_t* rpc, void* ctx) /* look for table */ dom = rpc_find_domain( &table ); if (dom == NULL) { - rpc->fault(ctx, 500, "Domain not found"); + rpc->fault(ctx, 500, "Domain table not found"); return; } @@ -661,7 +661,7 @@ static void ul_rpc_add(rpc_t* rpc, void* ctx) /* look for table */ dom = rpc_find_domain( &table ); if (dom == NULL) { - rpc->fault(ctx, 500, "Domain not found"); + rpc->fault(ctx, 500, "Domain table not found"); return; }