From 86dc3de29ae8bd579537e5b07d70254a74fc63f2 Mon Sep 17 00:00:00 2001 From: Dmitry Sinina Date: Sun, 28 Apr 2019 22:26:03 +0300 Subject: [PATCH 1/2] Fix Invalid capacity limitation when customer auth record contains multiple IPs. closes #472 --- ...190428191918_fix_customer_auth_capacity.rb | 2173 +++++++++++++++++ db/structure.sql | 12 +- 2 files changed, 2179 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20190428191918_fix_customer_auth_capacity.rb diff --git a/db/migrate/20190428191918_fix_customer_auth_capacity.rb b/db/migrate/20190428191918_fix_customer_auth_capacity.rb new file mode 100644 index 000000000..2b03afad0 --- /dev/null +++ b/db/migrate/20190428191918_fix_customer_auth_capacity.rb @@ -0,0 +1,2173 @@ +class FixCustomerAuthCapacity < ActiveRecord::Migration[5.2] + def up + execute %q{ +CREATE or replace FUNCTION switch17.route(i_node_id integer, i_pop_id integer, i_protocol_id smallint, i_remote_ip inet, i_remote_port integer, i_local_ip inet, i_local_port integer, i_from_dsp character varying, i_from_name character varying, i_from_domain character varying, i_from_port integer, i_to_name character varying, i_to_domain character varying, i_to_port integer, i_contact_name character varying, i_contact_domain character varying, i_contact_port integer, i_uri_name character varying, i_uri_domain character varying, i_auth_id integer, i_x_yeti_auth character varying, i_diversion character varying, i_x_orig_ip inet, i_x_orig_port integer, i_x_orig_protocol_id smallint, i_pai character varying, i_ppi character varying, i_privacy character varying, i_rpid character varying, i_rpid_privacy character varying) RETURNS SETOF switch17.callprofile61_ty + LANGUAGE plpgsql SECURITY DEFINER ROWS 10 + AS $$ + DECLARE + v_ret switch17.callprofile61_ty; + i integer; + v_ip inet; + v_remote_ip inet; + v_remote_port INTEGER; + v_transport_protocol_id smallint; + v_customer_auth_normalized class4.customers_auth_normalized; + v_destination class4.destinations%rowtype; + v_dialpeer record; + v_rateplan class4.rateplans%rowtype; + v_dst_gw class4.gateways%rowtype; + v_orig_gw class4.gateways%rowtype; + v_rp class4.routing_plans%rowtype; + v_customer_allowtime real; + v_vendor_allowtime real; + v_sorting_id integer; + v_customer_acc integer; + v_route_found boolean:=false; + v_c_acc billing.accounts%rowtype; + v_v_acc billing.accounts%rowtype; + v_network sys.network_prefixes%rowtype; + routedata record; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ + v_rate NUMERIC; + v_now timestamp; + v_x_yeti_auth varchar; + -- v_uri_domain varchar; + v_rate_limit float:='Infinity'::float; + v_destination_rate_limit float:='Infinity'::float; + v_test_vendor_id integer; + v_random float; + v_max_call_length integer; + v_routing_key varchar; + v_lnp_key varchar; + v_drop_call_if_lnp_fail boolean; + v_lnp_rule class4.routing_plan_lnp_rules%rowtype; + v_numberlist record; + v_numberlist_item record; + v_call_tags smallint[]:='{}'::smallint[]; + v_area_direction class4.routing_tag_detection_rules%rowtype; + + BEGIN + /*dbg{*/ + v_start:=now(); + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Execution start',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + + perform id from sys.load_balancers where signalling_ip=host(i_remote_ip)::varchar; + IF FOUND and i_x_orig_ip IS not NULL AND i_x_orig_port IS not NULL THEN + v_remote_ip:=i_x_orig_ip; + v_remote_port:=i_x_orig_port; + v_transport_protocol_id=i_x_orig_protocol_id; + /*dbg{*/RAISE NOTICE '% ms -> Got originator address "%:%, proto: %" from x-headers',EXTRACT(MILLISECOND from v_end-v_start), v_remote_ip,v_remote_port, v_transport_protocol_id;/*}dbg*/ + else + v_remote_ip:=i_remote_ip; + v_remote_port:=i_remote_port; + v_transport_protocol_id:=i_protocol_id; + /*dbg{*/RAISE NOTICE '% ms -> Got originator address "%:%, proto: %" from switch leg info',EXTRACT(MILLISECOND from v_end-v_start), v_remote_ip,v_remote_port, v_transport_protocol_id;/*}dbg*/ + end if; + + v_now:=now(); + v_ret:=switch17.new_profile(); + v_ret.cache_time = 10; + + v_ret.diversion_in:=i_diversion; + v_ret.diversion_out:=i_diversion; -- FIXME + + v_ret.auth_orig_protocol_id =v_transport_protocol_id; + v_ret.auth_orig_ip = v_remote_ip; + v_ret.auth_orig_port = v_remote_port; + + v_ret.src_name_in:=i_from_dsp; + v_ret.src_name_out:=v_ret.src_name_in; + + v_ret.src_prefix_in:=i_from_name; + v_ret.dst_prefix_in:=i_uri_name; + v_ret.dst_prefix_out:=v_ret.dst_prefix_in; + v_ret.src_prefix_out:=v_ret.src_prefix_in; + + v_ret.ruri_domain=i_uri_domain; + v_ret.from_domain=i_from_domain; + v_ret.to_domain=i_to_domain; + + v_ret.pai_in=i_pai; + v_ret.ppi_in=i_ppi; + v_ret.privacy_in=i_privacy; + v_ret.rpid_in=i_rpid; + v_ret.rpid_privacy_in=i_rpid_privacy; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. lookup started',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_x_yeti_auth:=COALESCE(i_x_yeti_auth,''); + -- v_uri_domain:=COALESCE(i_uri_domain,''); + + if i_auth_id is null then + SELECT into v_customer_auth_normalized ca.* + from class4.customers_auth_normalized ca + JOIN public.contractors c ON c.id=ca.customer_id + WHERE ca.enabled AND + ca.ip>>=v_remote_ip AND + prefix_range(ca.dst_prefix)@>prefix_range(v_ret.dst_prefix_in) AND + prefix_range(ca.src_prefix)@>prefix_range(v_ret.src_prefix_in) AND + (ca.pop_id=i_pop_id or ca.pop_id is null) and + COALESCE(ca.x_yeti_auth,'')=v_x_yeti_auth AND + COALESCE(nullif(ca.uri_domain,'')=i_uri_domain,true) AND + COALESCE(nullif(ca.to_domain,'')=i_to_domain,true) AND + COALESCE(nullif(ca.from_domain,'')=i_from_domain,true) AND + (ca.transport_protocol_id is null or ca.transport_protocol_id=v_transport_protocol_id) AND + length(v_ret.dst_prefix_in) between ca.dst_number_min_length and ca.dst_number_max_length and + length(v_ret.src_prefix_in) between ca.src_number_min_length and ca.src_number_max_length and + c.enabled and c.customer + ORDER BY + masklen(ca.ip) DESC, + ca.transport_protocol_id is null, + length(prefix_range(ca.dst_prefix)) DESC, + length(prefix_range(ca.src_prefix)) DESC, + ca.pop_id is null, + ca.uri_domain is null, + ca.to_domain is null, + ca.from_domain is null, + ca.require_incoming_auth + LIMIT 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 110.Cant find customer or customer locked',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=110; --Cant find customer or customer locked + RETURN NEXT v_ret; + RETURN; + END IF; + if v_customer_auth_normalized.require_incoming_auth then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. Incoming auth required. Respond 401',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.aleg_auth_required=true; + RETURN NEXT v_ret; + RETURN; + end IF; + if v_customer_auth_normalized.reject_calls then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 8004. Reject by customers auth',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8004; -- call rejected by authorization + + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_ret.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + SELECT INTO STRICT v_ret.customer_acc_external_id external_id FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + + RETURN NEXT v_ret; + RETURN; + end if; + else + SELECT into v_customer_auth_normalized ca.* + from class4.customers_auth_normalized ca + JOIN public.contractors c ON c.id=ca.customer_id + WHERE ca.enabled AND + ca.ip>>=v_remote_ip AND + prefix_range(ca.dst_prefix)@>prefix_range(v_ret.dst_prefix_in) AND + prefix_range(ca.src_prefix)@>prefix_range(v_ret.src_prefix_in) AND + (ca.pop_id=i_pop_id or ca.pop_id is null) and + COALESCE(ca.x_yeti_auth,'')=v_x_yeti_auth AND + COALESCE(nullif(ca.uri_domain,'')=i_uri_domain,true) AND + COALESCE(nullif(ca.to_domain,'')=i_to_domain,true) AND + COALESCE(nullif(ca.from_domain,'')=i_from_domain,true) AND + (ca.transport_protocol_id is null or ca.transport_protocol_id=v_transport_protocol_id) AND + length(v_ret.dst_prefix_in) between ca.dst_number_min_length and ca.dst_number_max_length and + length(v_ret.src_prefix_in) between ca.src_number_min_length and ca.src_number_max_length and + c.enabled and c.customer and + ca.require_incoming_auth and gateway_id = i_auth_id + ORDER BY + masklen(ca.ip) DESC, + ca.transport_protocol_id is null, + length(prefix_range(ca.dst_prefix)) DESC, + length(prefix_range(ca.src_prefix)) DESC, + ca.pop_id is null, + ca.uri_domain is null, + ca.to_domain is null, + ca.from_domain is null + LIMIT 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 110.Cant find customer or customer locked',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=110; --Cant find customer or customer locked + RETURN NEXT v_ret; + RETURN; + END IF; + if v_customer_auth_normalized.reject_calls then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 8004. Reject by customers auth',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8004; -- call rejected by authorization + + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_ret.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + SELECT INTO STRICT v_ret.customer_acc_external_id external_id FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + + RETURN NEXT v_ret; + RETURN; + end if; + end IF; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. found: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(v_customer_auth_normalized, true); + /*}dbg*/ + + -- feel customer data ;-) + v_ret.dump_level_id:=v_customer_auth_normalized.dump_level_id; + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_customer_auth_normalized.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + v_ret.orig_gw_id:=v_customer_auth_normalized.gateway_id; + + v_ret.radius_auth_profile_id=v_customer_auth_normalized.radius_auth_profile_id; + v_ret.aleg_radius_acc_profile_id=v_customer_auth_normalized.radius_accounting_profile_id; + v_ret.record_audio=v_customer_auth_normalized.enable_audio_recording; + + v_ret.customer_acc_check_balance=v_customer_auth_normalized.check_account_balance; + + SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + v_ret.customer_acc_external_id=v_c_acc.external_id; + v_ret.customer_acc_vat=v_c_acc.vat; + v_destination_rate_limit=coalesce(v_c_acc.destination_rate_limit::float,'Infinity'::float); + + if v_customer_auth_normalized.check_account_balance AND v_c_acc.balance<=v_c_acc.min_balance then + v_ret.disconnect_code_id=8000; --No enough customer balance + RETURN NEXT v_ret; + RETURN; + end if; + + v_ret.customer_acc_external_id=v_c_acc.external_id; + v_ret.customer_acc_vat=v_c_acc.vat; + + SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth_normalized.gateway_id; + if not v_orig_gw.enabled then + v_ret.disconnect_code_id=8005; -- Origination gateway is disabled + RETURN NEXT v_ret; + RETURN; + end if; + + v_ret.resources:=''; + if v_c_acc.origination_capacity is not null then + v_ret.resources:=v_ret.resources||'7:'||v_c_acc.id::varchar||':'||v_c_acc.total_capacity::varchar||':1;'; + end if; + + if v_c_acc.total_capacity is not null then + v_ret.resources:=v_ret.resources||'1:'||v_c_acc.id::varchar||':'||v_c_acc.origination_capacity::varchar||':1;'; + end if; + + if v_customer_auth_normalized.capacity is not null then + v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.customers_auth_id||':'||v_customer_auth_normalized.capacity::varchar||':1;'; + end if; + if v_orig_gw.origination_capacity is not null then + v_ret.resources:=v_ret.resources||'4:'||v_orig_gw.id::varchar||':'||v_orig_gw.origination_capacity::varchar||':1;'; + end if; + + -- Tag processing CA + v_call_tags=yeti_ext.tag_action(v_customer_auth_normalized.tag_action_id, v_call_tags, v_customer_auth_normalized.tag_action_value); + + /* + number rewriting _Before_ routing + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.src_prefix_out,v_ret.dst_prefix_out; + /*}dbg*/ + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand(v_ret.dst_prefix_out,v_customer_auth_normalized.dst_rewrite_rule,v_customer_auth_normalized.dst_rewrite_result); + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand(v_ret.src_prefix_out,v_customer_auth_normalized.src_rewrite_rule,v_customer_auth_normalized.src_rewrite_result); + v_ret.src_name_out=yeti_ext.regexp_replace_rand(v_ret.src_name_out,v_customer_auth_normalized.src_name_rewrite_rule,v_customer_auth_normalized.src_name_rewrite_result, true); + + -- if v_ret.radius_auth_profile_id is not null then + v_ret.src_number_radius:=i_from_name; + v_ret.dst_number_radius:=i_uri_name; + v_ret.src_number_radius=yeti_ext.regexp_replace_rand( + v_ret.src_number_radius, + v_customer_auth_normalized.src_number_radius_rewrite_rule, + v_customer_auth_normalized.src_number_radius_rewrite_result + ); + + v_ret.dst_number_radius=yeti_ext.regexp_replace_rand( + v_ret.dst_number_radius, + v_customer_auth_normalized.dst_number_radius_rewrite_rule, + v_customer_auth_normalized.dst_number_radius_rewrite_result + ); + v_ret.customer_auth_name=v_customer_auth_normalized."name"; + v_ret.customer_name=(select "name" from public.contractors where id=v_customer_auth_normalized.customer_id limit 1); + -- end if; + + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.src_prefix_out,v_ret.dst_prefix_out; + /*}dbg*/ + + ----- Numberlist processing------------------------------------------------------------------------------------------------------- + if v_customer_auth_normalized.dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.dst_prefix_out; + /*}dbg*/ + select into v_numberlist * from class4.numberlists where id=v_customer_auth_normalized.dst_numberlist_id; + CASE v_numberlist.mode_id + when 1 then -- strict match + select into v_numberlist_item * + from class4.numberlist_items ni + where ni.numberlist_id=v_customer_auth_normalized.dst_numberlist_id and ni.key=v_ret.dst_prefix_out limit 1; + when 2 then -- prefix match + select into v_numberlist_item * + from class4.numberlist_items ni + where + ni.numberlist_id=v_customer_auth_normalized.dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(v_ret.dst_prefix_out) and + length(v_ret.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) + desc limit 1; + + end case; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_numberlist_item); + /*}dbg*/ + IF v_numberlist_item.action_id is not null and v_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. Drop by key action. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_numberlist_item.key; + /*}dbg*/ + v_ret.disconnect_code_id=8001; --destination blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is not null and v_numberlist_item.action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist_item.src_rewrite_rule, + v_numberlist_item.src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist_item.dst_rewrite_rule, + v_numberlist_item.dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist_item.tag_action_id, v_call_tags, v_numberlist_item.tag_action_value); + -- pass call NOP. + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. Drop by default action',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + v_ret.disconnect_code_id=8001; --destination blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist.default_src_rewrite_rule, + v_numberlist.default_src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist.default_dst_rewrite_rule, + v_numberlist.default_dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist.tag_action_id, v_call_tags, v_numberlist.tag_action_value); + -- pass by default + end if; + end if; + + if v_customer_auth_normalized.src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist processing. Lookup by key: %s',EXTRACT(MILLISECOND from v_end-v_start), v_ret.src_prefix_out; + /*}dbg*/ + select into v_numberlist * from class4.numberlists where id=v_customer_auth_normalized.src_numberlist_id; + CASE v_numberlist.mode_id + when 1 then -- strict match + select into v_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=v_customer_auth_normalized.src_numberlist_id and ni.key=v_ret.src_prefix_out limit 1; + when 2 then -- prefix match + select into v_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=v_customer_auth_normalized.src_numberlist_id and + prefix_range(ni.key)@>prefix_range(v_ret.src_prefix_out) and + length(v_ret.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc limit 1; + end case; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_numberlist_item); + /*}dbg*/ + IF v_numberlist_item.action_id is not null and v_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. Drop by key action. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_numberlist_item.key; + /*}dbg*/ + v_ret.disconnect_code_id=8002; --source blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is not null and v_numberlist_item.action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist_item.src_rewrite_rule, + v_numberlist_item.src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist_item.dst_rewrite_rule, + v_numberlist_item.dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist_item.tag_action_id, v_call_tags, v_numberlist_item.tag_action_value); + -- pass call NOP. + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. Drop by default action',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8002; --source blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist.default_src_rewrite_rule, + v_numberlist.default_src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist.default_dst_rewrite_rule, + v_numberlist.default_dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist.tag_action_id, v_call_tags, v_numberlist.tag_action_value); + -- pass by default + end if; + end if; + + -- setting numbers used for routing & billing + v_ret.src_prefix_routing=v_ret.src_prefix_out; + v_ret.dst_prefix_routing=v_ret.dst_prefix_out; + v_routing_key=v_ret.dst_prefix_out; + + -- Areas and Tag detection------------------------------------------- + v_ret.src_area_id:=( + select area_id from class4.area_prefixes where prefix_range(prefix)@>prefix_range(v_ret.src_prefix_routing) + order by length(prefix_range(prefix)) desc limit 1 + ); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Area found: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.src_area_id; + /*}dbg*/ + + v_ret.dst_area_id:=( + select area_id from class4.area_prefixes where prefix_range(prefix)@>prefix_range(v_ret.dst_prefix_routing) + order by length(prefix_range(prefix)) desc limit 1 + ); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Area found: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.dst_area_id; + /*}dbg*/ + + + select into v_area_direction * from class4.routing_tag_detection_rules + where + (src_area_id is null OR src_area_id = v_ret.src_area_id) AND + (dst_area_id is null OR dst_area_id = v_ret.dst_area_id) AND + prefix_range(src_prefix) @> prefix_range(v_ret.src_prefix_routing) AND + prefix_range(dst_prefix) @> prefix_range(v_ret.dst_prefix_routing) AND + yeti_ext.tag_compare(routing_tag_ids, v_call_tags, routing_tag_mode_id ) > 0 + order by + yeti_ext.tag_compare(routing_tag_ids, v_call_tags, routing_tag_mode_id) desc, + length(prefix_range(v_ret.src_prefix_routing)) desc, + length(prefix_range(v_ret.dst_prefix_routing)) desc, + src_area_id is null, + dst_area_id is null + limit 1; + if found then + v_call_tags=yeti_ext.tag_action(v_area_direction.tag_action_id, v_call_tags, v_area_direction.tag_action_value); + end if; + + v_ret.routing_tag_ids:=v_call_tags; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Routing tag detected: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.routing_tag_ids; + /*}dbg*/ + ---------------------------------------------------------------------- + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Routing plan search start',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + + select into v_max_call_length,v_drop_call_if_lnp_fail max_call_duration,drop_call_if_lnp_fail from sys.guiconfig limit 1; + + v_routing_key=v_ret.dst_prefix_routing; + SELECT INTO v_rp * from class4.routing_plans WHERE id=v_customer_auth_normalized.routing_plan_id; + if v_rp.sorting_id=5 then -- route testing + v_test_vendor_id=regexp_replace(v_routing_key,'(.*)\*(.*)','\1')::integer; + v_routing_key=regexp_replace(v_routing_key,'(.*)\*(.*)','\2'); + v_ret.dst_prefix_out=v_routing_key; + v_ret.dst_prefix_routing=v_routing_key; + end if; + + if v_rp.use_lnp then + select into v_lnp_rule rules.* + from class4.routing_plan_lnp_rules rules + WHERE prefix_range(rules.dst_prefix)@>prefix_range(v_ret.dst_prefix_routing) and rules.routing_plan_id=v_rp.id + order by length(prefix_range(rules.dst_prefix)) limit 1; + if found then + v_ret.lnp_database_id=v_lnp_rule.database_id; + v_lnp_key=v_ret.dst_prefix_routing; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Need LNP lookup, LNP key: %',EXTRACT(MILLISECOND from v_end-v_start),v_lnp_key; + /*}dbg*/ + v_lnp_key=yeti_ext.regexp_replace_rand(v_lnp_key,v_lnp_rule.req_dst_rewrite_rule,v_lnp_rule.req_dst_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP key translation. LNP key: %',EXTRACT(MILLISECOND from v_end-v_start),v_lnp_key; + /*}dbg*/ + -- try cache + select into v_ret.lrn lrn from class4.lnp_cache where dst=v_lnp_key AND database_id=v_lnp_rule.database_id and expires_at>v_now; + if found then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Data found in cache, lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + -- TRANSLATING response from cache + v_ret.lrn=yeti_ext.regexp_replace_rand(v_ret.lrn,v_lnp_rule.lrn_rewrite_rule,v_lnp_rule.lrn_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Translation. lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + v_routing_key=v_ret.lrn; + else + v_ret.lrn=switch17.lnp_resolve(v_ret.lnp_database_id,v_lnp_key); + if v_ret.lrn is null then -- fail + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Query failed',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + if v_drop_call_if_lnp_fail then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Dropping call',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8003; --No response from LNP DB + RETURN NEXT v_ret; + RETURN; + end if; + else + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Success, lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + -- TRANSLATING response from LNP DB + v_ret.lrn=yeti_ext.regexp_replace_rand(v_ret.lrn,v_lnp_rule.lrn_rewrite_rule,v_lnp_rule.lrn_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Translation. lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + v_routing_key=v_ret.lrn; + end if; + end if; + end if; + end if; + + + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. search start. Routing key: %. Routing tags: %, Rate limit: %',EXTRACT(MILLISECOND from v_end-v_start), v_routing_key, v_ret.routing_tag_ids, v_destination_rate_limit; + /*}dbg*/ + v_network:=switch17.detect_network(v_ret.dst_prefix_routing); + v_ret.dst_network_id=v_network.network_id; + v_ret.dst_country_id=v_network.country_id; + + SELECT into v_destination d.*/*,switch.tracelog(d.*)*/ from class4.destinations d + WHERE + prefix_range(prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between d.dst_number_min_length and d.dst_number_max_length + AND rateplan_id=v_customer_auth_normalized.rateplan_id + AND enabled + AND valid_from <= v_now + AND valid_till >= v_now + AND yeti_ext.tag_compare(d.routing_tag_ids, v_call_tags, d.routing_tag_mode_id)>0 + ORDER BY length(prefix_range(prefix)) DESC, yeti_ext.tag_compare(d.routing_tag_ids, v_call_tags) desc + limit 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. Destination not found',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=111; --Cant find destination prefix + RETURN NEXT v_ret; + RETURN; + END IF; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. found: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(v_destination, true); + /*}dbg*/ + + v_ret.destination_id:=v_destination.id; + v_ret.destination_prefix=v_destination.prefix; + v_ret.destination_initial_interval:=v_destination.initial_interval; + v_ret.destination_fee:=v_destination.connect_fee::varchar; + v_ret.destination_next_interval:=v_destination.next_interval; + v_ret.destination_rate_policy_id:=v_destination.rate_policy_id; + v_ret.destination_reverse_billing:=v_destination.reverse_billing; + IF v_destination.reject_calls THEN + v_ret.disconnect_code_id=112; --Rejected by destination + RETURN NEXT v_ret; + RETURN; + END IF; + + if v_destination.next_rate::float>v_destination_rate_limit then + v_ret.disconnect_code_id=8006; -- No destination with appropriate rate found + RETURN NEXT v_ret; + RETURN; + end if; + + select into v_rateplan * from class4.rateplans where id=v_customer_auth_normalized.rateplan_id; + if COALESCE(v_destination.profit_control_mode_id,v_rateplan.profit_control_mode_id)=2 then -- per call + v_rate_limit=v_destination.next_rate::float; + end if; + + + /* + FIND dialpeers logic. Queries must use prefix index for best performance + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. search start. Routing key: %. Rate limit: %. Routing tag: %',EXTRACT(MILLISECOND from v_end-v_start), v_routing_key, v_rate_limit, v_ret.routing_tag_ids; + /*}dbg*/ + CASE v_rp.sorting_id + WHEN'1' THEN -- LCR,Prio, ACD&ASR control + FOR routedata IN ( + WITH step1 AS( + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + t_dp.next_rate as dp_next_rate, + t_dp.lcr_rate_multiplier AS dp_lcr_rate_multiplier, + t_dp.priority AS dp_priority, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id = t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + from step1 + WHERE + r=1 + and exclusive_rank=1 + AND dp_next_rate<=v_rate_limit + AND dp_enabled + and not dp_locked --ACD&ASR control for DP + ORDER BY dp_next_rate*dp_lcr_rate_multiplier, dp_priority DESC + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + end LOOP; + WHEN '2' THEN --LCR, no prio, No ACD&ASR control + FOR routedata IN ( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + -- (t_vendor_gateway.*)::class4.gateways as s1_vendor_gateway, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + AND dp_enabled + and dp_next_rate<=v_rate_limit + ORDER BY dp_metric + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN '3' THEN --Prio, LCR, ACD&ASR control + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + and not dp_locked + ORDER BY dp_metric_priority DESC, dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'4' THEN -- LCRD, Prio, ACD&ACR control + FOR routedata IN ( + WITH step1 AS( + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + ((t_dp.next_rate - first_value(t_dp.next_rate) OVER(ORDER BY t_dp.next_rate ASC)) > v_rp.rate_delta_max)::INTEGER *(t_dp.next_rate + t_dp.priority) - t_dp.priority AS r2, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id = t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + from step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_next_rate <= v_rate_limit + and dp_enabled + and not dp_locked --ACD&ASR control for DP + ORDER BY r2 ASC + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + end LOOP; + WHEN'5' THEN -- Route test + FOR routedata IN ( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_enabled + and dp_next_rate<=v_rate_limit + ORDER BY dp_metric_priority DESC, dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'6' THEN -- QD.Static,LCR,ACD&ACR control + v_random:=random(); + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY length(prefix_range(coalesce(rpsr.prefix,''))) desc + ) as r2, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled, + t_dp.force_hit_rate as dp_force_hit_rate, + rpsr.priority as rpsr_priority, + rpsr.weight as rpsr_weight + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + left join class4.routing_plan_static_routes rpsr + ON rpsr.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and rpsr.vendor_id=t_dp.vendor_id + AND prefix_range(rpsr.prefix)@>prefix_range(v_routing_key) + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and r2=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + and not dp_locked + ORDER BY + coalesce(v_random<=dp_force_hit_rate,false) desc, + yeti_ext.rank_dns_srv(rpsr_weight) over ( partition by rpsr_priority order by rpsr_weight), + dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'7' THEN -- QD.Static, No ACD&ACR control + v_random:=random(); + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY length(prefix_range(coalesce(rpsr.prefix,''))) desc + ) as r2, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled, + t_dp.force_hit_rate as dp_force_hit_rate, + rpsr.priority as rpsr_priority, + rpsr.weight as rpsr_weight + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + join class4.routing_plan_static_routes rpsr + ON rpsr.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and rpsr.vendor_id=t_dp.vendor_id + AND prefix_range(rpsr.prefix)@>prefix_range(v_routing_key) + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and r2=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + ORDER BY + coalesce(v_random<=dp_force_hit_rate,false) desc, + yeti_ext.rank_dns_srv(rpsr_weight) over ( partition by rpsr_priority order by rpsr_weight), + dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + + ELSE + RAISE NOTICE 'BUG: unknown sorting_id'; + END CASE; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Dialpeer search done',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=113; --No routes + RETURN NEXT v_ret; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DONE.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN; + END; + $$; + + set search_path TO switch17; + SELECT * from switch17.preprocess_all(); + set search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; + + + + } + + end + + + def down + execute %q{ +CREATE or replace FUNCTION switch17.route(i_node_id integer, i_pop_id integer, i_protocol_id smallint, i_remote_ip inet, i_remote_port integer, i_local_ip inet, i_local_port integer, i_from_dsp character varying, i_from_name character varying, i_from_domain character varying, i_from_port integer, i_to_name character varying, i_to_domain character varying, i_to_port integer, i_contact_name character varying, i_contact_domain character varying, i_contact_port integer, i_uri_name character varying, i_uri_domain character varying, i_auth_id integer, i_x_yeti_auth character varying, i_diversion character varying, i_x_orig_ip inet, i_x_orig_port integer, i_x_orig_protocol_id smallint, i_pai character varying, i_ppi character varying, i_privacy character varying, i_rpid character varying, i_rpid_privacy character varying) RETURNS SETOF switch17.callprofile61_ty + LANGUAGE plpgsql SECURITY DEFINER ROWS 10 + AS $$ + DECLARE + v_ret switch17.callprofile61_ty; + i integer; + v_ip inet; + v_remote_ip inet; + v_remote_port INTEGER; + v_transport_protocol_id smallint; + v_customer_auth_normalized class4.customers_auth_normalized; + v_destination class4.destinations%rowtype; + v_dialpeer record; + v_rateplan class4.rateplans%rowtype; + v_dst_gw class4.gateways%rowtype; + v_orig_gw class4.gateways%rowtype; + v_rp class4.routing_plans%rowtype; + v_customer_allowtime real; + v_vendor_allowtime real; + v_sorting_id integer; + v_customer_acc integer; + v_route_found boolean:=false; + v_c_acc billing.accounts%rowtype; + v_v_acc billing.accounts%rowtype; + v_network sys.network_prefixes%rowtype; + routedata record; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ + v_rate NUMERIC; + v_now timestamp; + v_x_yeti_auth varchar; + -- v_uri_domain varchar; + v_rate_limit float:='Infinity'::float; + v_destination_rate_limit float:='Infinity'::float; + v_test_vendor_id integer; + v_random float; + v_max_call_length integer; + v_routing_key varchar; + v_lnp_key varchar; + v_drop_call_if_lnp_fail boolean; + v_lnp_rule class4.routing_plan_lnp_rules%rowtype; + v_numberlist record; + v_numberlist_item record; + v_call_tags smallint[]:='{}'::smallint[]; + v_area_direction class4.routing_tag_detection_rules%rowtype; + + BEGIN + /*dbg{*/ + v_start:=now(); + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Execution start',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + + perform id from sys.load_balancers where signalling_ip=host(i_remote_ip)::varchar; + IF FOUND and i_x_orig_ip IS not NULL AND i_x_orig_port IS not NULL THEN + v_remote_ip:=i_x_orig_ip; + v_remote_port:=i_x_orig_port; + v_transport_protocol_id=i_x_orig_protocol_id; + /*dbg{*/RAISE NOTICE '% ms -> Got originator address "%:%, proto: %" from x-headers',EXTRACT(MILLISECOND from v_end-v_start), v_remote_ip,v_remote_port, v_transport_protocol_id;/*}dbg*/ + else + v_remote_ip:=i_remote_ip; + v_remote_port:=i_remote_port; + v_transport_protocol_id:=i_protocol_id; + /*dbg{*/RAISE NOTICE '% ms -> Got originator address "%:%, proto: %" from switch leg info',EXTRACT(MILLISECOND from v_end-v_start), v_remote_ip,v_remote_port, v_transport_protocol_id;/*}dbg*/ + end if; + + v_now:=now(); + v_ret:=switch17.new_profile(); + v_ret.cache_time = 10; + + v_ret.diversion_in:=i_diversion; + v_ret.diversion_out:=i_diversion; -- FIXME + + v_ret.auth_orig_protocol_id =v_transport_protocol_id; + v_ret.auth_orig_ip = v_remote_ip; + v_ret.auth_orig_port = v_remote_port; + + v_ret.src_name_in:=i_from_dsp; + v_ret.src_name_out:=v_ret.src_name_in; + + v_ret.src_prefix_in:=i_from_name; + v_ret.dst_prefix_in:=i_uri_name; + v_ret.dst_prefix_out:=v_ret.dst_prefix_in; + v_ret.src_prefix_out:=v_ret.src_prefix_in; + + v_ret.ruri_domain=i_uri_domain; + v_ret.from_domain=i_from_domain; + v_ret.to_domain=i_to_domain; + + v_ret.pai_in=i_pai; + v_ret.ppi_in=i_ppi; + v_ret.privacy_in=i_privacy; + v_ret.rpid_in=i_rpid; + v_ret.rpid_privacy_in=i_rpid_privacy; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. lookup started',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_x_yeti_auth:=COALESCE(i_x_yeti_auth,''); + -- v_uri_domain:=COALESCE(i_uri_domain,''); + + if i_auth_id is null then + SELECT into v_customer_auth_normalized ca.* + from class4.customers_auth_normalized ca + JOIN public.contractors c ON c.id=ca.customer_id + WHERE ca.enabled AND + ca.ip>>=v_remote_ip AND + prefix_range(ca.dst_prefix)@>prefix_range(v_ret.dst_prefix_in) AND + prefix_range(ca.src_prefix)@>prefix_range(v_ret.src_prefix_in) AND + (ca.pop_id=i_pop_id or ca.pop_id is null) and + COALESCE(ca.x_yeti_auth,'')=v_x_yeti_auth AND + COALESCE(nullif(ca.uri_domain,'')=i_uri_domain,true) AND + COALESCE(nullif(ca.to_domain,'')=i_to_domain,true) AND + COALESCE(nullif(ca.from_domain,'')=i_from_domain,true) AND + (ca.transport_protocol_id is null or ca.transport_protocol_id=v_transport_protocol_id) AND + length(v_ret.dst_prefix_in) between ca.dst_number_min_length and ca.dst_number_max_length and + length(v_ret.src_prefix_in) between ca.src_number_min_length and ca.src_number_max_length and + c.enabled and c.customer + ORDER BY + masklen(ca.ip) DESC, + ca.transport_protocol_id is null, + length(prefix_range(ca.dst_prefix)) DESC, + length(prefix_range(ca.src_prefix)) DESC, + ca.pop_id is null, + ca.uri_domain is null, + ca.to_domain is null, + ca.from_domain is null, + ca.require_incoming_auth + LIMIT 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 110.Cant find customer or customer locked',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=110; --Cant find customer or customer locked + RETURN NEXT v_ret; + RETURN; + END IF; + if v_customer_auth_normalized.require_incoming_auth then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. Incoming auth required. Respond 401',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.aleg_auth_required=true; + RETURN NEXT v_ret; + RETURN; + end IF; + if v_customer_auth_normalized.reject_calls then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 8004. Reject by customers auth',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8004; -- call rejected by authorization + + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_ret.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + SELECT INTO STRICT v_ret.customer_acc_external_id external_id FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + + RETURN NEXT v_ret; + RETURN; + end if; + else + SELECT into v_customer_auth_normalized ca.* + from class4.customers_auth_normalized ca + JOIN public.contractors c ON c.id=ca.customer_id + WHERE ca.enabled AND + ca.ip>>=v_remote_ip AND + prefix_range(ca.dst_prefix)@>prefix_range(v_ret.dst_prefix_in) AND + prefix_range(ca.src_prefix)@>prefix_range(v_ret.src_prefix_in) AND + (ca.pop_id=i_pop_id or ca.pop_id is null) and + COALESCE(ca.x_yeti_auth,'')=v_x_yeti_auth AND + COALESCE(nullif(ca.uri_domain,'')=i_uri_domain,true) AND + COALESCE(nullif(ca.to_domain,'')=i_to_domain,true) AND + COALESCE(nullif(ca.from_domain,'')=i_from_domain,true) AND + (ca.transport_protocol_id is null or ca.transport_protocol_id=v_transport_protocol_id) AND + length(v_ret.dst_prefix_in) between ca.dst_number_min_length and ca.dst_number_max_length and + length(v_ret.src_prefix_in) between ca.src_number_min_length and ca.src_number_max_length and + c.enabled and c.customer and + ca.require_incoming_auth and gateway_id = i_auth_id + ORDER BY + masklen(ca.ip) DESC, + ca.transport_protocol_id is null, + length(prefix_range(ca.dst_prefix)) DESC, + length(prefix_range(ca.src_prefix)) DESC, + ca.pop_id is null, + ca.uri_domain is null, + ca.to_domain is null, + ca.from_domain is null + LIMIT 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 110.Cant find customer or customer locked',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=110; --Cant find customer or customer locked + RETURN NEXT v_ret; + RETURN; + END IF; + if v_customer_auth_normalized.reject_calls then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. disconnection with 8004. Reject by customers auth',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8004; -- call rejected by authorization + + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_ret.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + SELECT INTO STRICT v_ret.customer_acc_external_id external_id FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + + RETURN NEXT v_ret; + RETURN; + end if; + end IF; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. found: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(v_customer_auth_normalized, true); + /*}dbg*/ + + -- feel customer data ;-) + v_ret.dump_level_id:=v_customer_auth_normalized.dump_level_id; + v_ret.customer_auth_id:=v_customer_auth_normalized.customers_auth_id; + v_ret.customer_auth_external_id:=v_customer_auth_normalized.external_id; + + v_ret.customer_id:=v_customer_auth_normalized.customer_id; + select into strict v_ret.customer_external_id external_id from public.contractors where id=v_customer_auth_normalized.customer_id; + + v_ret.rateplan_id:=v_customer_auth_normalized.rateplan_id; + v_ret.routing_plan_id:=v_customer_auth_normalized.routing_plan_id; + v_ret.customer_acc_id:=v_customer_auth_normalized.account_id; + v_ret.orig_gw_id:=v_customer_auth_normalized.gateway_id; + + v_ret.radius_auth_profile_id=v_customer_auth_normalized.radius_auth_profile_id; + v_ret.aleg_radius_acc_profile_id=v_customer_auth_normalized.radius_accounting_profile_id; + v_ret.record_audio=v_customer_auth_normalized.enable_audio_recording; + + v_ret.customer_acc_check_balance=v_customer_auth_normalized.check_account_balance; + + SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth_normalized.account_id; + v_ret.customer_acc_external_id=v_c_acc.external_id; + v_ret.customer_acc_vat=v_c_acc.vat; + v_destination_rate_limit=coalesce(v_c_acc.destination_rate_limit::float,'Infinity'::float); + + if v_customer_auth_normalized.check_account_balance AND v_c_acc.balance<=v_c_acc.min_balance then + v_ret.disconnect_code_id=8000; --No enough customer balance + RETURN NEXT v_ret; + RETURN; + end if; + + v_ret.customer_acc_external_id=v_c_acc.external_id; + v_ret.customer_acc_vat=v_c_acc.vat; + + SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth_normalized.gateway_id; + if not v_orig_gw.enabled then + v_ret.disconnect_code_id=8005; -- Origination gateway is disabled + RETURN NEXT v_ret; + RETURN; + end if; + + v_ret.resources:=''; + if v_c_acc.origination_capacity is not null then + v_ret.resources:=v_ret.resources||'7:'||v_c_acc.id::varchar||':'||v_c_acc.total_capacity::varchar||':1;'; + end if; + + if v_c_acc.total_capacity is not null then + v_ret.resources:=v_ret.resources||'1:'||v_c_acc.id::varchar||':'||v_c_acc.origination_capacity::varchar||':1;'; + end if; + + if v_customer_auth_normalized.capacity is not null then + v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.id::varchar||':'||v_customer_auth_normalized.capacity::varchar||':1;'; + end if; + if v_orig_gw.origination_capacity is not null then + v_ret.resources:=v_ret.resources||'4:'||v_orig_gw.id::varchar||':'||v_orig_gw.origination_capacity::varchar||':1;'; + end if; + + -- Tag processing CA + v_call_tags=yeti_ext.tag_action(v_customer_auth_normalized.tag_action_id, v_call_tags, v_customer_auth_normalized.tag_action_value); + + /* + number rewriting _Before_ routing + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.src_prefix_out,v_ret.dst_prefix_out; + /*}dbg*/ + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand(v_ret.dst_prefix_out,v_customer_auth_normalized.dst_rewrite_rule,v_customer_auth_normalized.dst_rewrite_result); + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand(v_ret.src_prefix_out,v_customer_auth_normalized.src_rewrite_rule,v_customer_auth_normalized.src_rewrite_result); + v_ret.src_name_out=yeti_ext.regexp_replace_rand(v_ret.src_name_out,v_customer_auth_normalized.src_name_rewrite_rule,v_customer_auth_normalized.src_name_rewrite_result, true); + + -- if v_ret.radius_auth_profile_id is not null then + v_ret.src_number_radius:=i_from_name; + v_ret.dst_number_radius:=i_uri_name; + v_ret.src_number_radius=yeti_ext.regexp_replace_rand( + v_ret.src_number_radius, + v_customer_auth_normalized.src_number_radius_rewrite_rule, + v_customer_auth_normalized.src_number_radius_rewrite_result + ); + + v_ret.dst_number_radius=yeti_ext.regexp_replace_rand( + v_ret.dst_number_radius, + v_customer_auth_normalized.dst_number_radius_rewrite_rule, + v_customer_auth_normalized.dst_number_radius_rewrite_result + ); + v_ret.customer_auth_name=v_customer_auth_normalized."name"; + v_ret.customer_name=(select "name" from public.contractors where id=v_customer_auth_normalized.customer_id limit 1); + -- end if; + + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> AUTH. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.src_prefix_out,v_ret.dst_prefix_out; + /*}dbg*/ + + ----- Numberlist processing------------------------------------------------------------------------------------------------------- + if v_customer_auth_normalized.dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.dst_prefix_out; + /*}dbg*/ + select into v_numberlist * from class4.numberlists where id=v_customer_auth_normalized.dst_numberlist_id; + CASE v_numberlist.mode_id + when 1 then -- strict match + select into v_numberlist_item * + from class4.numberlist_items ni + where ni.numberlist_id=v_customer_auth_normalized.dst_numberlist_id and ni.key=v_ret.dst_prefix_out limit 1; + when 2 then -- prefix match + select into v_numberlist_item * + from class4.numberlist_items ni + where + ni.numberlist_id=v_customer_auth_normalized.dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(v_ret.dst_prefix_out) and + length(v_ret.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) + desc limit 1; + + end case; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_numberlist_item); + /*}dbg*/ + IF v_numberlist_item.action_id is not null and v_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. Drop by key action. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_numberlist_item.key; + /*}dbg*/ + v_ret.disconnect_code_id=8001; --destination blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is not null and v_numberlist_item.action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist_item.src_rewrite_rule, + v_numberlist_item.src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist_item.dst_rewrite_rule, + v_numberlist_item.dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist_item.tag_action_id, v_call_tags, v_numberlist_item.tag_action_value); + -- pass call NOP. + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Numberlist. Drop by default action',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + v_ret.disconnect_code_id=8001; --destination blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist.default_src_rewrite_rule, + v_numberlist.default_src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist.default_dst_rewrite_rule, + v_numberlist.default_dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist.tag_action_id, v_call_tags, v_numberlist.tag_action_value); + -- pass by default + end if; + end if; + + if v_customer_auth_normalized.src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist processing. Lookup by key: %s',EXTRACT(MILLISECOND from v_end-v_start), v_ret.src_prefix_out; + /*}dbg*/ + select into v_numberlist * from class4.numberlists where id=v_customer_auth_normalized.src_numberlist_id; + CASE v_numberlist.mode_id + when 1 then -- strict match + select into v_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=v_customer_auth_normalized.src_numberlist_id and ni.key=v_ret.src_prefix_out limit 1; + when 2 then -- prefix match + select into v_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=v_customer_auth_normalized.src_numberlist_id and + prefix_range(ni.key)@>prefix_range(v_ret.src_prefix_out) and + length(v_ret.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc limit 1; + end case; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_numberlist_item); + /*}dbg*/ + IF v_numberlist_item.action_id is not null and v_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. Drop by key action. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_numberlist_item.key; + /*}dbg*/ + v_ret.disconnect_code_id=8002; --source blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is not null and v_numberlist_item.action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist_item.src_rewrite_rule, + v_numberlist_item.src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist_item.dst_rewrite_rule, + v_numberlist_item.dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist_item.tag_action_id, v_call_tags, v_numberlist_item.tag_action_value); + -- pass call NOP. + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Numberlist. Drop by default action',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8002; --source blacklisted + RETURN NEXT v_ret; + RETURN; + elsif v_numberlist_item.action_id is null and v_numberlist.default_action_id=2 then + v_ret.src_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.src_prefix_out, + v_numberlist.default_src_rewrite_rule, + v_numberlist.default_src_rewrite_result + ); + v_ret.dst_prefix_out=yeti_ext.regexp_replace_rand( + v_ret.dst_prefix_out, + v_numberlist.default_dst_rewrite_rule, + v_numberlist.default_dst_rewrite_result + ); + v_call_tags=yeti_ext.tag_action(v_numberlist.tag_action_id, v_call_tags, v_numberlist.tag_action_value); + -- pass by default + end if; + end if; + + -- setting numbers used for routing & billing + v_ret.src_prefix_routing=v_ret.src_prefix_out; + v_ret.dst_prefix_routing=v_ret.dst_prefix_out; + v_routing_key=v_ret.dst_prefix_out; + + -- Areas and Tag detection------------------------------------------- + v_ret.src_area_id:=( + select area_id from class4.area_prefixes where prefix_range(prefix)@>prefix_range(v_ret.src_prefix_routing) + order by length(prefix_range(prefix)) desc limit 1 + ); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> SRC Area found: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.src_area_id; + /*}dbg*/ + + v_ret.dst_area_id:=( + select area_id from class4.area_prefixes where prefix_range(prefix)@>prefix_range(v_ret.dst_prefix_routing) + order by length(prefix_range(prefix)) desc limit 1 + ); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST Area found: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.dst_area_id; + /*}dbg*/ + + + select into v_area_direction * from class4.routing_tag_detection_rules + where + (src_area_id is null OR src_area_id = v_ret.src_area_id) AND + (dst_area_id is null OR dst_area_id = v_ret.dst_area_id) AND + prefix_range(src_prefix) @> prefix_range(v_ret.src_prefix_routing) AND + prefix_range(dst_prefix) @> prefix_range(v_ret.dst_prefix_routing) AND + yeti_ext.tag_compare(routing_tag_ids, v_call_tags, routing_tag_mode_id ) > 0 + order by + yeti_ext.tag_compare(routing_tag_ids, v_call_tags, routing_tag_mode_id) desc, + length(prefix_range(v_ret.src_prefix_routing)) desc, + length(prefix_range(v_ret.dst_prefix_routing)) desc, + src_area_id is null, + dst_area_id is null + limit 1; + if found then + v_call_tags=yeti_ext.tag_action(v_area_direction.tag_action_id, v_call_tags, v_area_direction.tag_action_value); + end if; + + v_ret.routing_tag_ids:=v_call_tags; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Routing tag detected: %',EXTRACT(MILLISECOND from v_end-v_start), v_ret.routing_tag_ids; + /*}dbg*/ + ---------------------------------------------------------------------- + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Routing plan search start',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + + select into v_max_call_length,v_drop_call_if_lnp_fail max_call_duration,drop_call_if_lnp_fail from sys.guiconfig limit 1; + + v_routing_key=v_ret.dst_prefix_routing; + SELECT INTO v_rp * from class4.routing_plans WHERE id=v_customer_auth_normalized.routing_plan_id; + if v_rp.sorting_id=5 then -- route testing + v_test_vendor_id=regexp_replace(v_routing_key,'(.*)\*(.*)','\1')::integer; + v_routing_key=regexp_replace(v_routing_key,'(.*)\*(.*)','\2'); + v_ret.dst_prefix_out=v_routing_key; + v_ret.dst_prefix_routing=v_routing_key; + end if; + + if v_rp.use_lnp then + select into v_lnp_rule rules.* + from class4.routing_plan_lnp_rules rules + WHERE prefix_range(rules.dst_prefix)@>prefix_range(v_ret.dst_prefix_routing) and rules.routing_plan_id=v_rp.id + order by length(prefix_range(rules.dst_prefix)) limit 1; + if found then + v_ret.lnp_database_id=v_lnp_rule.database_id; + v_lnp_key=v_ret.dst_prefix_routing; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Need LNP lookup, LNP key: %',EXTRACT(MILLISECOND from v_end-v_start),v_lnp_key; + /*}dbg*/ + v_lnp_key=yeti_ext.regexp_replace_rand(v_lnp_key,v_lnp_rule.req_dst_rewrite_rule,v_lnp_rule.req_dst_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP key translation. LNP key: %',EXTRACT(MILLISECOND from v_end-v_start),v_lnp_key; + /*}dbg*/ + -- try cache + select into v_ret.lrn lrn from class4.lnp_cache where dst=v_lnp_key AND database_id=v_lnp_rule.database_id and expires_at>v_now; + if found then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Data found in cache, lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + -- TRANSLATING response from cache + v_ret.lrn=yeti_ext.regexp_replace_rand(v_ret.lrn,v_lnp_rule.lrn_rewrite_rule,v_lnp_rule.lrn_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Translation. lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + v_routing_key=v_ret.lrn; + else + v_ret.lrn=switch17.lnp_resolve(v_ret.lnp_database_id,v_lnp_key); + if v_ret.lrn is null then -- fail + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Query failed',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + if v_drop_call_if_lnp_fail then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Dropping call',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=8003; --No response from LNP DB + RETURN NEXT v_ret; + RETURN; + end if; + else + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Success, lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + -- TRANSLATING response from LNP DB + v_ret.lrn=yeti_ext.regexp_replace_rand(v_ret.lrn,v_lnp_rule.lrn_rewrite_rule,v_lnp_rule.lrn_rewrite_result); + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> LNP. Translation. lrn: %',EXTRACT(MILLISECOND from v_end-v_start),v_ret.lrn; + /*}dbg*/ + v_routing_key=v_ret.lrn; + end if; + end if; + end if; + end if; + + + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. search start. Routing key: %. Routing tags: %, Rate limit: %',EXTRACT(MILLISECOND from v_end-v_start), v_routing_key, v_ret.routing_tag_ids, v_destination_rate_limit; + /*}dbg*/ + v_network:=switch17.detect_network(v_ret.dst_prefix_routing); + v_ret.dst_network_id=v_network.network_id; + v_ret.dst_country_id=v_network.country_id; + + SELECT into v_destination d.*/*,switch.tracelog(d.*)*/ from class4.destinations d + WHERE + prefix_range(prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between d.dst_number_min_length and d.dst_number_max_length + AND rateplan_id=v_customer_auth_normalized.rateplan_id + AND enabled + AND valid_from <= v_now + AND valid_till >= v_now + AND yeti_ext.tag_compare(d.routing_tag_ids, v_call_tags, d.routing_tag_mode_id)>0 + ORDER BY length(prefix_range(prefix)) DESC, yeti_ext.tag_compare(d.routing_tag_ids, v_call_tags) desc + limit 1; + IF NOT FOUND THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. Destination not found',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=111; --Cant find destination prefix + RETURN NEXT v_ret; + RETURN; + END IF; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DST. found: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(v_destination, true); + /*}dbg*/ + + v_ret.destination_id:=v_destination.id; + v_ret.destination_prefix=v_destination.prefix; + v_ret.destination_initial_interval:=v_destination.initial_interval; + v_ret.destination_fee:=v_destination.connect_fee::varchar; + v_ret.destination_next_interval:=v_destination.next_interval; + v_ret.destination_rate_policy_id:=v_destination.rate_policy_id; + v_ret.destination_reverse_billing:=v_destination.reverse_billing; + IF v_destination.reject_calls THEN + v_ret.disconnect_code_id=112; --Rejected by destination + RETURN NEXT v_ret; + RETURN; + END IF; + + if v_destination.next_rate::float>v_destination_rate_limit then + v_ret.disconnect_code_id=8006; -- No destination with appropriate rate found + RETURN NEXT v_ret; + RETURN; + end if; + + select into v_rateplan * from class4.rateplans where id=v_customer_auth_normalized.rateplan_id; + if COALESCE(v_destination.profit_control_mode_id,v_rateplan.profit_control_mode_id)=2 then -- per call + v_rate_limit=v_destination.next_rate::float; + end if; + + + /* + FIND dialpeers logic. Queries must use prefix index for best performance + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. search start. Routing key: %. Rate limit: %. Routing tag: %',EXTRACT(MILLISECOND from v_end-v_start), v_routing_key, v_rate_limit, v_ret.routing_tag_ids; + /*}dbg*/ + CASE v_rp.sorting_id + WHEN'1' THEN -- LCR,Prio, ACD&ASR control + FOR routedata IN ( + WITH step1 AS( + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + t_dp.next_rate as dp_next_rate, + t_dp.lcr_rate_multiplier AS dp_lcr_rate_multiplier, + t_dp.priority AS dp_priority, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id = t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + from step1 + WHERE + r=1 + and exclusive_rank=1 + AND dp_next_rate<=v_rate_limit + AND dp_enabled + and not dp_locked --ACD&ASR control for DP + ORDER BY dp_next_rate*dp_lcr_rate_multiplier, dp_priority DESC + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + end LOOP; + WHEN '2' THEN --LCR, no prio, No ACD&ASR control + FOR routedata IN ( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + -- (t_vendor_gateway.*)::class4.gateways as s1_vendor_gateway, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + AND dp_enabled + and dp_next_rate<=v_rate_limit + ORDER BY dp_metric + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN '3' THEN --Prio, LCR, ACD&ASR control + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + and not dp_locked + ORDER BY dp_metric_priority DESC, dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'4' THEN -- LCRD, Prio, ACD&ACR control + FOR routedata IN ( + WITH step1 AS( + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + ((t_dp.next_rate - first_value(t_dp.next_rate) OVER(ORDER BY t_dp.next_rate ASC)) > v_rp.rate_delta_max)::INTEGER *(t_dp.next_rate + t_dp.priority) - t_dp.priority AS r2, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id = t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + from step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_next_rate <= v_rate_limit + and dp_enabled + and not dp_locked --ACD&ASR control for DP + ORDER BY r2 ASC + LIMIT v_rp.max_rerouting_attempts + ) LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + end LOOP; + WHEN'5' THEN -- Route test + FOR routedata IN ( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and dp_enabled + and dp_next_rate<=v_rate_limit + ORDER BY dp_metric_priority DESC, dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'6' THEN -- QD.Static,LCR,ACD&ACR control + v_random:=random(); + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY length(prefix_range(coalesce(rpsr.prefix,''))) desc + ) as r2, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.locked as dp_locked, + t_dp.enabled as dp_enabled, + t_dp.force_hit_rate as dp_force_hit_rate, + rpsr.priority as rpsr_priority, + rpsr.weight as rpsr_weight + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + left join class4.routing_plan_static_routes rpsr + ON rpsr.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and rpsr.vendor_id=t_dp.vendor_id + AND prefix_range(rpsr.prefix)@>prefix_range(v_routing_key) + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and r2=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + and not dp_locked + ORDER BY + coalesce(v_random<=dp_force_hit_rate,false) desc, + yeti_ext.rank_dns_srv(rpsr_weight) over ( partition by rpsr_priority order by rpsr_weight), + dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + WHEN'7' THEN -- QD.Static, No ACD&ACR control + v_random:=random(); + FOR routedata in( + WITH step1 AS( -- filtering + SELECT + (t_dp.*)::class4.dialpeers as s1_dialpeer, + (t_vendor_account.*)::billing.accounts as s1_vendor_account, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY + length(prefix_range(t_dp.prefix)) desc, + yeti_ext.tag_compare(t_dp.routing_tag_ids, v_call_tags, t_dp.routing_tag_mode_id) desc, + t_dp.exclusive_route desc -- in case when we have two identical prefixes with different exclusive flag value, we should lift up exclusive route, otherwise it will be filtered at WHERE r=1 and exclusive_rank=1 + ) as r, + rank() OVER ( + ORDER BY t_dp.exclusive_route desc -- force top rank for exclusive route + ) as exclusive_rank, + rank() OVER ( + PARTITION BY t_dp.vendor_id, t_dp.routeset_discriminator_id + ORDER BY length(prefix_range(coalesce(rpsr.prefix,''))) desc + ) as r2, + t_dp.priority as dp_metric_priority, + t_dp.next_rate*t_dp.lcr_rate_multiplier as dp_metric, + t_dp.next_rate as dp_next_rate, + t_dp.enabled as dp_enabled, + t_dp.force_hit_rate as dp_force_hit_rate, + rpsr.priority as rpsr_priority, + rpsr.weight as rpsr_weight + FROM class4.dialpeers t_dp + JOIN billing.accounts t_vendor_account ON t_dp.account_id=t_vendor_account.id + join public.contractors t_vendor on t_dp.vendor_id=t_vendor.id + JOIN class4.routing_plan_groups t_rpg ON t_dp.routing_group_id=t_rpg.routing_group_id + join class4.routing_plan_static_routes rpsr + ON rpsr.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and rpsr.vendor_id=t_dp.vendor_id + AND prefix_range(rpsr.prefix)@>prefix_range(v_routing_key) + WHERE + prefix_range(t_dp.prefix)@>prefix_range(v_routing_key) + AND length(v_routing_key) between t_dp.dst_number_min_length and t_dp.dst_number_max_length + AND t_rpg.routing_plan_id=v_customer_auth_normalized.routing_plan_id + and t_dp.valid_from<=v_now + and t_dp.valid_till>=v_now + AND t_vendor_account.balance 0 + ) + SELECT s1_dialpeer as s2_dialpeer, + s1_vendor_account as s2_vendor_account + FROM step1 + WHERE + r=1 + and exclusive_rank=1 + and r2=1 + and dp_next_rate<=v_rate_limit + and dp_enabled + ORDER BY + coalesce(v_random<=dp_force_hit_rate,false) desc, + yeti_ext.rank_dns_srv(rpsr_weight) over ( partition by rpsr_priority order by rpsr_weight), + dp_metric + LIMIT v_rp.max_rerouting_attempts + )LOOP + RETURN QUERY + /*rel{*/SELECT * from process_dp_release(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}rel*/ + /*dbg{*/SELECT * from process_dp_debug(v_ret,v_destination,routedata.s2_dialpeer,v_c_acc,v_orig_gw,routedata.s2_vendor_account,i_pop_id,v_customer_auth_normalized.send_billing_information,v_max_call_length);/*}dbg*/ + END LOOP; + + ELSE + RAISE NOTICE 'BUG: unknown sorting_id'; + END CASE; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> Dialpeer search done',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + v_ret.disconnect_code_id=113; --No routes + RETURN NEXT v_ret; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DONE.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN; + END; + $$; + + set search_path TO switch17; + SELECT * from switch17.preprocess_all(); + set search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; + + + } + + end +end diff --git a/db/structure.sql b/db/structure.sql index c23c787de..b41aca1d0 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -28572,7 +28572,7 @@ CREATE FUNCTION switch17.route(i_node_id integer, i_pop_id integer, i_protocol_i end if; if v_customer_auth_normalized.capacity is not null then - v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.id::varchar||':'||v_customer_auth_normalized.capacity::varchar||':1;'; + v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.customers_auth_id||':'||v_customer_auth_normalized.capacity::varchar||':1;'; end if; if v_orig_gw.origination_capacity is not null then v_ret.resources:=v_ret.resources||'4:'||v_orig_gw.id::varchar||':'||v_orig_gw.origination_capacity::varchar||':1;'; @@ -29651,7 +29651,7 @@ CREATE FUNCTION switch17.route_debug(i_node_id integer, i_pop_id integer, i_prot end if; if v_customer_auth_normalized.capacity is not null then - v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.id::varchar||':'||v_customer_auth_normalized.capacity::varchar||':1;'; + v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.customers_auth_id||':'||v_customer_auth_normalized.capacity::varchar||':1;'; end if; if v_orig_gw.origination_capacity is not null then v_ret.resources:=v_ret.resources||'4:'||v_orig_gw.id::varchar||':'||v_orig_gw.origination_capacity::varchar||':1;'; @@ -30702,7 +30702,7 @@ CREATE FUNCTION switch17.route_release(i_node_id integer, i_pop_id integer, i_pr end if; if v_customer_auth_normalized.capacity is not null then - v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.id::varchar||':'||v_customer_auth_normalized.capacity::varchar||':1;'; + v_ret.resources:=v_ret.resources||'3:'||v_customer_auth_normalized.customers_auth_id||':'||v_customer_auth_normalized.capacity::varchar||':1;'; end if; if v_orig_gw.origination_capacity is not null then v_ret.resources:=v_ret.resources||'4:'||v_orig_gw.id::varchar||':'||v_orig_gw.origination_capacity::varchar||':1;'; @@ -40236,8 +40236,7 @@ ALTER TABLE ONLY sys.sensors -- PostgreSQL database dump complete -- -SET search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import -; +SET search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; INSERT INTO "public"."schema_migrations" (version) VALUES ('20170822151410'), @@ -40286,6 +40285,7 @@ INSERT INTO "public"."schema_migrations" (version) VALUES ('20190318173242'), ('20190324161035'), ('20190326070548'), -('20190327134613'); +('20190327134613'), +('20190428191918'); From a4784f7bc5cbc7ca2d813d6b412ea9f927a9b8bf Mon Sep 17 00:00:00 2001 From: Dmitry Sinina Date: Mon, 29 Apr 2019 00:36:50 +0300 Subject: [PATCH 2/2] Nokogiri gem upgrade, CVE-2019-11068 --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 48511a3ab..b861bf0d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -369,7 +369,7 @@ GEM net_tcp_client (2.0.1) netstring (0.0.3) nio4r (2.3.1) - nokogiri (1.10.1) + nokogiri (1.10.3) mini_portile2 (~> 2.4.0) oj (2.18.5) orm_adapter (0.5.0)