From a309fe46990df18cc37873d9e88d112bdbc2939f Mon Sep 17 00:00:00 2001 From: Stefan Mititelu Date: Tue, 9 Jun 2015 17:02:55 +0300 Subject: [PATCH 1/4] rtpengine: changes for mi_fifo_commands Added a new fifo command, namely nh_ping_rtpp, which pings the given proxy or all proxies, and if a proxy does not respond, disable it temporarily. If the proxy responds, it does nothing. Changed the existing fifos to execute for a specific proxy or for all proxies depending on the first given parameter. Changed nh_enable_rtpp to try to ping before enabling and enable it only if ping success. Changed some formatting for nh_show_rtpp to print 'N/A' when disabled permanent and to display the correct recheck_ticks. Updated doku accordingly. --- modules/rtpengine/doc/rtpengine_admin.xml | 79 ++- modules/rtpengine/rtpengine.c | 588 ++++++++++++++++++---- 2 files changed, 549 insertions(+), 118 deletions(-) diff --git a/modules/rtpengine/doc/rtpengine_admin.xml b/modules/rtpengine/doc/rtpengine_admin.xml index ecc5c1e2d80..46d8903a301 100644 --- a/modules/rtpengine/doc/rtpengine_admin.xml +++ b/modules/rtpengine/doc/rtpengine_admin.xml @@ -837,21 +837,30 @@ start_recording();
<acronym>MI</acronym> Commands
- <function moreinfo="none">nh_enable_rtpp</function> + <function moreinfo="none">nh_enable_rtpp proxy_url/all 0/1</function> - Enables a &rtp; proxy if parameter value is greater than 0. - Disables it if a zero value is given. + Enables a &rtp; proxy if the second parameter value is greater than 0. Disables it if a zero value is given. + The first parameter is either a specific &rtp; proxy url (exactly as defined in + the config file) or the keyword all. + The second parameter value must be a number in decimal. - The first parameter is the &rtp; proxy url (exactly as defined in - the config file). + When try to enable the &rtp; proxy, an application ping command is sent to it. + If it fails, the proxy is not enabled. + Displays success or fail when try to enable/disable. - The second parameter value must be a number in decimal. + NOTE: If a &rtp; proxy is defined multiple times (in the same or diferent sets), all of its instances will be enabled/disabled. + + + NOTE: If a &rtp; proxy is in the disabled permanent state and one tries to enable it, even if the ping fails, + it is moved to a disabled temporary state and a recheck_ticks are given to it. + While the recheck_ticks are grater than 0, the proxy is considered disabled temporary, and it is not taken into consideration for sending data. + When the recheck_ticks are 0, the proxy is retested when trying to send data(not automatically retested), and data can be send to it on success. - NOTE: if a &rtp; proxy is defined multiple times (in the same or - diferente sete), all of its instances will be enables/disabled. + NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with :: + to escape the :: from the IPv6 address. See the example below. @@ -859,28 +868,68 @@ start_recording(); <programlisting format="linespecific"> ... $ &ctltool; fifo nh_enable_rtpp udp:192.168.2.133:8081 0 +$ &ctltool; fifo nh_enable_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999 1 +$ &ctltool; fifo nh_enable_rtpp all 1 ... </programlisting> </example> </section> - <section id="rtpengine.m.nh_show_rtpp"> - <title><function moreinfo="none">nh_show_rtpp</function> +
+ <function moreinfo="none">nh_show_rtpp proxy_url/all</function> Displays all the &rtp; proxies and their information: set and - status (disabled or not, weight and recheck_ticks). If a RTP proxy has been disabled by a mi command - a "(permanent)" quote will appear when printing the disabled status. This is to differentiate from - a temporary disable due to the proxy being not found responsive by kamailio. + status (disabled or not, weight and recheck_ticks). If a &rtp; proxy has been disabled by + nh_enable_rtpp mi command a "(permanent)" quote will appear when printing the disabled status. + This is to differentiate from a temporary disable due to the proxy being not found responsive + by kamailio. In addition, when disabled permanent, recheck_ticks have no meaning and "N\A" + is printed instead of the value. + + + It takes either a specific &rtp; proxy url (exactly as defined in + the config file) or the keyword all as a parameter. - No parameter. + NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with :: + to escape the :: from the IPv6 address. See the example below. <function moreinfo="none">nh_show_rtpp</function> usage ... -$ &ctltool; fifo nh_show_rtpp +$ &ctltool; fifo nh_show_rtpp udp:192.168.2.133:8081 +$ &ctltool; fifo nh_show_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999 +$ &ctltool; fifo nh_show_rtpp all +... + + +
+ +
+ <function moreinfo="none">nh_ping_rtpp proxy_url/all</function> + + Sends an application ping command to the &rtp; proxy. If the proxy does not respond, + it will be disabled, but not permanent. If the proxy responds, no action is taken. + Displays the ping result, i.e. + success or fail when try to ping. + + + It takes either a specific &rtp; proxy url (exactly as defined in + the config file) or the keyword all as a parameter. + + + NOTE: When specify the IPv6 &rtp; proxy url one must prefix it with :: + to escape the :: from the IPv6 address. See the example below. + + + + <function moreinfo="none">nh_ping_rtpp</function> usage + +... +$ &ctltool; fifo nh_ping_rtpp udp:192.168.2.133:8081 +$ &ctltool; fifo nh_ping_rtpp ::udp6:fe80::9a90:96ff:fea8:fd99:9999 +$ &ctltool; fifo nh_ping_rtpp all ... diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index c48757f5cfd..6f03d30662f 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -102,11 +102,12 @@ MODULE_VERSION #define MI_SET_NATPING_STATE "nh_enable_ping" #define MI_DEFAULT_NATPING_STATE 1 -#define MI_ENABLE_RTP_PROXY "nh_enable_rtpp" #define MI_MIN_RECHECK_TICKS 0 #define MI_MAX_RECHECK_TICKS (unsigned int)-1 +#define MI_ENABLE_RTP_PROXY "nh_enable_rtpp" #define MI_SHOW_RTP_PROXIES "nh_show_rtpp" +#define MI_PING_RTP_PROXY "nh_ping_rtpp" #define MI_RTP_PROXY_NOT_FOUND "RTP proxy not found" #define MI_RTP_PROXY_NOT_FOUND_LEN (sizeof(MI_RTP_PROXY_NOT_FOUND)-1) @@ -118,6 +119,8 @@ MODULE_VERSION #define MI_SET_LEN (sizeof(MI_SET)-1) #define MI_INDEX "index" #define MI_INDEX_LEN (sizeof(MI_INDEX)-1) +#define MI_ENABLED "enabled" +#define MI_ENABLED_LEN (sizeof(MI_ENABLED)-1) #define MI_DISABLED "disabled" #define MI_DISABLED_LEN (sizeof(MI_DISABLED)-1) #define MI_WEIGHT "weight" @@ -125,6 +128,24 @@ MODULE_VERSION #define MI_RECHECK_TICKS "recheck_ticks" #define MI_RECHECK_T_LEN (sizeof(MI_RECHECK_TICKS)-1) +#define MI_ERROR "Error when adding rtpp node details" +#define MI_ERROR_LEN (sizeof(MI_ERROR)-1) +#define MI_ALL "all" +#define MI_ALL_LEN (sizeof(MI_ALL)-1) +#define MI_ENABLE "enable" +#define MI_ENABLE_LEN (sizeof(MI_ENABLE)-1) +#define MI_DISABLE "disable" +#define MI_DISABLE_LEN (sizeof(MI_DISABLE)-1) +#define MI_PING "ping" +#define MI_PING_LEN (sizeof(MI_PING)-1) +#define MI_SUCCESS "success" +#define MI_SUCCESS_LEN (sizeof(MI_SUCCESS)-1) +#define MI_FAIL "fail" +#define MI_FAIL_LEN (sizeof(MI_FAIL)-1) + +#define MI_FOUND_ALL 2 +#define MI_FOUND_ONE 1 +#define MI_FOUND_NONE 0 #define CPORT "22222" @@ -135,6 +156,7 @@ enum rtpe_operation { OP_DELETE, OP_START_RECORDING, OP_QUERY, + OP_PING, }; struct ng_flags_parse { @@ -148,6 +170,7 @@ static const char *command_strings[] = { [OP_DELETE] = "delete", [OP_START_RECORDING] = "start recording", [OP_QUERY] = "query", + [OP_PING] = "ping", }; static char *gencookie(); @@ -179,14 +202,22 @@ static int get_ip_type(char *str_addr); static int get_ip_scope(char *str_addr); // useful for link-local ipv6 static int bind_force_send_ip(int sock_idx); +static int add_rtpp_node_info(struct mi_node *node, + struct rtpp_node *crt_rtpp, + struct rtpp_set *rtpp_list); + +static int rtpp_test_ping(struct rtpp_node *node); + /* Pseudo-Variables */ static int pv_get_rtpstat_f(struct sip_msg *, pv_param_t *, pv_value_t *); /*mi commands*/ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, void* param ); -static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, +static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, void* param); +static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, + void* param); static int rtpengine_disable_tout = 60; @@ -303,8 +334,9 @@ static param_export_t params[] = { }; static mi_export_t mi_cmds[] = { - {MI_ENABLE_RTP_PROXY, mi_enable_rtp_proxy, 0, 0, 0}, - {MI_SHOW_RTP_PROXIES, mi_show_rtpproxies, MI_NO_INPUT_FLAG, 0, 0}, + {MI_ENABLE_RTP_PROXY, mi_enable_rtp_proxy, 0, 0, 0}, + {MI_SHOW_RTP_PROXIES, mi_show_rtp_proxy, 0, 0, 0}, + {MI_PING_RTP_PROXY, mi_ping_rtp_proxy, 0, 0, 0}, { 0, 0, 0, 0, 0} }; @@ -423,7 +455,7 @@ static int bind_force_send_ip(int sock_idx) memset(&tmp, 0, sizeof(tmp)); getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp, &sock_len); inet_ntop(AF_INET, &tmp.sin_addr, str_addr, INET_ADDRSTRLEN); - LM_INFO("Binding on %s:%d\n", str_addr, ntohs(tmp.sin_port)); + LM_DBG("Binding on %s:%d\n", str_addr, ntohs(tmp.sin_port)); break; @@ -447,7 +479,7 @@ static int bind_force_send_ip(int sock_idx) memset(&tmp6, 0, sizeof(tmp6)); getsockname(rtpp_socks[sock_idx], (struct sockaddr *) &tmp6, &sock_len); inet_ntop(AF_INET6, &tmp6.sin6_addr, str_addr6, INET6_ADDRSTRLEN); - LM_INFO("Binding on ipv6 %s:%d\n", str_addr6, ntohs(tmp6.sin6_port)); + LM_DBG("Binding on ipv6 %s:%d\n", str_addr6, ntohs(tmp6.sin6_port)); break; @@ -779,67 +811,204 @@ static int fixup_set_id(void ** param, int param_no) return 0; } -static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, - void* param ) -{ struct mi_node* node; - str rtpp_url; +static int rtpp_test_ping(struct rtpp_node *node) +{ + bencode_buffer_t bencbuf; + bencode_item_t *dict; + char *cp; + int ret; + + if (bencode_buffer_init(&bencbuf)) { + return -1; + } + dict = bencode_dictionary(&bencbuf); + bencode_dictionary_add_string(dict, "command", command_strings[OP_PING]); + + if (bencbuf.error) { + goto error; + } + + cp = send_rtpp_command(node, dict, &ret); + if (!cp) { + goto error; + } + + dict = bencode_decode_expect(&bencbuf, cp, ret, BENCODE_DICTIONARY); + if (!dict || bencode_dictionary_get_strcmp(dict, "result", "pong")) { + goto error; + } + + bencode_buffer_free(&bencbuf); + return 0; + +error: + bencode_buffer_free(&bencbuf); + return -1; +} + +static struct mi_root* mi_enable_rtp_proxy(struct mi_root *cmd_tree, + void *param ) +{ + struct mi_node *node, *crt_node; + struct rtpp_set *rtpp_list; + struct rtpp_node *crt_rtpp, *found_rtpp; + struct mi_root *root; + struct mi_attr *attr; unsigned int enable; - struct rtpp_set * rtpp_list; - struct rtpp_node * crt_rtpp; - int found; + int found, found_rtpp_disabled; + str rtpp_url; + str snode, sattr, svalue; - found = 0; + found = MI_FOUND_NONE; + found_rtpp_disabled = 0; + found_rtpp = NULL; + enable = 0; - if(rtpp_set_list ==NULL) - goto end; + if (rtpp_set_list == NULL) { + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } node = cmd_tree->node.kids; - if(node == NULL) - return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + if (node == NULL) { + return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } - if(node->value.s == NULL || node->value.len ==0) - return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + if (node->value.s == NULL || node->value.len ==0) { + return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + /* get proxy */ rtpp_url = node->value; node = node->next; - if(node == NULL) - return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + if (node == NULL) { + return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } - enable = 0; - if( strno2int( &node->value, &enable) <0) + if (node->value.s == NULL || node->value.len ==0) { + return init_mi_tree(400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + + /* get value (enable/disable) */ + if(strno2int(&node->value, &enable) < 0) { goto error; + } + + node = node->next; + if (node != NULL) { + return init_mi_tree(400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } + + /* found a matching all - show all rtpp */ + if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) { + found = MI_FOUND_ALL; + } for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL; - rtpp_list = rtpp_list->rset_next){ + rtpp_list = rtpp_list->rset_next) { for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; - crt_rtpp = crt_rtpp->rn_next){ - /*found a matching rtpp*/ + crt_rtpp = crt_rtpp->rn_next) { + + /* found a matching rtpp - show it */ + if (found == MI_FOUND_ALL || + (crt_rtpp->rn_url.len == rtpp_url.len && + strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) { + /* do ping when try to enable the rtpp */ + if (enable) { + + /* if ping success, enable the rtpp and reset ticks */ + if (rtpp_test_ping(crt_rtpp) == 0) { + crt_rtpp->rn_disabled = 0; + crt_rtpp->rn_recheck_ticks = MI_MIN_RECHECK_TICKS; + + /* if ping fail, disable the rtpps but _not_ permanently*/ + } else { + crt_rtpp->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; + crt_rtpp->rn_disabled = 1; + found_rtpp_disabled = 1; + } + + /* do not ping when disable the rtpp; disable it permanenty */ + } else { + crt_rtpp->rn_disabled = 1; + crt_rtpp->rn_recheck_ticks = MI_MAX_RECHECK_TICKS; + } + + if (found == MI_FOUND_NONE) { + found = MI_FOUND_ONE; + found_rtpp = crt_rtpp; + } + } + } + } - if(crt_rtpp->rn_url.len == rtpp_url.len){ + root = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + if (!root) { + LM_ERR("the MI tree cannot be initialized!\n"); + return 0; + } + node = &root->node; - if(strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0){ - /*set the enabled/disabled status*/ - found = 1; - crt_rtpp->rn_recheck_ticks = - enable? MI_MIN_RECHECK_TICKS : MI_MAX_RECHECK_TICKS; - crt_rtpp->rn_disabled = enable?0:1; - } - } - } + switch (found) { + case MI_FOUND_ALL: + snode.s = MI_ALL; + snode.len = MI_ALL_LEN; + break; + case MI_FOUND_ONE: + snode.s = found_rtpp->rn_url.s; + snode.len = found_rtpp->rn_url.len; + break; + default: + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } + + svalue.s = MI_SUCCESS; + svalue.len = MI_SUCCESS_LEN; + + if (enable) { + sattr.s = MI_ENABLE; + sattr.len = MI_ENABLE_LEN; + + if (found_rtpp_disabled) { + svalue.s = MI_FAIL; + svalue.len = MI_FAIL_LEN; + } + } else { + sattr.s = MI_DISABLE; + sattr.len = MI_DISABLE_LEN; + } + + if (!(crt_node = add_mi_node_child(node, 0, + snode.s, snode.len, + 0, 0)) ) { + LM_ERR("cannot add the child node to the tree\n"); + goto error; } -end: - if(found) - return init_mi_tree( 200, MI_OK_S, MI_OK_LEN); - return init_mi_tree(404,MI_RTP_PROXY_NOT_FOUND,MI_RTP_PROXY_NOT_FOUND_LEN); + if ((attr = add_mi_attr(crt_node, MI_DUP_VALUE, + sattr.s, sattr.len, + svalue.s, svalue.len)) == 0) { + LM_ERR("cannot add attributes to the node\n"); + goto error; + } + + + return root; + error: - return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN); } + #define add_rtpp_node_int_info(_parent, _name, _name_len, _value, _child,\ _len, _string, _error)\ do {\ @@ -853,86 +1022,294 @@ static struct mi_root* mi_enable_rtp_proxy(struct mi_root* cmd_tree, goto _error;\ }while(0); -static struct mi_root* mi_show_rtpproxies(struct mi_root* cmd_tree, - void* param) + +static int add_rtpp_node_info (struct mi_node *node, + struct rtpp_node *crt_rtpp, + struct rtpp_set *rtpp_list) { - struct mi_node* node, *crt_node, *child; - struct mi_root* root; - struct mi_attr * attr; - struct rtpp_set * rtpp_list; - struct rtpp_node * crt_rtpp; - char * string, *id; int id_len, len; + int rtpp_ticks; + struct mi_node *crt_node, *child; + struct mi_attr *attr; + char *string, *id; string = id = 0; + id = int2str(rtpp_list->id_set, &id_len); + if(!id) { + LM_ERR("cannot convert set id\n"); + goto error; + } + + if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s, + crt_rtpp->rn_url.len, 0,0)) ) { + LM_ERR("cannot add the child node to the tree\n"); + goto error; + } + + LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s ); + + if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN, + id, id_len))== 0) { + LM_ERR("cannot add attributes to the node\n"); + goto error; + } + + add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN, + crt_rtpp->idx, child, len, string, error); + + if ((1 == crt_rtpp->rn_disabled ) && (crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS)) { + if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE, MI_DISABLED, MI_DISABLED_LEN, + MI_DISABLED_PERMANENT, MI_DISABLED_PERMANENT_LEN))) { + LM_ERR("cannot add disabled (permanent) message\n"); + goto error; + } + } + else { + add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN, + crt_rtpp->rn_disabled, child, len, string, error); + } + + add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN, + crt_rtpp->rn_weight, child, len, string, error); + + if (crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS) { + if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE, + MI_RECHECK_TICKS, MI_RECHECK_T_LEN, + "N/A", sizeof("N/A") - 1))) { + LM_ERR("cannot add MAX recheck_ticks value\n"); + goto error; + } + } else { + rtpp_ticks = crt_rtpp->rn_recheck_ticks - get_ticks(); + rtpp_ticks = rtpp_ticks < 0 ? 0 : rtpp_ticks; + add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS, MI_RECHECK_T_LEN, + rtpp_ticks, child, len, string, error); + } + + return 0; + +error: + return -1; +} + +static struct mi_root* mi_show_rtp_proxy(struct mi_root* cmd_tree, + void* param) +{ + struct mi_node *node; + struct mi_root *root; + struct rtpp_set *rtpp_list; + struct rtpp_node *crt_rtpp; + int found; + str rtpp_url; + + found = MI_FOUND_NONE; + + if (rtpp_set_list == NULL) { + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } + + node = cmd_tree->node.kids; + if (node == NULL) { + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } + + if (node->value.s == NULL || node->value.len ==0) { + return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + + rtpp_url = node->value; + if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) != 0 && rtpp_set_list == NULL) { + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } + + node = node->next; + if (node != NULL) { + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } + root = init_mi_tree(200, MI_OK_S, MI_OK_LEN); if (!root) { LM_ERR("the MI tree cannot be initialized!\n"); return 0; } - if(rtpp_set_list ==NULL) - return root; - node = &root->node; + /* found a matching all - show all rtpp */ + if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) { + found = MI_FOUND_ALL; + } + for(rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL; - rtpp_list = rtpp_list->rset_next){ + rtpp_list = rtpp_list->rset_next) { for(crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; - crt_rtpp = crt_rtpp->rn_next){ + crt_rtpp = crt_rtpp->rn_next) { - id = int2str(rtpp_list->id_set, &id_len); - if(!id){ - LM_ERR("cannot convert set id\n"); - goto error; - } + /* found a matching rtpp - show it */ + if (found == MI_FOUND_ALL || + (crt_rtpp->rn_url.len == rtpp_url.len && + strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) { - if(!(crt_node = add_mi_node_child(node, 0, crt_rtpp->rn_url.s, - crt_rtpp->rn_url.len, 0,0)) ) { - LM_ERR("cannot add the child node to the tree\n"); - goto error; - } + if (add_rtpp_node_info(node, crt_rtpp, rtpp_list) < 0) { + goto error; + } - LM_DBG("adding node name %s \n",crt_rtpp->rn_url.s ); + if (found == MI_FOUND_NONE) { + found = MI_FOUND_ONE; + } + } + } + } - if((attr = add_mi_attr(crt_node, MI_DUP_VALUE, MI_SET, MI_SET_LEN, - id, id_len))== 0){ - LM_ERR("cannot add attributes to the node\n"); - goto error; - } + switch (found) { + case MI_FOUND_ALL: + case MI_FOUND_ONE: + break; + default: + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } - add_rtpp_node_int_info(crt_node, MI_INDEX, MI_INDEX_LEN, - crt_rtpp->idx, child, len,string,error); - - if (( 1 == crt_rtpp->rn_disabled ) && ( crt_rtpp->rn_recheck_ticks == MI_MAX_RECHECK_TICKS)) { - if( !(child = add_mi_node_child(crt_node, MI_DUP_VALUE, MI_DISABLED, MI_DISABLED_LEN, - MI_DISABLED_PERMANENT, MI_DISABLED_PERMANENT_LEN))) { - LM_ERR("cannot add disabled (permanent) message\n"); - goto error; - } - } - else { - add_rtpp_node_int_info(crt_node, MI_DISABLED, MI_DISABLED_LEN, - crt_rtpp->rn_disabled, child, len,string,error); - } + return root; - add_rtpp_node_int_info(crt_node, MI_WEIGHT, MI_WEIGHT_LEN, - crt_rtpp->rn_weight, child, len, string,error); - add_rtpp_node_int_info(crt_node, MI_RECHECK_TICKS,MI_RECHECK_T_LEN, - crt_rtpp->rn_recheck_ticks, child, len, string, error); - } +error: + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN); +} + +static struct mi_root* mi_ping_rtp_proxy(struct mi_root* cmd_tree, + void* param) +{ + struct mi_node *node, *crt_node; + struct mi_attr *attr; + struct mi_root *root; + struct rtpp_set *rtpp_list; + struct rtpp_node *crt_rtpp, *found_rtpp; + int found, found_rtpp_disabled; + str rtpp_url; + str snode, sattr, svalue; + + found = 0; + found_rtpp_disabled = 0; + found_rtpp = NULL; + + if (rtpp_set_list == NULL) { + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } + + node = cmd_tree->node.kids; + if (node == NULL) { + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } + + if (node->value.s == NULL || node->value.len ==0) { + return init_mi_tree( 400, MI_BAD_PARM_S, MI_BAD_PARM_LEN); + } + + rtpp_url = node->value; + + node = node->next; + if (node != NULL) { + return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); + } + + /* found a matching all - ping all rtpp */ + if (strncmp(MI_ALL, rtpp_url.s, MI_ALL_LEN) == 0) { + found = MI_FOUND_ALL; + } + + for (rtpp_list = rtpp_set_list->rset_first; rtpp_list != NULL; + rtpp_list = rtpp_list->rset_next) { + + for (crt_rtpp = rtpp_list->rn_first; crt_rtpp != NULL; + crt_rtpp = crt_rtpp->rn_next) { + + /* found a matching rtpp - ping it */ + if (found == MI_FOUND_ALL || + (crt_rtpp->rn_url.len == rtpp_url.len && + strncmp(crt_rtpp->rn_url.s, rtpp_url.s, rtpp_url.len) == 0)) { + + /* if ping fail */ + if (rtpp_test_ping(crt_rtpp) < 0) { + crt_rtpp->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; + found_rtpp_disabled = 1; + crt_rtpp->rn_disabled = 1; + } + + if (found == MI_FOUND_NONE) { + found = MI_FOUND_ONE; + found_rtpp = crt_rtpp; + } + } + } + } + + root = init_mi_tree(200, MI_OK_S, MI_OK_LEN); + if (!root) { + LM_ERR("the MI tree cannot be initialized!\n"); + return 0; + } + + node = &root->node; + + switch (found) { + case MI_FOUND_ALL: + snode.s = MI_ALL; + snode.len = MI_ALL_LEN; + break; + case MI_FOUND_ONE: + snode.s = found_rtpp->rn_url.s; + snode.len = found_rtpp->rn_url.len; + break; + default: + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_RTP_PROXY_NOT_FOUND, MI_RTP_PROXY_NOT_FOUND_LEN); + } + + sattr.s = MI_PING; + sattr.len = MI_PING_LEN; + + if (found_rtpp_disabled) { + svalue.s = MI_FAIL; + svalue.len = MI_FAIL_LEN; + } else { + svalue.s = MI_SUCCESS; + svalue.len = MI_SUCCESS_LEN; + } + + if (!(crt_node = add_mi_node_child(node, 0, + snode.s, snode.len, + 0, 0)) ) { + LM_ERR("cannot add the child node to the tree\n"); + goto error; + } + + if ((attr = add_mi_attr(crt_node, MI_DUP_VALUE, + sattr.s, sattr.len, + svalue.s, svalue.len)) == 0) { + LM_ERR("cannot add attributes to the node\n"); + goto error; } return root; + error: - if (root) - free_mi_tree(root); - return 0; + if (root) { + free_mi_tree(root); + } + return init_mi_tree(404, MI_ERROR, MI_ERROR_LEN); } + static int mod_init(void) { @@ -1516,6 +1893,10 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ goto error; } cp = send_rtpp_command(node, ng_flags.dict, &ret); + if (cp == NULL) { + node->rn_disabled = 1; + node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; + } } while (cp == NULL); LM_DBG("proxy reply: %.*s\n", ret, cp); @@ -1606,6 +1987,8 @@ rtpp_test(struct rtpp_node *node, int isdisabled, int force) cp = send_rtpp_command(node, dict, &ret); if (!cp) { + node->rn_disabled = 1; + node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; LM_ERR("proxy did not respond to ping\n"); goto error; } @@ -1638,6 +2021,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) static char buf[0x10000]; struct pollfd fds[1]; struct iovec *v; + str out = STR_NULL; v = bencode_iovec(dict, &vcnt, 1, 0); if (!v) { @@ -1663,7 +2047,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) } if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { close(fd); - LM_ERR("can't connect to RTP proxy\n"); + LM_ERR("can't connect to RTP proxy <%s>\n", node->rn_url.s); goto badproxy; } @@ -1672,7 +2056,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) } while (len == -1 && errno == EINTR); if (len <= 0) { close(fd); - LM_ERR("can't send command to a RTP proxy\n"); + LM_ERR("can't send command to RTP proxy <%s>\n", node->rn_url.s); goto badproxy; } do { @@ -1680,7 +2064,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) } while (len == -1 && errno == EINTR); close(fd); if (len <= 0) { - LM_ERR("can't read reply from a RTP proxy\n"); + LM_ERR("can't read reply from RTP proxy <%s>\n", node->rn_url.s); goto badproxy; } } else { @@ -1700,7 +2084,8 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) len = writev(rtpp_socks[node->idx], v, vcnt + 1); } while (len == -1 && (errno == EINTR || errno == ENOBUFS)); if (len <= 0) { - LM_ERR("can't send command to a RTP proxy\n"); + bencode_get_str(bencode_dictionary_get(dict, "command"), &out); + LM_ERR("can't send command \"%.*s\" to RTP proxy <%s>\n", out.len, out.s, node->rn_url.s); goto badproxy; } while ((poll(fds, 1, rtpengine_tout_ms) == 1) && @@ -1709,7 +2094,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) len = recv(rtpp_socks[node->idx], buf, sizeof(buf)-1, 0); } while (len == -1 && errno == EINTR); if (len <= 0) { - LM_ERR("can't read reply from a RTP proxy\n"); + LM_ERR("can't read reply from RTP proxy <%s>\n", node->rn_url.s); goto badproxy; } if (len >= (v[0].iov_len - 1) && @@ -1726,7 +2111,7 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) } } if (i == rtpengine_retr) { - LM_ERR("timeout waiting reply from a RTP proxy\n"); + LM_ERR("timeout waiting reply from RTP proxy <%s>\n", node->rn_url.s); goto badproxy; } } @@ -1735,11 +2120,8 @@ send_rtpp_command(struct rtpp_node *node, bencode_item_t *dict, int *outlen) cp[len] = '\0'; *outlen = len; return cp; -badproxy: - LM_ERR("proxy <%s> does not respond, disable it\n", node->rn_url.s); - node->rn_disabled = 1; - node->rn_recheck_ticks = get_ticks() + rtpengine_disable_tout; +badproxy: return NULL; } From bbcac5b04262194b427ce6f7bfafed3cfd5095b1 Mon Sep 17 00:00:00 2001 From: Juha Heinanen Date: Tue, 16 Jun 2015 11:37:45 +0300 Subject: [PATCH 2/4] modules/lcr: added priority_ordering module parameter - allows ordering of matched gateways only by priority and weight --- modules/lcr/README | 219 ++++++++++++++++++---------------- modules/lcr/doc/lcr_admin.xml | 48 +++++++- modules/lcr/lcr_mod.c | 23 +++- 3 files changed, 183 insertions(+), 107 deletions(-) diff --git a/modules/lcr/README b/modules/lcr/README index 58268cfd42d..e7d92eb98c8 100644 --- a/modules/lcr/README +++ b/modules/lcr/README @@ -10,7 +10,7 @@ Juha Heinanen - Copyright (c) 2005-2014 Juha Heinanen + Copyright © 2005-2014 Juha Heinanen __________________________________________________________________ Table of Contents @@ -62,12 +62,13 @@ Juha Heinanen 3.35. lcr_rule_hash_size (integer) 3.36. lcr_gw_count (integer) 3.37. dont_strip_or_tag_flag (integer) - 3.38. fetch_rows (integer) - 3.39. ping_interval (integer) - 3.40. ping_inactivate_threshold (integer) - 3.41. ping_valid_reply_codes (string) - 3.42. ping_from (string) - 3.43. ping_socket (string) + 3.38. priority_ordering (integer) + 3.39. fetch_rows (integer) + 3.40. ping_interval (integer) + 3.41. ping_inactivate_threshold (integer) + 3.42. ping_valid_reply_codes (string) + 3.43. ping_from (string) + 3.44. ping_socket (string) 4. Functions @@ -128,25 +129,26 @@ Juha Heinanen 1.35. Setting lcr_rule_hash_size module parameter 1.36. Setting lcr_gw_count module parameter 1.37. Setting dont_strip_or_tag_flag module parameter - 1.38. Set fetch_rows parameter - 1.39. Set ping_interval parameter - 1.40. Set ping_inactive_threshold parameter - 1.41. Set ping_valid_reply_codes parameter - 1.42. Set ping_from parameter - 1.43. Set ping_socket parameter - 1.44. load_gws usage - 1.45. next_gw usage from a route block - 1.46. next_gw usage from a failure route block - 1.47. inactivate_gw usage - 1.48. defunct_gw usage - 1.49. from_gw usage + 1.38. Setting priority_ordering module parameter + 1.39. Set fetch_rows parameter + 1.40. Set ping_interval parameter + 1.41. Set ping_inactivate_threshold parameter + 1.42. Set ping_valid_reply_codes parameter + 1.43. Set ping_from parameter + 1.44. Set ping_socket parameter + 1.45. load_gws usage + 1.46. next_gw usage from a route block + 1.47. next_gw usage from a failure route block + 1.48. inactivate_gw usage + 1.49. defunct_gw usage 1.50. from_gw usage - 1.51. to_gw usage + 1.51. from_gw usage 1.52. to_gw usage - 1.53. lcr.reload RPC example - 1.54. lcr.dump_gws RPC example - 1.55. lcr.dump_rules RPC example - 1.56. lcr.defunct_gw RPC example + 1.53. to_gw usage + 1.54. lcr.reload RPC example + 1.55. lcr.dump_gws RPC example + 1.56. lcr.dump_rules RPC example + 1.57. lcr.defunct_gw RPC example Chapter 1. Admin Guide @@ -197,12 +199,13 @@ Chapter 1. Admin Guide 3.35. lcr_rule_hash_size (integer) 3.36. lcr_gw_count (integer) 3.37. dont_strip_or_tag_flag (integer) - 3.38. fetch_rows (integer) - 3.39. ping_interval (integer) - 3.40. ping_inactivate_threshold (integer) - 3.41. ping_valid_reply_codes (string) - 3.42. ping_from (string) - 3.43. ping_socket (string) + 3.38. priority_ordering (integer) + 3.39. fetch_rows (integer) + 3.40. ping_interval (integer) + 3.41. ping_inactivate_threshold (integer) + 3.42. ping_valid_reply_codes (string) + 3.43. ping_from (string) + 3.44. ping_socket (string) 4. Functions @@ -248,9 +251,14 @@ Chapter 1. Admin Guide currently designated as defunct) are ordered for forwarding purposes as follows: - * (1) according to longest Request-URI user part match - * (2) according to tuple's priority - * (3) according to tuple's randomized weight + 1. according to longest Request-URI user part match + 2. according to tuple's priority + 3. according to tuple's randomized weight + + or, if priority_ordering parameter is set to value 1, as follows: + + 1. according to tuple's priority + 2. according to tuple's randomized weight A tuple can be marked as a "stopper" tuple. If a "stopper" tuple matches, then matching stops at it and all other tuples with shorter @@ -349,18 +357,19 @@ Chapter 1. Admin Guide 3.35. lcr_rule_hash_size (integer) 3.36. lcr_gw_count (integer) 3.37. dont_strip_or_tag_flag (integer) - 3.38. fetch_rows (integer) - 3.39. ping_interval (integer) - 3.40. ping_inactivate_threshold (integer) - 3.41. ping_valid_reply_codes (string) - 3.42. ping_from (string) - 3.43. ping_socket (string) + 3.38. priority_ordering (integer) + 3.39. fetch_rows (integer) + 3.40. ping_interval (integer) + 3.41. ping_inactivate_threshold (integer) + 3.42. ping_valid_reply_codes (string) + 3.43. ping_from (string) + 3.44. ping_socket (string) 3.1. db_url (string) URL of the database table to be used. - Default value is "mysql://kamailioro:kamailioro@localhost/kamailio". + Default value is “mysql://kamailioro:kamailioro@localhost/kamailio”. Example 1.1. Setting db_url module parameter ... @@ -371,7 +380,7 @@ modparam("lcr","db_url","dbdriver://username:password@dbhost/dbname") Name of the table holding gateways definitions. - Default value is "lcr_gw". + Default value is “lcr_gw”. Example 1.2. Setting gw_table module parameter ... @@ -383,7 +392,7 @@ modparam("lcr", "lcr_gw_table","gw") Name of the auto-increment, primary key column. Common to all lcr module tables. - Default value is "id". + Default value is “id”. Example 1.3. Setting id_column module parameter ... @@ -397,7 +406,7 @@ modparam("lcr", "id_column", "row_id") the column is integer from 1 to lcr_count. In lcr_gw table, value of the column is from 0 to lcr_count. - Default value is "lcr_id". + Default value is “lcr_id”. Example 1.4. Setting lcr_id_column module parameter ... @@ -408,7 +417,7 @@ modparam("lcr", "lcr_id_column", "lcr_identifier") Name of the column holding gateway's name for documentation purpose. - Default value is "gw_name". + Default value is “gw_name”. Example 1.5. Setting gw_name_column module parameter ... @@ -419,7 +428,7 @@ modparam("lcr", "gw_name_column", "name") Name of the column holding the IPv4 or IPv6 address of the gateway. - Default value is "ip_addr". + Default value is “ip_addr”. Example 1.6. Setting ip_addr_column module parameter ... @@ -431,7 +440,7 @@ modparam("lcr", "ip_addr_column", "ip") Name of the column holding gateway's hostname that is used in Request-URI hostpart, when request is sent to the gateway. - Default value is "hostname". + Default value is “hostname”. Example 1.7. Setting hostname_column module parameter ... @@ -442,7 +451,7 @@ modparam("lcr", "hostname_column", "host") Name of the column holding the port number of the gateway. - Default value is "port". + Default value is “port”. Example 1.8. Setting port_column module parameter ... @@ -454,7 +463,7 @@ modparam("lcr", "port_column", "port") Name of the column holding gateway's parameters that is used in Request-URI, when request is sent to the gateway. - Default value is "params". + Default value is “params”. Example 1.9. Setting params_column module parameter ... @@ -465,7 +474,7 @@ modparam("lcr", "params_column", "parameters") Name of the column holding the uri scheme of the gateway. - Default value is "uri_scheme". + Default value is “uri_scheme”. Example 1.10. Setting uri_scheme_column module parameter ... @@ -477,7 +486,7 @@ modparam("lcr", "uri_scheme_column", "uri_scheme") Name of the column holding the transport protocol to be used for the gateway. - Default value is "transport". + Default value is “transport”. Example 1.11. Setting transport_column module parameter ... @@ -489,7 +498,7 @@ modparam("lcr", "transport_column", "trans") Name of the column holding the number of characters to be stripped from the front of Request-URI user part before inserting tag. - Default value is "strip". + Default value is “strip”. Example 1.12. Setting strip_column module parameter ... @@ -501,7 +510,7 @@ modparam("lcr", "strip_column", "strip_count") Name of the column holding gateway specific tag string that is added to Request URI userpart after stripping. - Default value is "tag". + Default value is “tag”. Example 1.13. Setting tag_column module parameter ... @@ -512,7 +521,7 @@ modparam("lcr", "tag_column", "gw_tag") Name of the column holding gateway specific flag values. - Default value is "flags". + Default value is “flags”. Example 1.14. Setting flags_column module parameter ... @@ -526,7 +535,7 @@ modparam("lcr", "flags_column", "gw_flags") max UNIX timestamp value) or greater, gw is considered currently unused and is not loaded into memory at all. - Default value is "defunct". + Default value is “defunct”. Example 1.15. Setting defunct_column module parameter ... @@ -537,7 +546,7 @@ modparam("lcr", "defunct_column", "defunct_until") Name of the table holding the LCR rules. - Default value is "lcr_rule". + Default value is “lcr_rule”. Example 1.16. Setting lcr_rule_table module parameter ... @@ -549,7 +558,7 @@ modparam("lcr", "lcr_rule_table", "rules") Name of the column holding prefix of Request-URI user part and prefix of gateway. - Default value is "prefix". + Default value is “prefix”. Example 1.17. Setting prefix_column module parameter ... @@ -560,7 +569,7 @@ modparam("lcr", "prefix_column", "number_prefix") Name of the column holding the From (caller's) URI. - Default value is "from_uri". + Default value is “from_uri”. Example 1.18. Setting from_uri_column module parameter ... @@ -572,7 +581,7 @@ modparam("lcr", "from_uri_column", "caller_uri") Name of the column holding the regular expression to match against the complete request URI (including the "sip:" prefix). - Default value is "request_uri". + Default value is “request_uri”. Example 1.19. Setting request_uri_column module parameter ... @@ -583,7 +592,7 @@ modparam("lcr", "request_uri_column", "callee_uri") Name of the column holding rule's stopper attribute. - Default value is "stopper". + Default value is “stopper”. Example 1.20. Setting stopper_column module parameter ... @@ -595,7 +604,7 @@ modparam("lcr", "stopper_column", "stop") Name of the column telling is the rule is currently enabled or disabled. - Default value is "enabled". + Default value is “enabled”. Example 1.21. Setting enabled_column module parameter ... @@ -607,7 +616,7 @@ modparam("lcr", "enabled_column", "in_use") Name of the table holding information about the LCR rule targets (gateways). - Default value is "lcr_rule_target". + Default value is “lcr_rule_target”. Example 1.22. Setting lcr_rule_target_table module parameter ... @@ -619,7 +628,7 @@ modparam("lcr", "lcr_rule_target_table", "rules") Name of lcr_rule_target_table column containing an id of lcr_rule table. - Default value is "rule_id". + Default value is “rule_id”. Example 1.23. Setting rule_id_column module parameter ... @@ -630,7 +639,7 @@ modparam("lcr", "rule_id_column", "rule") Name of lcr_rule_target_table column containing an id of lcr_gw table. - Default value is "gw_id". + Default value is “gw_id”. Example 1.24. Setting gw_id_column module parameter ... @@ -641,7 +650,7 @@ modparam("lcr", "gw_id_column", "gw") Name of the column holding the priority of the rule target. - Default value is "priority". + Default value is “priority”. Example 1.25. Setting priority_column module parameter ... @@ -652,7 +661,7 @@ modparam("lcr", "priority_column", "priority") Name of the column holding weight of rule target. - Default value is "weight". + Default value is “weight”. Example 1.26. Setting weight_column module parameter ... @@ -796,7 +805,18 @@ modparam("lcr", "lcr_gw_count", 1024) modparam("lcr", "dont_strip_or_tag_flag", 10) ... -3.38. fetch_rows (integer) +3.38. priority_ordering (integer) + + Defines how matching gateways are ordered (see Overview section). + + Default value is 0. + + Example 1.38. Setting priority_ordering module parameter +... +modparam("lcr", "priority_ordering", 1) +... + +3.39. fetch_rows (integer) The number of the rows to be fetched at once from database when loading data from lcr_rule table. This value can be used to tune the load time @@ -804,14 +824,14 @@ modparam("lcr", "dont_strip_or_tag_flag", 10) 3750. In order for this parameter to have effect, the database driver must support fetch_result() capability. - Default value is "1024". + Default value is “1024”. - Example 1.38. Set fetch_rows parameter + Example 1.39. Set fetch_rows parameter ... modparam("lcr", "fetch_rows", 3000) ... -3.39. ping_interval (integer) +3.40. ping_interval (integer) Interval in seconds for sending OPTIONS ping requests to gateways that, due to failures, have been marked as inactive by inactivate_gw() @@ -821,62 +841,61 @@ modparam("lcr", "fetch_rows", 3000) If value of this parameter is greater than zero, tm module must have been loaded and parameters lcr_id_avp and defunct_gw_avp must have been - defined. Value "0" disables sending of OPTIONS ping requests to failed + defined. Value “0” disables sending of OPTIONS ping requests to failed gateways. - Default value is "0". + Default value is “0”. - Example 1.39. Set ping_interval parameter + Example 1.40. Set ping_interval parameter ... modparam("lcr", "ping_interval", 15) ... -3.40. ping_inactivate_threshold (integer) +3.41. ping_inactivate_threshold (integer) Tells after how many failures (= inactivate_gw() function calls) a gateway is marked as inactive. - Default value is "1", i.e., gateway is marked inactive after first - failure. + Default value is “1”, i.e., gateway is inactivated after first failure. - Example 1.40. Set ping_inactive_threshold parameter + Example 1.41. Set ping_inactivate_threshold parameter ... -modparam("lcr", "ping_inactive_threshold", 3) +modparam("lcr", "ping_inactivate_threshold", 3) ... -3.41. ping_valid_reply_codes (string) +3.42. ping_valid_reply_codes (string) A comma separated list of SIP reply codes, which are accepted as valid replies to OPTIONS ping requests. Reply codes 2xx are by default accepted as valid replies and they don't need to be listed here. - Default value is "", i.e., only 2xx replies are considered as valid + Default value is “”, i.e., only 2xx replies are considered as valid replies. - Example 1.41. Set ping_valid_reply_codes parameter + Example 1.42. Set ping_valid_reply_codes parameter ... modparam("lcr", "ping_valid_reply_codes", "403,405,501") ... -3.42. ping_from (string) +3.43. ping_from (string) From URI used in OPTIONS ping requests. - Default value is "sip:pinger@localhost". + Default value is “sip:pinger@localhost”. - Example 1.42. Set ping_from parameter + Example 1.43. Set ping_from parameter ... modparam("lcr", "ping_from", "sip:proxy.operator.com") ... -3.43. ping_socket (string) +3.44. ping_socket (string) Socket to be used for sending OPTIONS ping request. If not set or set - to "", default socket is used. + to “”, default socket is used. - Default value is "". + Default value is “”. - Example 1.43. Set ping_socket parameter + Example 1.44. Set ping_socket parameter ... modparam("lcr", "ping_socket", "192.98.102.10:5060") ... @@ -912,7 +931,7 @@ modparam("lcr", "ping_socket", "192.98.102.10:5060") This function can be used from REQUEST_ROUTE. - Example 1.44. load_gws usage + Example 1.45. load_gws usage ... if (!load_gws(1, $rU, $var(caller_uri))) { sl_send_reply("500", "Server Internal Error - Cannot load gateways"); @@ -942,7 +961,7 @@ if (!load_gws(1, $rU, $var(caller_uri))) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.45. next_gw usage from a route block + Example 1.46. next_gw usage from a route block ... if (!next_gw()) { sl_send_reply("503", "Service not available - No gateways"); @@ -950,7 +969,7 @@ if (!next_gw()) { }; ... - Example 1.46. next_gw usage from a failure route block + Example 1.47. next_gw usage from a failure route block ... if (!next_gw()) { t_reply("503", "Service not available - No more gateways"); @@ -970,7 +989,7 @@ if (!next_gw()) { This function can be used from REQUEST_ROUTE and FAILURE_ROUTE. - Example 1.47. inactivate_gw usage + Example 1.48. inactivate_gw usage ... failure_route [GW_FAILURE] { ... @@ -991,7 +1010,7 @@ failure_route [GW_FAILURE] { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.48. defunct_gw usage + Example 1.49. defunct_gw usage ... defunct_gw(60); ... @@ -1023,7 +1042,7 @@ defunct_gw(60); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE. - Example 1.49. from_gw usage + Example 1.50. from_gw usage ... if (from_gw(1, $avp(s:real_source_addr), 2) { ... @@ -1053,7 +1072,7 @@ if (from_gw(1, $avp(s:real_source_addr), 2) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, ONREPLY_ROUTE. - Example 1.50. from_gw usage + Example 1.51. from_gw usage ... $var(lcr_id) = from_any_gw("192.168.1.1", 3); ... @@ -1074,7 +1093,7 @@ $var(lcr_id) = from_any_gw("192.168.1.1", 3); This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.51. to_gw usage + Example 1.52. to_gw usage ... if (to_gw("1")) { ... @@ -1100,7 +1119,7 @@ if (to_gw("1")) { This function can be used from REQUEST_ROUTE, FAILURE_ROUTE. - Example 1.52. to_gw usage + Example 1.53. to_gw usage ... if (to_any_gw("192.55.66.2", 1)) { ... @@ -1123,7 +1142,7 @@ if (to_any_gw("192.55.66.2", 1)) { Parameters: none - Example 1.53. lcr.reload RPC example + Example 1.54. lcr.reload RPC example $ kamcmd lcr.reload 5.2. lcr.dump_gws @@ -1132,7 +1151,7 @@ if (to_any_gw("192.55.66.2", 1)) { Parameters: none - Example 1.54. lcr.dump_gws RPC example + Example 1.55. lcr.dump_gws RPC example $ kamcmd lcr.dump_gws 5.3. lcr.dump_rules @@ -1142,7 +1161,7 @@ if (to_any_gw("192.55.66.2", 1)) { Parameters: none - Example 1.55. lcr.dump_rules RPC example + Example 1.56. lcr.dump_rules RPC example $ kamcmd lcr.dump_rules 5.4. lcr.defunct_gw @@ -1155,7 +1174,7 @@ if (to_any_gw("192.55.66.2", 1)) { Parameters: lcr_id gw_id period - Example 1.56. lcr.defunct_gw RPC example + Example 1.57. lcr.defunct_gw RPC example $ kamcmd lcr.defunct_gw 1 4 120 6. Known Limitations diff --git a/modules/lcr/doc/lcr_admin.xml b/modules/lcr/doc/lcr_admin.xml index fcd8d55bef1..3a47466425f 100644 --- a/modules/lcr/doc/lcr_admin.xml +++ b/modules/lcr/doc/lcr_admin.xml @@ -44,20 +44,35 @@ are ordered for forwarding purposes as follows: - + - (1) according to longest Request-URI user part match + according to longest Request-URI user part match - (2) according to tuple's priority + according to tuple's priority - (3) according to tuple's randomized weight + according to tuple's randomized weight - + + + + or, if priority_ordering parameter is set to value 1, as follows: + + + + + according to tuple's priority + + + + according to tuple's randomized weight + + + A tuple can be marked as a "stopper" tuple. If a "stopper" @@ -970,6 +985,29 @@ modparam("lcr", "dont_strip_or_tag_flag", 10)
+
+ <varname>priority_ordering</varname> (integer) + + Defines how matching gateways are ordered (see Overview section). + + + + Default value is 0. + + + + + Setting <varname>priority_ordering</varname> module + parameter + + +... +modparam("lcr", "priority_ordering", 1) +... + + +
+
<varname>fetch_rows</varname> (integer) diff --git a/modules/lcr/lcr_mod.c b/modules/lcr/lcr_mod.c index ae01b2410a0..81247d22818 100644 --- a/modules/lcr/lcr_mod.c +++ b/modules/lcr/lcr_mod.c @@ -218,6 +218,9 @@ str ping_valid_reply_codes_param = {"", 0}; str ping_socket_param = {"", 0}; str ping_from_param = {"sip:pinger@localhost", 20}; +/* use priority as main ordering criteria */ +static unsigned int priority_ordering_param = 0; + /* * Other module types and variables */ @@ -345,6 +348,7 @@ static param_export_t params[] = { {"lcr_rule_hash_size", INT_PARAM, &lcr_rule_hash_size_param}, {"lcr_gw_count", INT_PARAM, &lcr_gw_count_param}, {"dont_strip_or_prefix_flag",INT_PARAM, &dont_strip_or_prefix_flag_param}, + {"priority_ordering", INT_PARAM, &priority_ordering_param}, {"fetch_rows", INT_PARAM, &fetch_rows_param}, {"ping_interval", INT_PARAM, &ping_interval_param}, {"ping_inactivate_threshold", INT_PARAM, &ping_inactivate_threshold_param}, @@ -465,6 +469,12 @@ static int mod_init(void) return -1; } + if ((priority_ordering_param != 0) && (priority_ordering_param != 1)) { + LM_ERR("invalid priority_ordering value <%d>\n", + priority_ordering_param); + return -1; + } + /* Process AVP params */ if (gw_uri_avp_param && *gw_uri_avp_param) { @@ -780,6 +790,17 @@ static int comp_matched(const void *m1, const void *m2) struct matched_gw_info *mi1 = (struct matched_gw_info *) m1; struct matched_gw_info *mi2 = (struct matched_gw_info *) m2; + if (priority_ordering_param) { + /* Sort by priority */ + if (mi1->priority < mi2->priority) return 1; + if (mi1->priority == mi2->priority) { + /* Sort by randomized weigth */ + if (mi1->weight > mi2->weight) return 1; + if (mi1->weight == mi2->weight) return 0; + } + return -1; + } + /* Sort by prefix_len */ if (mi1->prefix_len > mi2->prefix_len) return 1; if (mi1->prefix_len == mi2->prefix_len) { @@ -789,9 +810,7 @@ static int comp_matched(const void *m1, const void *m2) /* Sort by randomized weigth */ if (mi1->weight > mi2->weight) return 1; if (mi1->weight == mi2->weight) return 0; - return -1; } - return -1; } return -1; } From 9c3ea838b31039ac067e17d519df67b64b0dada1 Mon Sep 17 00:00:00 2001 From: Daniel-Constantin Mierla Date: Tue, 16 Jun 2015 15:06:43 +0200 Subject: [PATCH 3/4] dialog: re-entrant mutex for dialogs hash table slots - changed from a lock set usage to per slot lock field --- modules/dialog/dlg_hash.c | 39 +++++++-------------------------------- modules/dialog/dlg_hash.h | 31 +++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/modules/dialog/dlg_hash.c b/modules/dialog/dlg_hash.c index 536fe323d13..e3d0005fd15 100644 --- a/modules/dialog/dlg_hash.c +++ b/modules/dialog/dlg_hash.c @@ -42,9 +42,6 @@ #include "dlg_req_within.h" #include "dlg_db_handler.h" -#define MAX_LDG_LOCKS 2048 -#define MIN_LDG_LOCKS 2 - extern int dlg_ka_interval; /*! global dialog table */ @@ -223,7 +220,7 @@ int dlg_clean_run(ticks_t ti) tm = (unsigned int)time(NULL); for(i=0; isize; i++) { - lock_set_get(d_table->locks, d_table->entries[i].lock_idx); + dlg_lock(d_table, &d_table->entries[i]); dlg = d_table->entries[i].first; while (dlg) { tdlg = dlg; @@ -243,7 +240,7 @@ int dlg_clean_run(ticks_t ti) tdlg->dflags |= DLG_FLAG_CHANGED; } } - lock_set_release(d_table->locks, d_table->entries[i].lock_idx); + dlg_unlock(d_table, &d_table->entries[i]); } return 0; } @@ -288,30 +285,13 @@ int init_dlg_table(unsigned int size) d_table->size = size; d_table->entries = (struct dlg_entry*)(d_table+1); - n = (size=MIN_LDG_LOCKS ; n-- ) { - d_table->locks = lock_set_alloc(n); - if (d_table->locks==0) - continue; - if (lock_set_init(d_table->locks)==0) { - lock_set_dealloc(d_table->locks); - d_table->locks = 0; - continue; - } - d_table->locks_no = n; - break; - } - - if (d_table->locks==0) { - LM_ERR("unable to allocted at least %d locks for the hash table\n", - MIN_LDG_LOCKS); - goto error1; - } - for( i=0 ; ientries[i]), 0, sizeof(struct dlg_entry) ); + if(lock_init(&d_table->entries[i].lock)<0) { + LM_ERR("failed to init lock for slot: %d\n", i); + goto error1; + } d_table->entries[i].next_id = rand() % (3*size); - d_table->entries[i].lock_idx = i % d_table->locks_no; } return 0; @@ -411,11 +391,6 @@ void destroy_dlg_table(void) if (d_table==0) return; - if (d_table->locks) { - lock_set_destroy(d_table->locks); - lock_set_dealloc(d_table->locks); - } - for( i=0 ; isize; i++ ) { dlg = d_table->entries[i].first; while (dlg) { @@ -423,7 +398,7 @@ void destroy_dlg_table(void) dlg = dlg->next; destroy_dlg(l_dlg); } - + lock_destroy(&d_table->entries[i].lock); } shm_free(d_table); diff --git a/modules/dialog/dlg_hash.h b/modules/dialog/dlg_hash.h index d79d994bc41..b09fe381e6c 100644 --- a/modules/dialog/dlg_hash.h +++ b/modules/dialog/dlg_hash.h @@ -33,6 +33,7 @@ #include "../../locking.h" #include "../../lib/kmi/mi.h" #include "../../timer.h" +#include "../../atomic_ops.h" #include "dlg_timer.h" #include "dlg_cb.h" @@ -134,7 +135,9 @@ typedef struct dlg_entry struct dlg_cell *first; /*!< dialog list */ struct dlg_cell *last; /*!< optimisation, end of the dialog list */ unsigned int next_id; /*!< next id */ - unsigned int lock_idx; /*!< lock index */ + gen_lock_t lock; /* mutex to access items in the slot */ + atomic_t locker_pid; /* pid of the process that holds the lock */ + int rec_lock_level; /* recursive lock count */ } dlg_entry_t; @@ -143,8 +146,6 @@ typedef struct dlg_table { unsigned int size; /*!< size of the dialog table */ struct dlg_entry *entries; /*!< dialog hash table */ - unsigned int locks_no; /*!< number of locks */ - gen_lock_set_t *locks; /*!< lock table */ } dlg_table_t; @@ -160,12 +161,22 @@ extern dlg_table_t *d_table; /*! - * \brief Set a dialog lock + * \brief Set a dialog lock (re-entrant) * \param _table dialog table * \param _entry locked entry */ #define dlg_lock(_table, _entry) \ - lock_set_get( (_table)->locks, (_entry)->lock_idx); + do { \ + int mypid; \ + mypid = my_pid(); \ + if (likely(atomic_get( &(_entry)->locker_pid) != mypid)) { \ + lock_get( &(_entry)->lock); \ + atomic_set( &(_entry)->locker_pid, mypid); \ + } else { \ + /* locked within the same process that executed us */ \ + (_entry)->rec_lock_level++; \ + } \ + } while(0) /*! @@ -174,7 +185,15 @@ extern dlg_table_t *d_table; * \param _entry locked entry */ #define dlg_unlock(_table, _entry) \ - lock_set_release( (_table)->locks, (_entry)->lock_idx); + do { \ + if (likely((_entry)->rec_lock_level == 0)) { \ + atomic_set( &(_entry)->locker_pid, 0); \ + lock_release( &(_entry)->lock); \ + } else { \ + /* recursive locked => decrease lock count */ \ + (_entry)->rec_lock_level--; \ + } \ + } while(0) /*! * \brief Unlink a dialog from the list without locking From ceffd956e3b7a8070ffb6cf6c1a05b0f86f34ac8 Mon Sep 17 00:00:00 2001 From: Lucian Balaceanu Date: Tue, 16 Jun 2015 16:23:33 +0300 Subject: [PATCH 4/4] rtpengine: interpret session limit message - upon receiving a "Parallel session limit reached"message from rtpengine Kamailio's rtpengine module should try the next media relay available (or none if none is available) without marking the media relay as unavailable; --- modules/rtpengine/rtpengine.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/modules/rtpengine/rtpengine.c b/modules/rtpengine/rtpengine.c index 6f03d30662f..0c4e807f55b 100644 --- a/modules/rtpengine/rtpengine.c +++ b/modules/rtpengine/rtpengine.c @@ -255,6 +255,8 @@ static int_str setid_avp; static str write_sdp_pvar_str = {NULL, 0}; static pv_spec_t* write_sdp_pvar = NULL; +#define RTPENGINE_SESS_LIMIT_MSG "Parallel session limit reached" +#define RTPENGINE_SESS_LIMIT_MSG_LEN (sizeof(RTPENGINE_SESS_LIMIT_MSG)-1) char* force_send_ip_str=""; int force_send_ip_af = AF_UNSPEC; @@ -1882,6 +1884,7 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ active_rtpp_set = default_rtpp_set; queried_nodes = 0; +select_node: do { if (++queried_nodes > queried_nodes_limit) { LM_ERR("queried nodes limit reached\n"); @@ -1909,11 +1912,19 @@ static bencode_item_t *rtpp_function_call(bencode_buffer_t *bencbuf, struct sip_ goto error; } if (!bencode_dictionary_get_strcmp(resp, "result", "error")) { - if (!bencode_dictionary_get_str(resp, "error-reason", &error)) - LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp); - else + if (!bencode_dictionary_get_str(resp, "error-reason", &error)) { + LM_ERR("proxy return error but didn't give an error reason: %.*s\n", ret, cp); + } + else { + if ((RTPENGINE_SESS_LIMIT_MSG_LEN == error.len) && + (strncmp(error.s, RTPENGINE_SESS_LIMIT_MSG, RTPENGINE_SESS_LIMIT_MSG_LEN) == 0)) + { + LM_WARN("proxy %.*s: %.*s", node->rn_url.len, node->rn_url.s , error.len, error.s); + goto select_node; + } LM_ERR("proxy replied with error: %.*s\n", error.len, error.s); - goto error; + } + goto error; } if (body_out)