From d75ed2261662f1e0f6e5c9d880a202b2e5b8f519 Mon Sep 17 00:00:00 2001 From: Dmitry Sinina Date: Sat, 24 Aug 2024 14:49:20 +0300 Subject: [PATCH] improve headers array input for orig_append_headers_reply (#1534) * improve headers array input for orig_append_headers_reply, term_append_headers_req, orig_append_headers_req * upgrade rexml * gw api resource remove filters by append headers --- Gemfile.lock | 2 +- app/admin/equipment/gateways.rb | 18 +- app/models/gateway.rb | 18 +- .../api/rest/admin/gateway_resource.rb | 9 +- config/locales/en.yml | 1 + db/migrate/20240824084143_headers_arrays.rb | 3135 +++++++++++++++++ db/structure.sql | 33 +- .../inputs/newline_array_of_headers_input.rb | 34 + .../rest/admin/gateways_controller_spec.rb | 2 - spec/factories/gateways.rb | 11 +- spec/models/gateway_spec.rb | 6 +- spec/requests/api/rest/admin/gateways_spec.rb | 2 + 12 files changed, 3232 insertions(+), 39 deletions(-) create mode 100644 db/migrate/20240824084143_headers_arrays.rb create mode 100644 lib/active_admin/inputs/newline_array_of_headers_input.rb diff --git a/Gemfile.lock b/Gemfile.lock index b12e8b513..ec850ef4b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -715,7 +715,7 @@ GEM responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) - rexml (3.3.4) + rexml (3.3.6) strscan rspec (3.10.0) rspec-core (~> 3.10.0) diff --git a/app/admin/equipment/gateways.rb b/app/admin/equipment/gateways.rb index 8230184e5..6cbcd9801 100644 --- a/app/admin/equipment/gateways.rb +++ b/app/admin/equipment/gateways.rb @@ -397,8 +397,8 @@ def resource_params f.inputs 'Origination' do f.input :orig_next_hop - f.input :orig_append_headers_req - f.input :orig_append_headers_reply, as: :array_of_strings + f.input :orig_append_headers_req, as: :newline_array_of_headers + f.input :orig_append_headers_reply, as: :newline_array_of_headers f.input :orig_use_outbound_proxy f.input :orig_force_outbound_proxy f.input :orig_proxy_transport_protocol, as: :select, include_blank: false @@ -433,7 +433,7 @@ def resource_params f.input :term_next_hop_for_replies f.input :term_next_hop f.input :term_disconnect_policy, input_html: { class: 'chosen' }, include_blank: true - f.input :term_append_headers_req + f.input :term_append_headers_req, as: :newline_array_of_headers f.input :sdp_alines_filter_type, as: :select, include_blank: false f.input :sdp_alines_filter_list f.input :ringing_timeout @@ -589,8 +589,12 @@ def resource_params panel 'Origination' do attributes_table_for s do row :orig_next_hop - row :orig_append_headers_req - row :orig_append_headers_reply + row :orig_append_headers_req do |row| + pre row.orig_append_headers_req.join("\r\n") + end + row :orig_append_headers_reply do |row| + pre row.orig_append_headers_reply.join("\r\n") + end row :orig_use_outbound_proxy row :orig_force_outbound_proxy row :orig_proxy_transport_protocol @@ -629,7 +633,9 @@ def resource_params row :term_next_hop_for_replies row :term_next_hop row :term_disconnect_policy - row :term_append_headers_req + row :term_append_headers_req do |row| + pre row.term_append_headers_req.join("\r\n") + end row :sdp_alines_filter_type row :sdp_alines_filter_list row :ringing_timeout diff --git a/app/models/gateway.rb b/app/models/gateway.rb index 361a70eeb..758bbbfe0 100644 --- a/app/models/gateway.rb +++ b/app/models/gateway.rb @@ -39,8 +39,8 @@ # max_30x_redirects :integer(2) default(0), not null # max_transfers :integer(2) default(0), not null # name :string not null -# orig_append_headers_reply :string is an Array -# orig_append_headers_req :string +# orig_append_headers_reply :string default([]), not null, is an Array +# orig_append_headers_req :string default([]), not null, is an Array # orig_force_outbound_proxy :boolean default(FALSE), not null # orig_next_hop :string # orig_outbound_proxy :string @@ -82,7 +82,7 @@ # sst_session_expires :integer(4) default(50) # suppress_early_media :boolean default(FALSE), not null # symmetric_rtp_nonstop :boolean default(FALSE), not null -# term_append_headers_req :string +# term_append_headers_req :string default([]), not null, is an Array # term_force_outbound_proxy :boolean default(FALSE), not null # term_next_hop :string # term_next_hop_for_replies :boolean default(FALSE), not null @@ -394,10 +394,20 @@ def rtp_acl=(value) end def orig_append_headers_reply=(value) - value = value.split(',').map(&:strip).reject(&:blank?) if value.is_a? String + value = value.split("\r\n").map(&:strip).reject(&:blank?) if value.is_a? String self[:orig_append_headers_reply] = value end + def orig_append_headers_req=(value) + value = value.split("\r\n").map(&:strip).reject(&:blank?) if value.is_a? String + self[:orig_append_headers_req] = value + end + + def term_append_headers_req=(value) + value = value.split("\r\n").map(&:strip).reject(&:blank?) if value.is_a? String + self[:term_append_headers_req] = value + end + def host=(value) self[:host] = self.class.normalize_host(value) end diff --git a/app/resources/api/rest/admin/gateway_resource.rb b/app/resources/api/rest/admin/gateway_resource.rb index 81eece93c..dc628da27 100644 --- a/app/resources/api/rest/admin/gateway_resource.rb +++ b/app/resources/api/rest/admin/gateway_resource.rb @@ -8,6 +8,7 @@ class Api::Rest::Admin::GatewayResource < ::BaseResource :dst_rewrite_rule, :dst_rewrite_result, :auth_enabled, :auth_user, :auth_password, :auth_from_user, :auth_from_domain, :term_use_outbound_proxy, :term_force_outbound_proxy, :term_outbound_proxy, :term_next_hop_for_replies, :term_next_hop, :term_append_headers_req, + :orig_append_headers_req, :orig_append_headers_reply, :sdp_alines_filter_list, :ringing_timeout, :relay_options, :relay_reinvite, :relay_hold, :relay_prack, :relay_update, :suppress_early_media, :fake_180_timer, :transit_headers_from_origination, :transit_headers_from_termination, :sip_interface_name, :allow_1xx_without_to_tag, :sip_timer_b, @@ -97,8 +98,10 @@ class Api::Rest::Admin::GatewayResource < ::BaseResource ransack_filter :termination_capacity, type: :number ransack_filter :term_next_hop, type: :string ransack_filter :orig_next_hop, type: :string - ransack_filter :orig_append_headers_req, type: :string - ransack_filter :term_append_headers_req, type: :string + # Disabled because there is no support for arrays in ransack_filter + # ransack_filter :orig_append_headers_req, type: :array_of_strings + # ransack_filter :orig_append_headers_reply, type: :array_of_strings + # ransack_filter :term_append_headers_req, type: :array_of_strings ransack_filter :dialog_nat_handling, type: :boolean ransack_filter :orig_force_outbound_proxy, type: :boolean ransack_filter :orig_use_outbound_proxy, type: :boolean @@ -207,6 +210,8 @@ def self.updatable_fields(_context) term_next_hop term_disconnect_policy term_append_headers_req + orig_append_headers_req + orig_append_headers_reply sdp_alines_filter_list ringing_timeout relay_options diff --git a/config/locales/en.yml b/config/locales/en.yml index 0a40bbdeb..c0e01e0f0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -31,6 +31,7 @@ en: hint_array_of_strings: "Comma-separated array of strings" + hint_newline_array_of_headers: "Newline separated array of Header: Value elements" date: formats: long: "%Y-%m-%d" diff --git a/db/migrate/20240824084143_headers_arrays.rb b/db/migrate/20240824084143_headers_arrays.rb new file mode 100644 index 000000000..4439dd4df --- /dev/null +++ b/db/migrate/20240824084143_headers_arrays.rb @@ -0,0 +1,3135 @@ +class HeadersArrays < ActiveRecord::Migration[7.0] + def up + execute %q{ + alter table class4.gateways + alter column orig_append_headers_req type varchar[] using string_to_array(orig_append_headers_req, '\r\n'), + alter column term_append_headers_req type varchar[] using string_to_array(orig_append_headers_req, '\r\n'); + + alter table class4.gateways + alter column orig_append_headers_req set default '{}'::varchar[], + alter column orig_append_headers_req set not null, + alter column orig_append_headers_reply set default '{}'::varchar[], + alter column orig_append_headers_reply set not null, + alter column term_append_headers_req set default '{}'::varchar[], + alter column term_append_headers_req set not null; + +CREATE or replace FUNCTION switch20.process_gw(i_profile switch20.callprofile_ty, i_destination class4.destinations, i_dp class4.dialpeers, i_customer_acc billing.accounts, i_customer_gw class4.gateways, i_vendor_acc billing.accounts, i_vendor_gw class4.gateways, i_send_billing_information boolean, i_max_call_length integer, i_diversion character varying[], i_privacy character varying[], i_pai character varying[], i_ppi character varying) RETURNS switch20.callprofile_ty + LANGUAGE plpgsql STABLE SECURITY DEFINER COST 100000 + AS $_$ +DECLARE + i integer; + v_vendor_allowtime real; + v_route_found boolean:=false; + v_from_user varchar; + v_from_domain varchar; + v_schema varchar; + v_termination_numberlist class4.numberlists%rowtype; + v_termination_numberlist_item class4.numberlist_items%rowtype; + v_termination_numberlist_size integer; + v_aleg_append_headers_reply varchar[] not null default ARRAY[]::varchar[]; + v_bleg_append_headers_req varchar[] not null default ARRAY[]::varchar[]; + v_diversion varchar[] not null default ARRAY[]::varchar[]; + v_diversion_header varchar; + v_diversion_out varchar[] not null default ARRAY[]::varchar[]; + v_pai_out varchar[] not null default ARRAY[]::varchar[]; + v_pai varchar; + v_allow_pai boolean:=true; + v_to_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_from_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_host varchar; + v_ruri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_user_params varchar[] not null default ARRAY[]::varchar[]; + v_to_username varchar; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ +BEGIN + /*dbg{*/ + v_start:=now(); + --RAISE NOTICE 'process_dp in: %',i_profile; + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Found dialpeer: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_dp,true); + /*}dbg*/ + + --RAISE NOTICE 'process_dp dst: %',i_destination; + + i_profile.destination_id:=i_destination.id; + i_profile.destination_fee:=i_destination.connect_fee::varchar; + i_profile.destination_rate_policy_id:=i_destination.rate_policy_id; + + --vendor account capacity limit; + i_profile.legb_res= ''; + if i_vendor_acc.termination_capacity is not null then + i_profile.legb_res = '2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + end if; + + if i_vendor_acc.total_capacity is not null then + i_profile.legb_res = i_profile.legb_res||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + end if; + + -- dialpeer account capacity limit; + if i_dp.capacity is not null then + i_profile.legb_res = i_profile.legb_res||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + end if; + + /* */ + i_profile.dialpeer_id=i_dp.id; + i_profile.dialpeer_prefix=i_dp.prefix; + i_profile.dialpeer_next_rate=i_dp.next_rate::varchar; + i_profile.dialpeer_initial_rate=i_dp.initial_rate::varchar; + i_profile.dialpeer_initial_interval=i_dp.initial_interval; + i_profile.dialpeer_next_interval=i_dp.next_interval; + i_profile.dialpeer_fee=i_dp.connect_fee::varchar; + i_profile.dialpeer_reverse_billing=i_dp.reverse_billing; + i_profile.vendor_id=i_dp.vendor_id; + i_profile.vendor_acc_id=i_dp.account_id; + i_profile.term_gw_id=i_vendor_gw.id; + + i_profile.orig_gw_name=i_customer_gw."name"; + i_profile.orig_gw_external_id=i_customer_gw.external_id; + + i_profile.term_gw_name=i_vendor_gw."name"; + i_profile.term_gw_external_id=i_vendor_gw.external_id; + + i_profile.customer_account_name=i_customer_acc."name"; + + i_profile.routing_group_id:=i_dp.routing_group_id; + + if i_send_billing_information then + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-INT:'||i_profile.dialpeer_initial_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-INT:'||i_profile.dialpeer_next_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-RATE:'||i_profile.dialpeer_initial_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-RATE:'||i_profile.dialpeer_next_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-CF:'||i_profile.dialpeer_fee)::varchar); + end if; + v_aleg_append_headers_reply = array_cat(v_aleg_append_headers_reply,i_customer_gw.orig_append_headers_reply); + i_profile.aleg_append_headers_reply=ARRAY_TO_STRING(v_aleg_append_headers_reply,'\r\n'); + + if i_destination.use_dp_intervals THEN + i_profile.destination_initial_interval:=i_dp.initial_interval; + i_profile.destination_next_interval:=i_dp.next_interval; + ELSE + i_profile.destination_initial_interval:=i_destination.initial_interval; + i_profile.destination_next_interval:=i_destination.next_interval; + end if; + + CASE i_profile.destination_rate_policy_id + WHEN 1 THEN -- fixed + i_profile.destination_next_rate:=i_destination.next_rate::varchar; + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + WHEN 2 THEN -- based on dialpeer + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + WHEN 3 THEN -- min + IF i_dp.next_rate >= i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; -- FIXED least + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + WHEN 4 THEN -- max + IF i_dp.next_rate < i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; --FIXED + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + ELSE + -- + end case; + + + + /* time limiting START */ + --SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth.account_id; + --SELECT INTO STRICT v_v_acc * FROM billing.accounts WHERE id=v_dialpeer.account_id; + + + if i_profile.time_limit is null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit is not set, calculating',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + IF (i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval<0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: No enough customer balance even for first billing interval. rejecting',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + i_profile.disconnect_code_id=8000; --Not enough customer balance + RETURN i_profile; + ELSIF i_destination.next_rate!=0 AND i_destination.next_interval!=0 THEN + i_profile.time_limit = (i_destination.initial_interval+ + LEAST(FLOOR(((i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval)/ + (i_destination.next_rate/60*i_destination.next_interval)),24e6)::integer*i_destination.next_interval)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + ELSE /* DST rates is 0, allowing maximum call length */ + i_profile.time_limit = COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: DST rate is 0. customer time limit set to max value: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + end IF; + end if; + + IF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee <0 THEN /* No enough balance, skipping this profile */ + v_vendor_allowtime:=0; + return null; + ELSIF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval<0 THEN /* No enough balance even for first billing interval - skipping this profile */ + return null; + ELSIF i_dp.next_rate!=0 AND i_dp.next_interval!=0 THEN /* DP rates is not zero, calculating limit */ + v_vendor_allowtime:=i_dp.initial_interval+ + LEAST(FLOOR(((i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval)/ + (i_dp.next_rate/60*i_dp.next_interval)),24e6)::integer*i_dp.next_interval; + ELSE /* DP rates is 0, allowing maximum call length */ + v_vendor_allowtime:=COALESCE(i_vendor_acc.max_call_duration, i_max_call_length); + end IF; + + i_profile.time_limit=LEAST( + COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer, + COALESCE(i_vendor_acc.max_call_duration, i_max_call_length)::integer, + v_vendor_allowtime, + i_profile.time_limit + )::integer; + + + /* number rewriting _After_ routing */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_dp.dst_rewrite_rule,i_dp.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_dp.src_rewrite_rule,i_dp.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_dp.src_name_rewrite_rule,i_dp.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + /* + get termination gw data + */ + --SELECT into v_dst_gw * from class4.gateways WHERE id=v_dialpeer.gateway_id; + --SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth.gateway_id; + --vendor gw + if i_vendor_gw.termination_capacity is not null then + i_profile.legb_res:=i_profile.legb_res||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + i_profile.resources:=i_profile.resources||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + end if; + + + /* + numberlist processing _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before numberlist processing src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + ----- DST Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.dst_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_dst_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + ni.key=i_profile.dst_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.dst_prefix_out) and + length(i_profile.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_dst_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + ----- SRC Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.src_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_src_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + ni.key=i_profile.src_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.src_prefix_out) and + length(i_profile.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_src_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + /* + number rewriting _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_vendor_gw.dst_rewrite_rule,i_vendor_gw.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_vendor_gw.src_rewrite_rule,i_vendor_gw.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_vendor_gw.src_name_rewrite_rule,i_vendor_gw.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + IF cardinality(i_diversion) > 0 AND i_vendor_gw.diversion_send_mode_id > 1 THEN + v_diversion = yeti_ext.regexp_replace_rand(i_diversion, i_vendor_gw.diversion_rewrite_rule, i_vendor_gw.diversion_rewrite_result); + + IF i_vendor_gw.diversion_send_mode_id = 2 AND i_vendor_gw.diversion_domain is not null AND i_vendor_gw.diversion_domain!='' THEN + /* Diversion as SIP URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req = array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + END LOOP; + ELSIF i_vendor_gw.diversion_send_mode_id = 3 THEN + /* Diversion as TEL URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req=array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header)::varchar + ); + END LOOP; + END IF; + + /* Field for CDR */ + i_profile.diversion_out = array_to_string(v_diversion_out, ','); + END IF; + + CASE i_vendor_gw.privacy_mode_id + WHEN 0 THEN + -- do nothing + WHEN 1 THEN + IF cardinality(array_remove(i_privacy,'none')) > 0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 2 THEN + IF 'critical' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 3 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. Applying privacy.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) OR 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + END IF; + IF 'id' = ANY(i_privacy) OR 'header' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. removing PAI/PPI headers.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + v_allow_pai = false; + END IF; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + WHEN 4 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF cardinality(i_privacy)>0 THEN + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + WHEN 5 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding with anonymous From.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) or 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + END CASE; + + IF v_allow_pai THEN + -- only if privacy mode allows to send PAI + IF i_vendor_gw.pai_send_mode_id = 1 THEN + -- TEL URI + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 2 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + -- SIP URL + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 3 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 4 THEN + -- relay + FOREACH v_pai IN ARRAY i_pai LOOP + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: %s', v_pai)::varchar); + END LOOP; + v_pai_out = i_pai; + IF i_ppi is not null and i_ppi!='' THEN + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Preferred-Identity: %s', i_ppi)::varchar); + i_profile.ppi_out = i_ppi; + END IF; + END IF; + i_profile.pai_out = NULLIF(array_to_string(v_pai_out, ','),''); + END IF; + + IF i_vendor_gw.stir_shaken_mode_id = 1 AND COALESCE(i_profile.ss_attest_id,0) > 0 THEN + -- insert signature + i_profile.ss_crt_id = i_vendor_gw.stir_shaken_crt_id; + i_profile.ss_otn = i_profile.src_prefix_routing; + i_profile.ss_dtn = i_profile.dst_prefix_routing; + i_profile.legb_ss_status_id = i_profile.ss_attest_id; + END IF; + + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); + i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); + + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); + + i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled + i_profile.next_hop:=i_vendor_gw.term_next_hop; + i_profile.aleg_next_hop:=i_customer_gw.orig_next_hop; + -- i_profile.next_hop_for_replies:=v_dst_gw.term_next_hop_for_replies; + + i_profile.dlg_nat_handling=i_customer_gw.dialog_nat_handling; + + i_profile.call_id:=''; -- Generation by sems + + i_profile.enable_auth:=i_vendor_gw.auth_enabled; + i_profile.auth_pwd:=i_vendor_gw.auth_password; + i_profile.auth_user:=i_vendor_gw.auth_user; + i_profile.enable_aleg_auth:=false; + i_profile.auth_aleg_pwd:=''; + i_profile.auth_aleg_user:=''; + + if i_profile.enable_auth then + v_from_user=COALESCE(i_vendor_gw.auth_from_user,i_profile.src_prefix_out,''); + -- may be it already defined by privacy logic + v_from_domain=COALESCE(v_from_domain, i_vendor_gw.auth_from_domain, '$Oi'); + else + v_from_user=COALESCE(i_profile.src_prefix_out,''); + if i_vendor_gw.preserve_anonymous_from_domain and i_profile.from_domain='anonymous.invalid' then + v_from_domain='anonymous.invalid'; + else + v_from_domain=COALESCE(v_from_domain, '$Oi'); + end if; + end if; + + v_to_username = yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out, i_vendor_gw.to_rewrite_rule, i_vendor_gw.to_rewrite_result); + + if i_vendor_gw.sip_schema_id = 1 then + v_schema='sip'; + elsif i_vendor_gw.sip_schema_id = 2 then + v_schema='sips'; + elsif i_vendor_gw.sip_schema_id = 3 then + v_schema='sip'; + -- user=phone param require e.164 with + in username, but we are not forcing it + v_from_uri_params = array_append(v_from_uri_params,'user=phone'); + v_to_uri_params = array_append(v_to_uri_params,'user=phone'); + v_ruri_params = array_append(v_ruri_params,'user=phone'); + else + RAISE exception 'Unknown termination gateway % SIP schema %', i_vendor_gw.id, i_vendor_gw.sip_schema_id; + end if; + + if i_vendor_gw.send_lnp_information and i_profile.lrn is not null then + if i_profile.lrn=i_profile.dst_prefix_routing then -- number not ported, but request was successf we musr add ;npdi=yes; + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + i_profile.lrn=nullif(i_profile.dst_prefix_routing,i_profile.lrn); -- clear lnr field if number not ported; + else -- if number ported + v_ruri_user_params = array_append(v_ruri_user_params, 'rn='||i_profile.lrn); + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + end if; + end if; + + i_profile.registered_aor_mode_id = i_vendor_gw.registered_aor_mode_id; + if i_vendor_gw.registered_aor_mode_id > 0 then + i_profile.registered_aor_id=i_vendor_gw.id; + v_ruri_host = 'unknown.invalid'; + else + v_ruri_host = i_vendor_gw.host; + end if; + + i_profile."from" = switch20.build_uri(false, v_schema, i_profile.src_name_out, v_from_user, null, v_from_domain, null, v_from_uri_params); + + i_profile."to" = switch20.build_uri(false, v_schema, null, v_to_username, null, v_ruri_host, i_vendor_gw.port, v_to_uri_params); + i_profile.ruri = switch20.build_uri(true, v_schema, null, i_profile.dst_prefix_out, v_ruri_user_params, v_ruri_host, i_vendor_gw.port, v_ruri_params); + + i_profile.bleg_transport_protocol_id:=i_vendor_gw.transport_protocol_id; + i_profile.bleg_protocol_priority_id:=i_vendor_gw.network_protocol_priority_id; + + i_profile.aleg_media_encryption_mode_id:=i_customer_gw.media_encryption_mode_id; + i_profile.bleg_media_encryption_mode_id:=i_vendor_gw.media_encryption_mode_id; + + IF (i_vendor_gw.term_use_outbound_proxy ) THEN + i_profile.outbound_proxy:=v_schema||':'||i_vendor_gw.term_outbound_proxy; + i_profile.force_outbound_proxy:=i_vendor_gw.term_force_outbound_proxy; + i_profile.bleg_outbound_proxy_transport_protocol_id:=i_vendor_gw.term_proxy_transport_protocol_id; + ELSE + i_profile.outbound_proxy:=NULL; + i_profile.force_outbound_proxy:=false; + END IF; + + IF (i_customer_gw.orig_use_outbound_proxy ) THEN + i_profile.aleg_force_outbound_proxy:=i_customer_gw.orig_force_outbound_proxy; + i_profile.aleg_outbound_proxy=v_schema||':'||i_customer_gw.orig_outbound_proxy; + i_profile.aleg_outbound_proxy_transport_protocol_id:=i_customer_gw.orig_proxy_transport_protocol_id; + else + i_profile.aleg_force_outbound_proxy:=FALSE; + i_profile.aleg_outbound_proxy=NULL; + end if; + + i_profile.aleg_policy_id=i_customer_gw.orig_disconnect_policy_id; + i_profile.bleg_policy_id=i_vendor_gw.term_disconnect_policy_id; + + i_profile.transit_headers_a2b:=i_customer_gw.transit_headers_from_origination||';'||i_vendor_gw.transit_headers_from_origination; + i_profile.transit_headers_b2a:=i_vendor_gw.transit_headers_from_termination||';'||i_customer_gw.transit_headers_from_termination; + + i_profile.sdp_filter_type_id:=0; + i_profile.sdp_filter_list:=''; + + i_profile.sdp_alines_filter_type_id:=i_vendor_gw.sdp_alines_filter_type_id; + i_profile.sdp_alines_filter_list:=i_vendor_gw.sdp_alines_filter_list; + + i_profile.enable_session_timer=i_vendor_gw.sst_enabled; + i_profile.session_expires =i_vendor_gw.sst_session_expires; + i_profile.minimum_timer:=i_vendor_gw.sst_minimum_timer; + i_profile.maximum_timer:=i_vendor_gw.sst_maximum_timer; + i_profile.session_refresh_method_id:=i_vendor_gw.session_refresh_method_id; + i_profile.accept_501_reply:=i_vendor_gw.sst_accept501; + + i_profile.enable_aleg_session_timer=i_customer_gw.sst_enabled; + i_profile.aleg_session_expires:=i_customer_gw.sst_session_expires; + i_profile.aleg_minimum_timer:=i_customer_gw.sst_minimum_timer; + i_profile.aleg_maximum_timer:=i_customer_gw.sst_maximum_timer; + i_profile.aleg_session_refresh_method_id:=i_customer_gw.session_refresh_method_id; + i_profile.aleg_accept_501_reply:=i_customer_gw.sst_accept501; + + i_profile.reply_translations:=''; + i_profile.disconnect_code_id:=NULL; + i_profile.enable_rtprelay:=i_vendor_gw.proxy_media OR i_customer_gw.proxy_media; + + i_profile.rtprelay_interface:=i_vendor_gw.rtp_interface_name; + i_profile.aleg_rtprelay_interface:=i_customer_gw.rtp_interface_name; + + i_profile.outbound_interface:=i_vendor_gw.sip_interface_name; + i_profile.aleg_outbound_interface:=i_customer_gw.sip_interface_name; + + i_profile.bleg_force_symmetric_rtp:=i_vendor_gw.force_symmetric_rtp; + i_profile.bleg_symmetric_rtp_nonstop=i_vendor_gw.symmetric_rtp_nonstop; + + i_profile.aleg_force_symmetric_rtp:=i_customer_gw.force_symmetric_rtp; + i_profile.aleg_symmetric_rtp_nonstop=i_customer_gw.symmetric_rtp_nonstop; + + i_profile.bleg_rtp_ping=i_vendor_gw.rtp_ping; + i_profile.aleg_rtp_ping=i_customer_gw.rtp_ping; + + i_profile.bleg_relay_options = i_vendor_gw.relay_options; + i_profile.aleg_relay_options = i_customer_gw.relay_options; + + + i_profile.filter_noaudio_streams = i_vendor_gw.filter_noaudio_streams OR i_customer_gw.filter_noaudio_streams; + i_profile.force_one_way_early_media = i_vendor_gw.force_one_way_early_media OR i_customer_gw.force_one_way_early_media; + i_profile.aleg_relay_reinvite = i_vendor_gw.relay_reinvite; + i_profile.bleg_relay_reinvite = i_customer_gw.relay_reinvite; + + i_profile.aleg_relay_hold = i_vendor_gw.relay_hold; + i_profile.bleg_relay_hold = i_customer_gw.relay_hold; + + i_profile.aleg_relay_prack = i_vendor_gw.relay_prack; + i_profile.bleg_relay_prack = i_customer_gw.relay_prack; + i_profile.aleg_rel100_mode_id = i_customer_gw.rel100_mode_id; + i_profile.bleg_rel100_mode_id = i_vendor_gw.rel100_mode_id; + + i_profile.rtp_relay_timestamp_aligning=i_vendor_gw.rtp_relay_timestamp_aligning OR i_customer_gw.rtp_relay_timestamp_aligning; + i_profile.allow_1xx_wo2tag=i_vendor_gw.allow_1xx_without_to_tag OR i_customer_gw.allow_1xx_without_to_tag; + + i_profile.aleg_sdp_c_location_id=i_customer_gw.sdp_c_location_id; + i_profile.bleg_sdp_c_location_id=i_vendor_gw.sdp_c_location_id; + i_profile.trusted_hdrs_gw=false; + + + + i_profile.aleg_codecs_group_id:=i_customer_gw.codec_group_id; + i_profile.bleg_codecs_group_id:=i_vendor_gw.codec_group_id; + i_profile.aleg_single_codec_in_200ok:=i_customer_gw.single_codec_in_200ok; + i_profile.bleg_single_codec_in_200ok:=i_vendor_gw.single_codec_in_200ok; + i_profile.try_avoid_transcoding = i_customer_gw.try_avoid_transcoding; + i_profile.ringing_timeout=i_vendor_gw.ringing_timeout; + i_profile.dead_rtp_time=GREATEST(i_vendor_gw.rtp_timeout,i_customer_gw.rtp_timeout); + i_profile.invite_timeout=i_vendor_gw.sip_timer_b; + i_profile.srv_failover_timeout=i_vendor_gw.dns_srv_failover_timer; + i_profile.fake_180_timer=i_vendor_gw.fake_180_timer; + i_profile.rtp_force_relay_cn=i_vendor_gw.rtp_force_relay_cn OR i_customer_gw.rtp_force_relay_cn; + i_profile.patch_ruri_next_hop=i_vendor_gw.resolve_ruri; + + i_profile.aleg_sensor_id=i_customer_gw.sensor_id; + i_profile.aleg_sensor_level_id=i_customer_gw.sensor_level_id; + i_profile.bleg_sensor_id=i_vendor_gw.sensor_id; + i_profile.bleg_sensor_level_id=i_vendor_gw.sensor_level_id; + + i_profile.aleg_dtmf_send_mode_id=i_customer_gw.dtmf_send_mode_id; + i_profile.aleg_dtmf_recv_modes=i_customer_gw.dtmf_receive_mode_id; + i_profile.bleg_dtmf_send_mode_id=i_vendor_gw.dtmf_send_mode_id; + i_profile.bleg_dtmf_recv_modes=i_vendor_gw.dtmf_receive_mode_id; + + + i_profile.aleg_rtp_filter_inband_dtmf=false; + i_profile.bleg_rtp_filter_inband_dtmf=false; + + if i_customer_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + elsif i_customer_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_vendor_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.aleg_rtp_filter_inband_dtmf=false; + elsif i_vendor_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + + if i_vendor_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + elsif i_vendor_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_customer_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.bleg_rtp_filter_inband_dtmf=false; + elsif i_customer_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + i_profile.aleg_rtp_acl = i_customer_gw.rtp_acl; + i_profile.bleg_rtp_acl = i_vendor_gw.rtp_acl; + + i_profile.rtprelay_force_dtmf_relay=i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_detection=NOT i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_filtering=NOT i_vendor_gw.force_dtmf_relay; + i_profile.bleg_max_30x_redirects = i_vendor_gw.max_30x_redirects; + i_profile.bleg_max_transfers = i_vendor_gw.max_transfers; + + + i_profile.aleg_relay_update=i_customer_gw.relay_update; + i_profile.bleg_relay_update=i_vendor_gw.relay_update; + i_profile.suppress_early_media=i_customer_gw.suppress_early_media OR i_vendor_gw.suppress_early_media; + + i_profile.bleg_radius_acc_profile_id=i_vendor_gw.radius_accounting_profile_id; + i_profile.bleg_force_cancel_routeset=i_vendor_gw.force_cancel_routeset; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Finished: % ',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_profile,true); + /*}dbg*/ + RETURN i_profile; +END; +$_$; + +set search_path TO switch20; +SELECT * from switch20.preprocess_all(); +set search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; + + +CREATE or replace FUNCTION switch21.process_gw(i_profile switch21.callprofile_ty, i_destination class4.destinations, i_dp class4.dialpeers, i_customer_acc billing.accounts, i_customer_gw class4.gateways, i_vendor_acc billing.accounts, i_vendor_gw class4.gateways, i_send_billing_information boolean, i_max_call_length integer, i_diversion character varying[], i_privacy character varying[], i_pai character varying[], i_ppi character varying) RETURNS switch21.callprofile_ty + LANGUAGE plpgsql STABLE SECURITY DEFINER COST 100000 + AS $_$ +DECLARE + i integer; + v_vendor_allowtime real; + v_route_found boolean:=false; + v_from_user varchar; + v_from_domain varchar; + v_schema varchar; + v_termination_numberlist class4.numberlists%rowtype; + v_termination_numberlist_item class4.numberlist_items%rowtype; + v_termination_numberlist_size integer; + v_aleg_append_headers_reply varchar[] not null default ARRAY[]::varchar[]; + v_bleg_append_headers_req varchar[] not null default ARRAY[]::varchar[]; + v_diversion varchar[] not null default ARRAY[]::varchar[]; + v_diversion_header varchar; + v_diversion_out varchar[] not null default ARRAY[]::varchar[]; + v_pai_out varchar[] not null default ARRAY[]::varchar[]; + v_pai varchar; + v_allow_pai boolean:=true; + v_to_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_from_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_host varchar; + v_ruri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_user_params varchar[] not null default ARRAY[]::varchar[]; + v_to_username varchar; + v_customer_transit_headers_from_origination varchar[] default ARRAY[]::varchar[]; + v_vendor_transit_headers_from_origination varchar[] default ARRAY[]::varchar[]; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ +BEGIN + /*dbg{*/ + v_start:=now(); + --RAISE NOTICE 'process_dp in: %',i_profile; + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Found dialpeer: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_dp,true); + /*}dbg*/ + + --RAISE NOTICE 'process_dp dst: %',i_destination; + + i_profile.destination_id:=i_destination.id; + i_profile.destination_fee:=i_destination.connect_fee::varchar; + i_profile.destination_rate_policy_id:=i_destination.rate_policy_id; + + --vendor account capacity limit; + i_profile.legb_res= ''; + if i_vendor_acc.termination_capacity is not null then + i_profile.legb_res = '2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + end if; + + if i_vendor_acc.total_capacity is not null then + i_profile.legb_res = i_profile.legb_res||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + end if; + + -- dialpeer account capacity limit; + if i_dp.capacity is not null then + i_profile.legb_res = i_profile.legb_res||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + end if; + + /* */ + i_profile.dialpeer_id=i_dp.id; + i_profile.dialpeer_prefix=i_dp.prefix; + i_profile.dialpeer_next_rate=i_dp.next_rate::varchar; + i_profile.dialpeer_initial_rate=i_dp.initial_rate::varchar; + i_profile.dialpeer_initial_interval=i_dp.initial_interval; + i_profile.dialpeer_next_interval=i_dp.next_interval; + i_profile.dialpeer_fee=i_dp.connect_fee::varchar; + i_profile.dialpeer_reverse_billing=i_dp.reverse_billing; + i_profile.vendor_id=i_dp.vendor_id; + i_profile.vendor_acc_id=i_dp.account_id; + i_profile.term_gw_id=i_vendor_gw.id; + + i_profile.orig_gw_name=i_customer_gw."name"; + i_profile.orig_gw_external_id=i_customer_gw.external_id; + + i_profile.term_gw_name=i_vendor_gw."name"; + i_profile.term_gw_external_id=i_vendor_gw.external_id; + + i_profile.customer_account_name=i_customer_acc."name"; + + i_profile.routing_group_id:=i_dp.routing_group_id; + + -- TODO. store arrays in GW and not convert it there + v_customer_transit_headers_from_origination = string_to_array(COALESCE(i_customer_gw.transit_headers_from_origination,''),','); + v_vendor_transit_headers_from_origination = string_to_array(COALESCE(i_vendor_gw.transit_headers_from_origination,''),','); + + if i_send_billing_information then + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-INT:'||i_profile.dialpeer_initial_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-INT:'||i_profile.dialpeer_next_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-RATE:'||i_profile.dialpeer_initial_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-RATE:'||i_profile.dialpeer_next_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-CF:'||i_profile.dialpeer_fee)::varchar); + end if; + v_aleg_append_headers_reply = array_cat(v_aleg_append_headers_reply,i_customer_gw.orig_append_headers_reply); + i_profile.aleg_append_headers_reply=ARRAY_TO_STRING(v_aleg_append_headers_reply,'\r\n'); + + if i_destination.use_dp_intervals THEN + i_profile.destination_initial_interval:=i_dp.initial_interval; + i_profile.destination_next_interval:=i_dp.next_interval; + ELSE + i_profile.destination_initial_interval:=i_destination.initial_interval; + i_profile.destination_next_interval:=i_destination.next_interval; + end if; + + IF i_profile.package_counter_id IS NULL THEN + CASE i_profile.destination_rate_policy_id + WHEN 1 THEN -- fixed + i_profile.destination_next_rate:=i_destination.next_rate::varchar; + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + WHEN 2 THEN -- based on dialpeer + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + WHEN 3 THEN -- min + IF i_dp.next_rate >= i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; -- FIXED least + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + WHEN 4 THEN -- max + IF i_dp.next_rate < i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; --FIXED + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + ELSE + -- + end case; + END IF; + + + /* time limiting START */ + --SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth.account_id; + --SELECT INTO STRICT v_v_acc * FROM billing.accounts WHERE id=v_dialpeer.account_id; + + + if i_profile.time_limit is null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit is not set, calculating',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + IF (i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval<0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: No enough customer balance even for first billing interval. rejecting',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + i_profile.disconnect_code_id=8000; --Not enough customer balance + RETURN i_profile; + ELSIF i_destination.next_rate!=0 AND i_destination.next_interval!=0 THEN + i_profile.time_limit = (i_destination.initial_interval+ + LEAST(FLOOR(((i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval)/ + (i_destination.next_rate/60*i_destination.next_interval)),24e6)::integer*i_destination.next_interval)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + ELSE /* DST rates is 0, allowing maximum call length */ + i_profile.time_limit = COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: DST rate is 0. customer time limit set to max value: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + end IF; + end if; + + IF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee <0 THEN /* No enough balance, skipping this profile */ + v_vendor_allowtime:=0; + return null; + ELSIF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval<0 THEN /* No enough balance even for first billing interval - skipping this profile */ + return null; + ELSIF i_dp.next_rate!=0 AND i_dp.next_interval!=0 THEN /* DP rates is not zero, calculating limit */ + v_vendor_allowtime:=i_dp.initial_interval+ + LEAST(FLOOR(((i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval)/ + (i_dp.next_rate/60*i_dp.next_interval)),24e6)::integer*i_dp.next_interval; + ELSE /* DP rates is 0, allowing maximum call length */ + v_vendor_allowtime:=COALESCE(i_vendor_acc.max_call_duration, i_max_call_length); + end IF; + + i_profile.time_limit=LEAST( + COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer, + COALESCE(i_vendor_acc.max_call_duration, i_max_call_length)::integer, + v_vendor_allowtime, + i_profile.time_limit + )::integer; + + + /* number rewriting _After_ routing */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_dp.dst_rewrite_rule,i_dp.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_dp.src_rewrite_rule,i_dp.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_dp.src_name_rewrite_rule,i_dp.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + /* + get termination gw data + */ + --SELECT into v_dst_gw * from class4.gateways WHERE id=v_dialpeer.gateway_id; + --SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth.gateway_id; + --vendor gw + if i_vendor_gw.termination_capacity is not null then + i_profile.legb_res:=i_profile.legb_res||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + end if; + + + /* + numberlist processing _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before numberlist processing src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + ----- DST Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.dst_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_dst_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + ni.key=i_profile.dst_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.dst_prefix_out) and + length(i_profile.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_dst_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + ----- SRC Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.src_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_src_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + ni.key=i_profile.src_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.src_prefix_out) and + length(i_profile.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_src_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + /* + number rewriting _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_vendor_gw.dst_rewrite_rule,i_vendor_gw.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_vendor_gw.src_rewrite_rule,i_vendor_gw.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_vendor_gw.src_name_rewrite_rule,i_vendor_gw.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + IF cardinality(i_diversion) > 0 AND i_vendor_gw.diversion_send_mode_id > 1 THEN + v_diversion = yeti_ext.regexp_replace_rand(i_diversion, i_vendor_gw.diversion_rewrite_rule, i_vendor_gw.diversion_rewrite_result); + + IF i_vendor_gw.diversion_send_mode_id = 2 AND i_vendor_gw.diversion_domain is not null AND i_vendor_gw.diversion_domain!='' THEN + /* Diversion as SIP URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req = array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + END LOOP; + ELSIF i_vendor_gw.diversion_send_mode_id = 3 THEN + /* Diversion as TEL URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req=array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header)::varchar + ); + END LOOP; + END IF; + + /* Field for CDR */ + i_profile.diversion_out = array_to_string(v_diversion_out, ','); + END IF; + + CASE i_vendor_gw.privacy_mode_id + WHEN 0 THEN + -- do nothing + WHEN 1 THEN + IF cardinality(array_remove(i_privacy,'none')) > 0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 2 THEN + IF 'critical' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 3 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. Applying privacy.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) OR 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + END IF; + IF 'id' = ANY(i_privacy) OR 'header' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. removing PAI/PPI headers.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + v_allow_pai = false; + END IF; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + WHEN 4 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF cardinality(i_privacy)>0 THEN + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + WHEN 5 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding with anonymous From.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) or 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + END CASE; + + IF v_allow_pai THEN + -- only if privacy mode allows to send PAI + IF i_vendor_gw.pai_send_mode_id = 1 THEN + -- TEL URI + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 2 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + -- SIP URL + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 3 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 4 THEN + -- relay + FOREACH v_pai IN ARRAY i_pai LOOP + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: %s', v_pai)::varchar); + END LOOP; + v_pai_out = i_pai; + IF i_ppi is not null and i_ppi!='' THEN + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Preferred-Identity: %s', i_ppi)::varchar); + i_profile.ppi_out = i_ppi; + END IF; + END IF; + i_profile.pai_out = NULLIF(array_to_string(v_pai_out, ','),''); + END IF; + + IF i_vendor_gw.stir_shaken_mode_id IN (1,2) THEN + IF i_profile.lega_ss_status_id >0 THEN + -- relaying valid header from customer + i_profile.legb_ss_status_id = i_profile.lega_ss_status_id; + v_customer_transit_headers_from_origination = array_append(v_customer_transit_headers_from_origination,'Identity'); + v_vendor_transit_headers_from_origination = array_append(v_vendor_transit_headers_from_origination,'Identity'); + ELSIF COALESCE(i_profile.ss_attest_id,0) > 0 AND i_vendor_gw.stir_shaken_crt_id IS NOT NULL THEN + -- insert our signature + i_profile.ss_crt_id = i_vendor_gw.stir_shaken_crt_id; + i_profile.legb_ss_status_id = i_profile.ss_attest_id; + + IF i_vendor_gw.stir_shaken_mode_id = 1 THEN + i_profile.ss_otn = i_profile.src_prefix_routing; + i_profile.ss_dtn = i_profile.dst_prefix_routing; + ELSIF i_vendor_gw.stir_shaken_mode_id = 2 THEN + i_profile.ss_otn = i_profile.src_prefix_out; + i_profile.ss_dtn = i_profile.dst_prefix_out; + END IF; + END IF; + END IF ; + + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); + i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); + + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); + + i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled + i_profile.next_hop:=i_vendor_gw.term_next_hop; + i_profile.aleg_next_hop:=i_customer_gw.orig_next_hop; + -- i_profile.next_hop_for_replies:=v_dst_gw.term_next_hop_for_replies; + + i_profile.dlg_nat_handling=i_customer_gw.dialog_nat_handling; + + i_profile.call_id:=''; -- Generation by sems + + i_profile.enable_auth:=i_vendor_gw.auth_enabled; + i_profile.auth_pwd:=i_vendor_gw.auth_password; + i_profile.auth_user:=i_vendor_gw.auth_user; + i_profile.enable_aleg_auth:=false; + i_profile.auth_aleg_pwd:=''; + i_profile.auth_aleg_user:=''; + + if i_profile.enable_auth then + v_from_user=COALESCE(i_vendor_gw.auth_from_user,i_profile.src_prefix_out,''); + -- may be it already defined by privacy logic + v_from_domain=COALESCE(v_from_domain, i_vendor_gw.auth_from_domain, '$Oi'); + else + v_from_user=COALESCE(i_profile.src_prefix_out,''); + if i_vendor_gw.preserve_anonymous_from_domain and i_profile.from_domain='anonymous.invalid' then + v_from_domain='anonymous.invalid'; + else + v_from_domain=COALESCE(v_from_domain, '$Oi'); + end if; + end if; + + v_to_username = yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out, i_vendor_gw.to_rewrite_rule, i_vendor_gw.to_rewrite_result); + + if i_vendor_gw.sip_schema_id = 1 then + v_schema='sip'; + elsif i_vendor_gw.sip_schema_id = 2 then + v_schema='sips'; + elsif i_vendor_gw.sip_schema_id = 3 then + v_schema='sip'; + -- user=phone param require e.164 with + in username, but we are not forcing it + v_from_uri_params = array_append(v_from_uri_params,'user=phone'); + v_to_uri_params = array_append(v_to_uri_params,'user=phone'); + v_ruri_params = array_append(v_ruri_params,'user=phone'); + else + RAISE exception 'Unknown termination gateway % SIP schema %', i_vendor_gw.id, i_vendor_gw.sip_schema_id; + end if; + + if i_vendor_gw.send_lnp_information and i_profile.lrn is not null then + if i_profile.lrn=i_profile.dst_prefix_routing then -- number not ported, but request was successf we musr add ;npdi=yes; + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + i_profile.lrn=nullif(i_profile.dst_prefix_routing,i_profile.lrn); -- clear lnr field if number not ported; + else -- if number ported + v_ruri_user_params = array_append(v_ruri_user_params, 'rn='||i_profile.lrn); + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + end if; + end if; + + i_profile.registered_aor_mode_id = i_vendor_gw.registered_aor_mode_id; + if i_vendor_gw.registered_aor_mode_id > 0 then + i_profile.registered_aor_id=i_vendor_gw.id; + v_ruri_host = 'unknown.invalid'; + else + v_ruri_host = i_vendor_gw.host; + end if; + + i_profile."from" = switch21.build_uri(false, v_schema, i_profile.src_name_out, v_from_user, null, v_from_domain, null, v_from_uri_params); + + i_profile."to" = switch21.build_uri(false, v_schema, null, v_to_username, null, v_ruri_host, i_vendor_gw.port, v_to_uri_params); + i_profile.ruri = switch21.build_uri(true, v_schema, null, i_profile.dst_prefix_out, v_ruri_user_params, v_ruri_host, i_vendor_gw.port, v_ruri_params); + + i_profile.bleg_transport_protocol_id:=i_vendor_gw.transport_protocol_id; + i_profile.bleg_protocol_priority_id:=i_vendor_gw.network_protocol_priority_id; + + i_profile.aleg_media_encryption_mode_id:=i_customer_gw.media_encryption_mode_id; + i_profile.bleg_media_encryption_mode_id:=i_vendor_gw.media_encryption_mode_id; + + IF (i_vendor_gw.term_use_outbound_proxy ) THEN + i_profile.outbound_proxy:=v_schema||':'||i_vendor_gw.term_outbound_proxy; + i_profile.force_outbound_proxy:=i_vendor_gw.term_force_outbound_proxy; + i_profile.bleg_outbound_proxy_transport_protocol_id:=i_vendor_gw.term_proxy_transport_protocol_id; + ELSE + i_profile.outbound_proxy:=NULL; + i_profile.force_outbound_proxy:=false; + END IF; + + IF (i_customer_gw.orig_use_outbound_proxy ) THEN + i_profile.aleg_force_outbound_proxy:=i_customer_gw.orig_force_outbound_proxy; + i_profile.aleg_outbound_proxy=v_schema||':'||i_customer_gw.orig_outbound_proxy; + i_profile.aleg_outbound_proxy_transport_protocol_id:=i_customer_gw.orig_proxy_transport_protocol_id; + else + i_profile.aleg_force_outbound_proxy:=FALSE; + i_profile.aleg_outbound_proxy=NULL; + end if; + + i_profile.aleg_policy_id=i_customer_gw.orig_disconnect_policy_id; + i_profile.bleg_policy_id=i_vendor_gw.term_disconnect_policy_id; + + i_profile.transit_headers_a2b:=array_to_string(v_customer_transit_headers_from_origination,',')||';'||array_to_string(v_vendor_transit_headers_from_origination,','); + i_profile.transit_headers_b2a:=i_vendor_gw.transit_headers_from_termination||';'||i_customer_gw.transit_headers_from_termination; + + i_profile.sdp_filter_type_id:=0; + i_profile.sdp_filter_list:=''; + + i_profile.sdp_alines_filter_type_id:=i_vendor_gw.sdp_alines_filter_type_id; + i_profile.sdp_alines_filter_list:=i_vendor_gw.sdp_alines_filter_list; + + i_profile.enable_session_timer=i_vendor_gw.sst_enabled; + i_profile.session_expires =i_vendor_gw.sst_session_expires; + i_profile.minimum_timer:=i_vendor_gw.sst_minimum_timer; + i_profile.maximum_timer:=i_vendor_gw.sst_maximum_timer; + i_profile.session_refresh_method_id:=i_vendor_gw.session_refresh_method_id; + i_profile.accept_501_reply:=i_vendor_gw.sst_accept501; + + i_profile.enable_aleg_session_timer=i_customer_gw.sst_enabled; + i_profile.aleg_session_expires:=i_customer_gw.sst_session_expires; + i_profile.aleg_minimum_timer:=i_customer_gw.sst_minimum_timer; + i_profile.aleg_maximum_timer:=i_customer_gw.sst_maximum_timer; + i_profile.aleg_session_refresh_method_id:=i_customer_gw.session_refresh_method_id; + i_profile.aleg_accept_501_reply:=i_customer_gw.sst_accept501; + + i_profile.reply_translations:=''; + i_profile.disconnect_code_id:=NULL; + i_profile.enable_rtprelay:=i_vendor_gw.proxy_media OR i_customer_gw.proxy_media; + + i_profile.rtprelay_interface:=i_vendor_gw.rtp_interface_name; + i_profile.aleg_rtprelay_interface:=i_customer_gw.rtp_interface_name; + + i_profile.outbound_interface:=i_vendor_gw.sip_interface_name; + i_profile.aleg_outbound_interface:=i_customer_gw.sip_interface_name; + + i_profile.bleg_force_symmetric_rtp:=i_vendor_gw.force_symmetric_rtp; + i_profile.bleg_symmetric_rtp_nonstop=i_vendor_gw.symmetric_rtp_nonstop; + + i_profile.aleg_force_symmetric_rtp:=i_customer_gw.force_symmetric_rtp; + i_profile.aleg_symmetric_rtp_nonstop=i_customer_gw.symmetric_rtp_nonstop; + + i_profile.bleg_rtp_ping=i_vendor_gw.rtp_ping; + i_profile.aleg_rtp_ping=i_customer_gw.rtp_ping; + + i_profile.bleg_relay_options = i_vendor_gw.relay_options; + i_profile.aleg_relay_options = i_customer_gw.relay_options; + + + i_profile.filter_noaudio_streams = i_vendor_gw.filter_noaudio_streams OR i_customer_gw.filter_noaudio_streams; + i_profile.force_one_way_early_media = i_vendor_gw.force_one_way_early_media OR i_customer_gw.force_one_way_early_media; + i_profile.aleg_relay_reinvite = i_vendor_gw.relay_reinvite; + i_profile.bleg_relay_reinvite = i_customer_gw.relay_reinvite; + + i_profile.aleg_relay_hold = i_vendor_gw.relay_hold; + i_profile.bleg_relay_hold = i_customer_gw.relay_hold; + + i_profile.aleg_relay_prack = i_vendor_gw.relay_prack; + i_profile.bleg_relay_prack = i_customer_gw.relay_prack; + i_profile.aleg_rel100_mode_id = i_customer_gw.rel100_mode_id; + i_profile.bleg_rel100_mode_id = i_vendor_gw.rel100_mode_id; + + i_profile.rtp_relay_timestamp_aligning=i_vendor_gw.rtp_relay_timestamp_aligning OR i_customer_gw.rtp_relay_timestamp_aligning; + i_profile.allow_1xx_wo2tag=i_vendor_gw.allow_1xx_without_to_tag OR i_customer_gw.allow_1xx_without_to_tag; + + i_profile.aleg_sdp_c_location_id=i_customer_gw.sdp_c_location_id; + i_profile.bleg_sdp_c_location_id=i_vendor_gw.sdp_c_location_id; + i_profile.trusted_hdrs_gw=false; + + + + i_profile.aleg_codecs_group_id:=i_customer_gw.codec_group_id; + i_profile.bleg_codecs_group_id:=i_vendor_gw.codec_group_id; + i_profile.aleg_single_codec_in_200ok:=i_customer_gw.single_codec_in_200ok; + i_profile.bleg_single_codec_in_200ok:=i_vendor_gw.single_codec_in_200ok; + i_profile.try_avoid_transcoding = i_customer_gw.try_avoid_transcoding; + i_profile.ringing_timeout=i_vendor_gw.ringing_timeout; + i_profile.dead_rtp_time=GREATEST(i_vendor_gw.rtp_timeout,i_customer_gw.rtp_timeout); + i_profile.invite_timeout=i_vendor_gw.sip_timer_b; + i_profile.srv_failover_timeout=i_vendor_gw.dns_srv_failover_timer; + i_profile.fake_180_timer=i_vendor_gw.fake_180_timer; + i_profile.rtp_force_relay_cn=i_vendor_gw.rtp_force_relay_cn OR i_customer_gw.rtp_force_relay_cn; + i_profile.patch_ruri_next_hop=i_vendor_gw.resolve_ruri; + + i_profile.aleg_sensor_id=i_customer_gw.sensor_id; + i_profile.aleg_sensor_level_id=i_customer_gw.sensor_level_id; + i_profile.bleg_sensor_id=i_vendor_gw.sensor_id; + i_profile.bleg_sensor_level_id=i_vendor_gw.sensor_level_id; + + i_profile.aleg_dtmf_send_mode_id=i_customer_gw.dtmf_send_mode_id; + i_profile.aleg_dtmf_recv_modes=i_customer_gw.dtmf_receive_mode_id; + i_profile.bleg_dtmf_send_mode_id=i_vendor_gw.dtmf_send_mode_id; + i_profile.bleg_dtmf_recv_modes=i_vendor_gw.dtmf_receive_mode_id; + + + i_profile.aleg_rtp_filter_inband_dtmf=false; + i_profile.bleg_rtp_filter_inband_dtmf=false; + + if i_customer_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + elsif i_customer_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_vendor_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.aleg_rtp_filter_inband_dtmf=false; + elsif i_vendor_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + + if i_vendor_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + elsif i_vendor_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_customer_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.bleg_rtp_filter_inband_dtmf=false; + elsif i_customer_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + i_profile.aleg_rtp_acl = i_customer_gw.rtp_acl; + i_profile.bleg_rtp_acl = i_vendor_gw.rtp_acl; + + i_profile.rtprelay_force_dtmf_relay=i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_detection=NOT i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_filtering=NOT i_vendor_gw.force_dtmf_relay; + i_profile.bleg_max_30x_redirects = i_vendor_gw.max_30x_redirects; + i_profile.bleg_max_transfers = i_vendor_gw.max_transfers; + + + i_profile.aleg_relay_update=i_customer_gw.relay_update; + i_profile.bleg_relay_update=i_vendor_gw.relay_update; + i_profile.suppress_early_media=i_customer_gw.suppress_early_media OR i_vendor_gw.suppress_early_media; + + i_profile.bleg_radius_acc_profile_id=i_vendor_gw.radius_accounting_profile_id; + i_profile.bleg_force_cancel_routeset=i_vendor_gw.force_cancel_routeset; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Finished: % ',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_profile,true); + /*}dbg*/ + RETURN i_profile; +END; +$_$; + + set search_path TO switch21; + SELECT * from switch21.preprocess_all(); + set search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; + + + } + + + + end + + def down + execute %q{ + + alter table class4.gateways + alter column orig_append_headers_req drop not null, + alter column orig_append_headers_req drop default, + alter column orig_append_headers_reply drop not null, + alter column orig_append_headers_reply drop default, + alter column term_append_headers_req drop not null, + alter column term_append_headers_req drop default; + + alter table class4.gateways + alter column orig_append_headers_req type varchar using array_to_string(orig_append_headers_req, '\r\n'), + alter column term_append_headers_req type varchar using array_to_string(orig_append_headers_req, '\r\n'); + +CREATE or replace FUNCTION switch20.process_gw(i_profile switch20.callprofile_ty, i_destination class4.destinations, i_dp class4.dialpeers, i_customer_acc billing.accounts, i_customer_gw class4.gateways, i_vendor_acc billing.accounts, i_vendor_gw class4.gateways, i_send_billing_information boolean, i_max_call_length integer, i_diversion character varying[], i_privacy character varying[], i_pai character varying[], i_ppi character varying) RETURNS switch20.callprofile_ty + LANGUAGE plpgsql STABLE SECURITY DEFINER COST 100000 + AS $_$ +DECLARE + i integer; + v_vendor_allowtime real; + v_route_found boolean:=false; + v_from_user varchar; + v_from_domain varchar; + v_schema varchar; + v_termination_numberlist class4.numberlists%rowtype; + v_termination_numberlist_item class4.numberlist_items%rowtype; + v_termination_numberlist_size integer; + v_aleg_append_headers_reply varchar[] not null default ARRAY[]::varchar[]; + v_bleg_append_headers_req varchar[] not null default ARRAY[]::varchar[]; + v_diversion varchar[] not null default ARRAY[]::varchar[]; + v_diversion_header varchar; + v_diversion_out varchar[] not null default ARRAY[]::varchar[]; + v_pai_out varchar[] not null default ARRAY[]::varchar[]; + v_pai varchar; + v_allow_pai boolean:=true; + v_to_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_from_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_host varchar; + v_ruri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_user_params varchar[] not null default ARRAY[]::varchar[]; + v_to_username varchar; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ +BEGIN + /*dbg{*/ + v_start:=now(); + --RAISE NOTICE 'process_dp in: %',i_profile; + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Found dialpeer: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_dp,true); + /*}dbg*/ + + --RAISE NOTICE 'process_dp dst: %',i_destination; + + i_profile.destination_id:=i_destination.id; + i_profile.destination_fee:=i_destination.connect_fee::varchar; + i_profile.destination_rate_policy_id:=i_destination.rate_policy_id; + + --vendor account capacity limit; + i_profile.legb_res= ''; + if i_vendor_acc.termination_capacity is not null then + i_profile.legb_res = '2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + end if; + + if i_vendor_acc.total_capacity is not null then + i_profile.legb_res = i_profile.legb_res||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + end if; + + -- dialpeer account capacity limit; + if i_dp.capacity is not null then + i_profile.legb_res = i_profile.legb_res||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + i_profile.resources = i_profile.resources||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + end if; + + /* */ + i_profile.dialpeer_id=i_dp.id; + i_profile.dialpeer_prefix=i_dp.prefix; + i_profile.dialpeer_next_rate=i_dp.next_rate::varchar; + i_profile.dialpeer_initial_rate=i_dp.initial_rate::varchar; + i_profile.dialpeer_initial_interval=i_dp.initial_interval; + i_profile.dialpeer_next_interval=i_dp.next_interval; + i_profile.dialpeer_fee=i_dp.connect_fee::varchar; + i_profile.dialpeer_reverse_billing=i_dp.reverse_billing; + i_profile.vendor_id=i_dp.vendor_id; + i_profile.vendor_acc_id=i_dp.account_id; + i_profile.term_gw_id=i_vendor_gw.id; + + i_profile.orig_gw_name=i_customer_gw."name"; + i_profile.orig_gw_external_id=i_customer_gw.external_id; + + i_profile.term_gw_name=i_vendor_gw."name"; + i_profile.term_gw_external_id=i_vendor_gw.external_id; + + i_profile.customer_account_name=i_customer_acc."name"; + + i_profile.routing_group_id:=i_dp.routing_group_id; + + if i_send_billing_information then + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-INT:'||i_profile.dialpeer_initial_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-INT:'||i_profile.dialpeer_next_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-RATE:'||i_profile.dialpeer_initial_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-RATE:'||i_profile.dialpeer_next_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-CF:'||i_profile.dialpeer_fee)::varchar); + end if; + v_aleg_append_headers_reply = array_cat(v_aleg_append_headers_reply,i_customer_gw.orig_append_headers_reply); + i_profile.aleg_append_headers_reply=ARRAY_TO_STRING(v_aleg_append_headers_reply,'\r\n'); + + if i_destination.use_dp_intervals THEN + i_profile.destination_initial_interval:=i_dp.initial_interval; + i_profile.destination_next_interval:=i_dp.next_interval; + ELSE + i_profile.destination_initial_interval:=i_destination.initial_interval; + i_profile.destination_next_interval:=i_destination.next_interval; + end if; + + CASE i_profile.destination_rate_policy_id + WHEN 1 THEN -- fixed + i_profile.destination_next_rate:=i_destination.next_rate::varchar; + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + WHEN 2 THEN -- based on dialpeer + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + WHEN 3 THEN -- min + IF i_dp.next_rate >= i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; -- FIXED least + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + WHEN 4 THEN -- max + IF i_dp.next_rate < i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; --FIXED + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + ELSE + -- + end case; + + + + /* time limiting START */ + --SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth.account_id; + --SELECT INTO STRICT v_v_acc * FROM billing.accounts WHERE id=v_dialpeer.account_id; + + + if i_profile.time_limit is null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit is not set, calculating',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + IF (i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval<0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: No enough customer balance even for first billing interval. rejecting',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + i_profile.disconnect_code_id=8000; --Not enough customer balance + RETURN i_profile; + ELSIF i_destination.next_rate!=0 AND i_destination.next_interval!=0 THEN + i_profile.time_limit = (i_destination.initial_interval+ + LEAST(FLOOR(((i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval)/ + (i_destination.next_rate/60*i_destination.next_interval)),24e6)::integer*i_destination.next_interval)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + ELSE /* DST rates is 0, allowing maximum call length */ + i_profile.time_limit = COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: DST rate is 0. customer time limit set to max value: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + end IF; + end if; + + IF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee <0 THEN /* No enough balance, skipping this profile */ + v_vendor_allowtime:=0; + return null; + ELSIF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval<0 THEN /* No enough balance even for first billing interval - skipping this profile */ + return null; + ELSIF i_dp.next_rate!=0 AND i_dp.next_interval!=0 THEN /* DP rates is not zero, calculating limit */ + v_vendor_allowtime:=i_dp.initial_interval+ + LEAST(FLOOR(((i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval)/ + (i_dp.next_rate/60*i_dp.next_interval)),24e6)::integer*i_dp.next_interval; + ELSE /* DP rates is 0, allowing maximum call length */ + v_vendor_allowtime:=COALESCE(i_vendor_acc.max_call_duration, i_max_call_length); + end IF; + + i_profile.time_limit=LEAST( + COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer, + COALESCE(i_vendor_acc.max_call_duration, i_max_call_length)::integer, + v_vendor_allowtime, + i_profile.time_limit + )::integer; + + + /* number rewriting _After_ routing */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_dp.dst_rewrite_rule,i_dp.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_dp.src_rewrite_rule,i_dp.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_dp.src_name_rewrite_rule,i_dp.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + /* + get termination gw data + */ + --SELECT into v_dst_gw * from class4.gateways WHERE id=v_dialpeer.gateway_id; + --SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth.gateway_id; + --vendor gw + if i_vendor_gw.termination_capacity is not null then + i_profile.legb_res:=i_profile.legb_res||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + i_profile.resources:=i_profile.resources||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + end if; + + + /* + numberlist processing _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before numberlist processing src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + ----- DST Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.dst_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_dst_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + ni.key=i_profile.dst_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.dst_prefix_out) and + length(i_profile.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_dst_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + ----- SRC Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.src_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_src_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + ni.key=i_profile.src_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.src_prefix_out) and + length(i_profile.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_src_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + /* + number rewriting _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_vendor_gw.dst_rewrite_rule,i_vendor_gw.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_vendor_gw.src_rewrite_rule,i_vendor_gw.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_vendor_gw.src_name_rewrite_rule,i_vendor_gw.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + IF cardinality(i_diversion) > 0 AND i_vendor_gw.diversion_send_mode_id > 1 THEN + v_diversion = yeti_ext.regexp_replace_rand(i_diversion, i_vendor_gw.diversion_rewrite_rule, i_vendor_gw.diversion_rewrite_result); + + IF i_vendor_gw.diversion_send_mode_id = 2 AND i_vendor_gw.diversion_domain is not null AND i_vendor_gw.diversion_domain!='' THEN + /* Diversion as SIP URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req = array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + END LOOP; + ELSIF i_vendor_gw.diversion_send_mode_id = 3 THEN + /* Diversion as TEL URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req=array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header)::varchar + ); + END LOOP; + END IF; + + /* Field for CDR */ + i_profile.diversion_out = array_to_string(v_diversion_out, ','); + END IF; + + CASE i_vendor_gw.privacy_mode_id + WHEN 0 THEN + -- do nothing + WHEN 1 THEN + IF cardinality(array_remove(i_privacy,'none')) > 0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 2 THEN + IF 'critical' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 3 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. Applying privacy.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) OR 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + END IF; + IF 'id' = ANY(i_privacy) OR 'header' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. removing PAI/PPI headers.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + v_allow_pai = false; + END IF; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + WHEN 4 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF cardinality(i_privacy)>0 THEN + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + WHEN 5 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding with anonymous From.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) or 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + END CASE; + + IF v_allow_pai THEN + -- only if privacy mode allows to send PAI + IF i_vendor_gw.pai_send_mode_id = 1 THEN + -- TEL URI + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 2 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + -- SIP URL + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 3 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 4 THEN + -- relay + FOREACH v_pai IN ARRAY i_pai LOOP + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: %s', v_pai)::varchar); + END LOOP; + v_pai_out = i_pai; + IF i_ppi is not null and i_ppi!='' THEN + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Preferred-Identity: %s', i_ppi)::varchar); + i_profile.ppi_out = i_ppi; + END IF; + END IF; + i_profile.pai_out = NULLIF(array_to_string(v_pai_out, ','),''); + END IF; + + IF i_vendor_gw.stir_shaken_mode_id = 1 AND COALESCE(i_profile.ss_attest_id,0) > 0 THEN + -- insert signature + i_profile.ss_crt_id = i_vendor_gw.stir_shaken_crt_id; + i_profile.ss_otn = i_profile.src_prefix_routing; + i_profile.ss_dtn = i_profile.dst_prefix_routing; + i_profile.legb_ss_status_id = i_profile.ss_attest_id; + END IF; + + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); + + i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + + i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled + i_profile.next_hop:=i_vendor_gw.term_next_hop; + i_profile.aleg_next_hop:=i_customer_gw.orig_next_hop; + -- i_profile.next_hop_for_replies:=v_dst_gw.term_next_hop_for_replies; + + i_profile.dlg_nat_handling=i_customer_gw.dialog_nat_handling; + + i_profile.call_id:=''; -- Generation by sems + + i_profile.enable_auth:=i_vendor_gw.auth_enabled; + i_profile.auth_pwd:=i_vendor_gw.auth_password; + i_profile.auth_user:=i_vendor_gw.auth_user; + i_profile.enable_aleg_auth:=false; + i_profile.auth_aleg_pwd:=''; + i_profile.auth_aleg_user:=''; + + if i_profile.enable_auth then + v_from_user=COALESCE(i_vendor_gw.auth_from_user,i_profile.src_prefix_out,''); + -- may be it already defined by privacy logic + v_from_domain=COALESCE(v_from_domain, i_vendor_gw.auth_from_domain, '$Oi'); + else + v_from_user=COALESCE(i_profile.src_prefix_out,''); + if i_vendor_gw.preserve_anonymous_from_domain and i_profile.from_domain='anonymous.invalid' then + v_from_domain='anonymous.invalid'; + else + v_from_domain=COALESCE(v_from_domain, '$Oi'); + end if; + end if; + + v_to_username = yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out, i_vendor_gw.to_rewrite_rule, i_vendor_gw.to_rewrite_result); + + if i_vendor_gw.sip_schema_id = 1 then + v_schema='sip'; + elsif i_vendor_gw.sip_schema_id = 2 then + v_schema='sips'; + elsif i_vendor_gw.sip_schema_id = 3 then + v_schema='sip'; + -- user=phone param require e.164 with + in username, but we are not forcing it + v_from_uri_params = array_append(v_from_uri_params,'user=phone'); + v_to_uri_params = array_append(v_to_uri_params,'user=phone'); + v_ruri_params = array_append(v_ruri_params,'user=phone'); + else + RAISE exception 'Unknown termination gateway % SIP schema %', i_vendor_gw.id, i_vendor_gw.sip_schema_id; + end if; + + if i_vendor_gw.send_lnp_information and i_profile.lrn is not null then + if i_profile.lrn=i_profile.dst_prefix_routing then -- number not ported, but request was successf we musr add ;npdi=yes; + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + i_profile.lrn=nullif(i_profile.dst_prefix_routing,i_profile.lrn); -- clear lnr field if number not ported; + else -- if number ported + v_ruri_user_params = array_append(v_ruri_user_params, 'rn='||i_profile.lrn); + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + end if; + end if; + + i_profile.registered_aor_mode_id = i_vendor_gw.registered_aor_mode_id; + if i_vendor_gw.registered_aor_mode_id > 0 then + i_profile.registered_aor_id=i_vendor_gw.id; + v_ruri_host = 'unknown.invalid'; + else + v_ruri_host = i_vendor_gw.host; + end if; + + i_profile."from" = switch20.build_uri(false, v_schema, i_profile.src_name_out, v_from_user, null, v_from_domain, null, v_from_uri_params); + + i_profile."to" = switch20.build_uri(false, v_schema, null, v_to_username, null, v_ruri_host, i_vendor_gw.port, v_to_uri_params); + i_profile.ruri = switch20.build_uri(true, v_schema, null, i_profile.dst_prefix_out, v_ruri_user_params, v_ruri_host, i_vendor_gw.port, v_ruri_params); + + i_profile.bleg_transport_protocol_id:=i_vendor_gw.transport_protocol_id; + i_profile.bleg_protocol_priority_id:=i_vendor_gw.network_protocol_priority_id; + + i_profile.aleg_media_encryption_mode_id:=i_customer_gw.media_encryption_mode_id; + i_profile.bleg_media_encryption_mode_id:=i_vendor_gw.media_encryption_mode_id; + + IF (i_vendor_gw.term_use_outbound_proxy ) THEN + i_profile.outbound_proxy:=v_schema||':'||i_vendor_gw.term_outbound_proxy; + i_profile.force_outbound_proxy:=i_vendor_gw.term_force_outbound_proxy; + i_profile.bleg_outbound_proxy_transport_protocol_id:=i_vendor_gw.term_proxy_transport_protocol_id; + ELSE + i_profile.outbound_proxy:=NULL; + i_profile.force_outbound_proxy:=false; + END IF; + + IF (i_customer_gw.orig_use_outbound_proxy ) THEN + i_profile.aleg_force_outbound_proxy:=i_customer_gw.orig_force_outbound_proxy; + i_profile.aleg_outbound_proxy=v_schema||':'||i_customer_gw.orig_outbound_proxy; + i_profile.aleg_outbound_proxy_transport_protocol_id:=i_customer_gw.orig_proxy_transport_protocol_id; + else + i_profile.aleg_force_outbound_proxy:=FALSE; + i_profile.aleg_outbound_proxy=NULL; + end if; + + i_profile.aleg_policy_id=i_customer_gw.orig_disconnect_policy_id; + i_profile.bleg_policy_id=i_vendor_gw.term_disconnect_policy_id; + + i_profile.transit_headers_a2b:=i_customer_gw.transit_headers_from_origination||';'||i_vendor_gw.transit_headers_from_origination; + i_profile.transit_headers_b2a:=i_vendor_gw.transit_headers_from_termination||';'||i_customer_gw.transit_headers_from_termination; + + i_profile.sdp_filter_type_id:=0; + i_profile.sdp_filter_list:=''; + + i_profile.sdp_alines_filter_type_id:=i_vendor_gw.sdp_alines_filter_type_id; + i_profile.sdp_alines_filter_list:=i_vendor_gw.sdp_alines_filter_list; + + i_profile.enable_session_timer=i_vendor_gw.sst_enabled; + i_profile.session_expires =i_vendor_gw.sst_session_expires; + i_profile.minimum_timer:=i_vendor_gw.sst_minimum_timer; + i_profile.maximum_timer:=i_vendor_gw.sst_maximum_timer; + i_profile.session_refresh_method_id:=i_vendor_gw.session_refresh_method_id; + i_profile.accept_501_reply:=i_vendor_gw.sst_accept501; + + i_profile.enable_aleg_session_timer=i_customer_gw.sst_enabled; + i_profile.aleg_session_expires:=i_customer_gw.sst_session_expires; + i_profile.aleg_minimum_timer:=i_customer_gw.sst_minimum_timer; + i_profile.aleg_maximum_timer:=i_customer_gw.sst_maximum_timer; + i_profile.aleg_session_refresh_method_id:=i_customer_gw.session_refresh_method_id; + i_profile.aleg_accept_501_reply:=i_customer_gw.sst_accept501; + + i_profile.reply_translations:=''; + i_profile.disconnect_code_id:=NULL; + i_profile.enable_rtprelay:=i_vendor_gw.proxy_media OR i_customer_gw.proxy_media; + + i_profile.rtprelay_interface:=i_vendor_gw.rtp_interface_name; + i_profile.aleg_rtprelay_interface:=i_customer_gw.rtp_interface_name; + + i_profile.outbound_interface:=i_vendor_gw.sip_interface_name; + i_profile.aleg_outbound_interface:=i_customer_gw.sip_interface_name; + + i_profile.bleg_force_symmetric_rtp:=i_vendor_gw.force_symmetric_rtp; + i_profile.bleg_symmetric_rtp_nonstop=i_vendor_gw.symmetric_rtp_nonstop; + + i_profile.aleg_force_symmetric_rtp:=i_customer_gw.force_symmetric_rtp; + i_profile.aleg_symmetric_rtp_nonstop=i_customer_gw.symmetric_rtp_nonstop; + + i_profile.bleg_rtp_ping=i_vendor_gw.rtp_ping; + i_profile.aleg_rtp_ping=i_customer_gw.rtp_ping; + + i_profile.bleg_relay_options = i_vendor_gw.relay_options; + i_profile.aleg_relay_options = i_customer_gw.relay_options; + + + i_profile.filter_noaudio_streams = i_vendor_gw.filter_noaudio_streams OR i_customer_gw.filter_noaudio_streams; + i_profile.force_one_way_early_media = i_vendor_gw.force_one_way_early_media OR i_customer_gw.force_one_way_early_media; + i_profile.aleg_relay_reinvite = i_vendor_gw.relay_reinvite; + i_profile.bleg_relay_reinvite = i_customer_gw.relay_reinvite; + + i_profile.aleg_relay_hold = i_vendor_gw.relay_hold; + i_profile.bleg_relay_hold = i_customer_gw.relay_hold; + + i_profile.aleg_relay_prack = i_vendor_gw.relay_prack; + i_profile.bleg_relay_prack = i_customer_gw.relay_prack; + i_profile.aleg_rel100_mode_id = i_customer_gw.rel100_mode_id; + i_profile.bleg_rel100_mode_id = i_vendor_gw.rel100_mode_id; + + i_profile.rtp_relay_timestamp_aligning=i_vendor_gw.rtp_relay_timestamp_aligning OR i_customer_gw.rtp_relay_timestamp_aligning; + i_profile.allow_1xx_wo2tag=i_vendor_gw.allow_1xx_without_to_tag OR i_customer_gw.allow_1xx_without_to_tag; + + i_profile.aleg_sdp_c_location_id=i_customer_gw.sdp_c_location_id; + i_profile.bleg_sdp_c_location_id=i_vendor_gw.sdp_c_location_id; + i_profile.trusted_hdrs_gw=false; + + + + i_profile.aleg_codecs_group_id:=i_customer_gw.codec_group_id; + i_profile.bleg_codecs_group_id:=i_vendor_gw.codec_group_id; + i_profile.aleg_single_codec_in_200ok:=i_customer_gw.single_codec_in_200ok; + i_profile.bleg_single_codec_in_200ok:=i_vendor_gw.single_codec_in_200ok; + i_profile.try_avoid_transcoding = i_customer_gw.try_avoid_transcoding; + i_profile.ringing_timeout=i_vendor_gw.ringing_timeout; + i_profile.dead_rtp_time=GREATEST(i_vendor_gw.rtp_timeout,i_customer_gw.rtp_timeout); + i_profile.invite_timeout=i_vendor_gw.sip_timer_b; + i_profile.srv_failover_timeout=i_vendor_gw.dns_srv_failover_timer; + i_profile.fake_180_timer=i_vendor_gw.fake_180_timer; + i_profile.rtp_force_relay_cn=i_vendor_gw.rtp_force_relay_cn OR i_customer_gw.rtp_force_relay_cn; + i_profile.patch_ruri_next_hop=i_vendor_gw.resolve_ruri; + + i_profile.aleg_sensor_id=i_customer_gw.sensor_id; + i_profile.aleg_sensor_level_id=i_customer_gw.sensor_level_id; + i_profile.bleg_sensor_id=i_vendor_gw.sensor_id; + i_profile.bleg_sensor_level_id=i_vendor_gw.sensor_level_id; + + i_profile.aleg_dtmf_send_mode_id=i_customer_gw.dtmf_send_mode_id; + i_profile.aleg_dtmf_recv_modes=i_customer_gw.dtmf_receive_mode_id; + i_profile.bleg_dtmf_send_mode_id=i_vendor_gw.dtmf_send_mode_id; + i_profile.bleg_dtmf_recv_modes=i_vendor_gw.dtmf_receive_mode_id; + + + i_profile.aleg_rtp_filter_inband_dtmf=false; + i_profile.bleg_rtp_filter_inband_dtmf=false; + + if i_customer_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + elsif i_customer_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_vendor_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.aleg_rtp_filter_inband_dtmf=false; + elsif i_vendor_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + + if i_vendor_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + elsif i_vendor_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_customer_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.bleg_rtp_filter_inband_dtmf=false; + elsif i_customer_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + i_profile.aleg_rtp_acl = i_customer_gw.rtp_acl; + i_profile.bleg_rtp_acl = i_vendor_gw.rtp_acl; + + i_profile.rtprelay_force_dtmf_relay=i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_detection=NOT i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_filtering=NOT i_vendor_gw.force_dtmf_relay; + i_profile.bleg_max_30x_redirects = i_vendor_gw.max_30x_redirects; + i_profile.bleg_max_transfers = i_vendor_gw.max_transfers; + + + i_profile.aleg_relay_update=i_customer_gw.relay_update; + i_profile.bleg_relay_update=i_vendor_gw.relay_update; + i_profile.suppress_early_media=i_customer_gw.suppress_early_media OR i_vendor_gw.suppress_early_media; + + i_profile.bleg_radius_acc_profile_id=i_vendor_gw.radius_accounting_profile_id; + i_profile.bleg_force_cancel_routeset=i_vendor_gw.force_cancel_routeset; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Finished: % ',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_profile,true); + /*}dbg*/ + RETURN i_profile; +END; +$_$; + +set search_path TO switch20; +SELECT * from switch20.preprocess_all(); +set search_path TO gui, public, switch, billing, class4, runtime_stats, sys, logs, data_import; + + +CREATE or replace FUNCTION switch21.process_gw(i_profile switch21.callprofile_ty, i_destination class4.destinations, i_dp class4.dialpeers, i_customer_acc billing.accounts, i_customer_gw class4.gateways, i_vendor_acc billing.accounts, i_vendor_gw class4.gateways, i_send_billing_information boolean, i_max_call_length integer, i_diversion character varying[], i_privacy character varying[], i_pai character varying[], i_ppi character varying) RETURNS switch21.callprofile_ty + LANGUAGE plpgsql STABLE SECURITY DEFINER COST 100000 + AS $_$ +DECLARE + i integer; + v_vendor_allowtime real; + v_route_found boolean:=false; + v_from_user varchar; + v_from_domain varchar; + v_schema varchar; + v_termination_numberlist class4.numberlists%rowtype; + v_termination_numberlist_item class4.numberlist_items%rowtype; + v_termination_numberlist_size integer; + v_aleg_append_headers_reply varchar[] not null default ARRAY[]::varchar[]; + v_bleg_append_headers_req varchar[] not null default ARRAY[]::varchar[]; + v_diversion varchar[] not null default ARRAY[]::varchar[]; + v_diversion_header varchar; + v_diversion_out varchar[] not null default ARRAY[]::varchar[]; + v_pai_out varchar[] not null default ARRAY[]::varchar[]; + v_pai varchar; + v_allow_pai boolean:=true; + v_to_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_from_uri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_host varchar; + v_ruri_params varchar[] not null default ARRAY[]::varchar[]; + v_ruri_user_params varchar[] not null default ARRAY[]::varchar[]; + v_to_username varchar; + v_customer_transit_headers_from_origination varchar[] default ARRAY[]::varchar[]; + v_vendor_transit_headers_from_origination varchar[] default ARRAY[]::varchar[]; + /*dbg{*/ + v_start timestamp; + v_end timestamp; + /*}dbg*/ +BEGIN + /*dbg{*/ + v_start:=now(); + --RAISE NOTICE 'process_dp in: %',i_profile; + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Found dialpeer: %',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_dp,true); + /*}dbg*/ + + --RAISE NOTICE 'process_dp dst: %',i_destination; + + i_profile.destination_id:=i_destination.id; + i_profile.destination_fee:=i_destination.connect_fee::varchar; + i_profile.destination_rate_policy_id:=i_destination.rate_policy_id; + + --vendor account capacity limit; + i_profile.legb_res= ''; + if i_vendor_acc.termination_capacity is not null then + i_profile.legb_res = '2:'||i_dp.account_id::varchar||':'||i_vendor_acc.termination_capacity::varchar||':1;'; + end if; + + if i_vendor_acc.total_capacity is not null then + i_profile.legb_res = i_profile.legb_res||'7:'||i_dp.account_id::varchar||':'||i_vendor_acc.total_capacity::varchar||':1;'; + end if; + + -- dialpeer account capacity limit; + if i_dp.capacity is not null then + i_profile.legb_res = i_profile.legb_res||'6:'||i_dp.id::varchar||':'||i_dp.capacity::varchar||':1;'; + end if; + + /* */ + i_profile.dialpeer_id=i_dp.id; + i_profile.dialpeer_prefix=i_dp.prefix; + i_profile.dialpeer_next_rate=i_dp.next_rate::varchar; + i_profile.dialpeer_initial_rate=i_dp.initial_rate::varchar; + i_profile.dialpeer_initial_interval=i_dp.initial_interval; + i_profile.dialpeer_next_interval=i_dp.next_interval; + i_profile.dialpeer_fee=i_dp.connect_fee::varchar; + i_profile.dialpeer_reverse_billing=i_dp.reverse_billing; + i_profile.vendor_id=i_dp.vendor_id; + i_profile.vendor_acc_id=i_dp.account_id; + i_profile.term_gw_id=i_vendor_gw.id; + + i_profile.orig_gw_name=i_customer_gw."name"; + i_profile.orig_gw_external_id=i_customer_gw.external_id; + + i_profile.term_gw_name=i_vendor_gw."name"; + i_profile.term_gw_external_id=i_vendor_gw.external_id; + + i_profile.customer_account_name=i_customer_acc."name"; + + i_profile.routing_group_id:=i_dp.routing_group_id; + + -- TODO. store arrays in GW and not convert it there + v_customer_transit_headers_from_origination = string_to_array(COALESCE(i_customer_gw.transit_headers_from_origination,''),','); + v_vendor_transit_headers_from_origination = string_to_array(COALESCE(i_vendor_gw.transit_headers_from_origination,''),','); + + if i_send_billing_information then + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-INT:'||i_profile.dialpeer_initial_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-INT:'||i_profile.dialpeer_next_interval)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-INIT-RATE:'||i_profile.dialpeer_initial_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-NEXT-RATE:'||i_profile.dialpeer_next_rate)::varchar); + v_aleg_append_headers_reply=array_append(v_aleg_append_headers_reply, (E'X-VND-CF:'||i_profile.dialpeer_fee)::varchar); + end if; + v_aleg_append_headers_reply = array_cat(v_aleg_append_headers_reply,i_customer_gw.orig_append_headers_reply); + i_profile.aleg_append_headers_reply=ARRAY_TO_STRING(v_aleg_append_headers_reply,'\r\n'); + + if i_destination.use_dp_intervals THEN + i_profile.destination_initial_interval:=i_dp.initial_interval; + i_profile.destination_next_interval:=i_dp.next_interval; + ELSE + i_profile.destination_initial_interval:=i_destination.initial_interval; + i_profile.destination_next_interval:=i_destination.next_interval; + end if; + + IF i_profile.package_counter_id IS NULL THEN + CASE i_profile.destination_rate_policy_id + WHEN 1 THEN -- fixed + i_profile.destination_next_rate:=i_destination.next_rate::varchar; + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + WHEN 2 THEN -- based on dialpeer + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + WHEN 3 THEN -- min + IF i_dp.next_rate >= i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; -- FIXED least + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + WHEN 4 THEN -- max + IF i_dp.next_rate < i_destination.next_rate THEN + i_profile.destination_next_rate:=i_destination.next_rate::varchar; --FIXED + i_profile.destination_initial_rate:=i_destination.initial_rate::varchar; + ELSE + i_profile.destination_next_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.next_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; -- DYNAMIC + i_profile.destination_initial_rate:=(COALESCE(i_destination.dp_margin_fixed,0)+i_dp.initial_rate*(1+COALESCE(i_destination.dp_margin_percent,0)))::varchar; + END IF; + ELSE + -- + end case; + END IF; + + + /* time limiting START */ + --SELECT INTO STRICT v_c_acc * FROM billing.accounts WHERE id=v_customer_auth.account_id; + --SELECT INTO STRICT v_v_acc * FROM billing.accounts WHERE id=v_dialpeer.account_id; + + + if i_profile.time_limit is null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit is not set, calculating',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + IF (i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval<0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: No enough customer balance even for first billing interval. rejecting',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + i_profile.disconnect_code_id=8000; --Not enough customer balance + RETURN i_profile; + ELSIF i_destination.next_rate!=0 AND i_destination.next_interval!=0 THEN + i_profile.time_limit = (i_destination.initial_interval+ + LEAST(FLOOR(((i_customer_acc.balance-i_customer_acc.min_balance)-i_destination.connect_fee-i_destination.initial_rate/60*i_destination.initial_interval)/ + (i_destination.next_rate/60*i_destination.next_interval)),24e6)::integer*i_destination.next_interval)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: customer time limit: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + ELSE /* DST rates is 0, allowing maximum call length */ + i_profile.time_limit = COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer; + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> process_gw: DST rate is 0. customer time limit set to max value: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.time_limit; + /*}dbg*/ + end IF; + end if; + + IF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee <0 THEN /* No enough balance, skipping this profile */ + v_vendor_allowtime:=0; + return null; + ELSIF (i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval<0 THEN /* No enough balance even for first billing interval - skipping this profile */ + return null; + ELSIF i_dp.next_rate!=0 AND i_dp.next_interval!=0 THEN /* DP rates is not zero, calculating limit */ + v_vendor_allowtime:=i_dp.initial_interval+ + LEAST(FLOOR(((i_vendor_acc.max_balance-i_vendor_acc.balance)-i_dp.connect_fee-i_dp.initial_rate/60*i_dp.initial_interval)/ + (i_dp.next_rate/60*i_dp.next_interval)),24e6)::integer*i_dp.next_interval; + ELSE /* DP rates is 0, allowing maximum call length */ + v_vendor_allowtime:=COALESCE(i_vendor_acc.max_call_duration, i_max_call_length); + end IF; + + i_profile.time_limit=LEAST( + COALESCE(i_customer_acc.max_call_duration, i_max_call_length)::integer, + COALESCE(i_vendor_acc.max_call_duration, i_max_call_length)::integer, + v_vendor_allowtime, + i_profile.time_limit + )::integer; + + + /* number rewriting _After_ routing */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_dp.dst_rewrite_rule,i_dp.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_dp.src_rewrite_rule,i_dp.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_dp.src_name_rewrite_rule,i_dp.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + /* + get termination gw data + */ + --SELECT into v_dst_gw * from class4.gateways WHERE id=v_dialpeer.gateway_id; + --SELECT into v_orig_gw * from class4.gateways WHERE id=v_customer_auth.gateway_id; + --vendor gw + if i_vendor_gw.termination_capacity is not null then + i_profile.legb_res:=i_profile.legb_res||'5:'||i_vendor_gw.id::varchar||':'||i_vendor_gw.termination_capacity::varchar||':1;'; + end if; + + + /* + numberlist processing _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before numberlist processing src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + ----- DST Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_dst_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.dst_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_dst_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + ni.key=i_profile.dst_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.dst_prefix_out) and + length(i_profile.dst_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_dst_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_dst_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + ----- SRC Numberlist processing------------------------------------------------------------------------------------------------------- + IF i_vendor_gw.termination_src_numberlist_id is not null then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist processing. Lookup by key: %',EXTRACT(MILLISECOND from v_end-v_start), i_profile.src_prefix_out; + /*}dbg*/ + + select into v_termination_numberlist * from class4.numberlists where id=i_vendor_gw.termination_src_numberlist_id; + CASE v_termination_numberlist.mode_id + when 1 then -- strict match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + ni.key=i_profile.src_prefix_out + limit 1; + when 2 then -- prefix match + select into v_termination_numberlist_item * from class4.numberlist_items ni + where + ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id and + prefix_range(ni.key)@>prefix_range(i_profile.src_prefix_out) and + length(i_profile.src_prefix_out) between ni.number_min_length and ni.number_max_length + order by length(prefix_range(ni.key)) desc + limit 1; + when 3 then -- random + select into v_termination_numberlist_size count(*) from class4.numberlist_items where numberlist_id=i_vendor_gw.termination_src_numberlist_id; + select into v_termination_numberlist_item * from class4.numberlist_items ni + where ni.numberlist_id=i_vendor_gw.termination_src_numberlist_id order by ni.id OFFSET floor(random()*v_termination_numberlist_size) limit 1; + END CASE; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. key found: %',EXTRACT(MILLISECOND from v_end-v_start), row_to_json(v_termination_numberlist_item); + /*}dbg*/ + + IF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW SRC Numberlist. Drop by key action. Skipping route. Key: %',EXTRACT(MILLISECOND from v_end-v_start), v_termination_numberlist_item.key; + /*}dbg*/ + RETURN null; + ELSIF v_termination_numberlist_item.action_id is not null and v_termination_numberlist_item.action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist_item.src_rewrite_rule, + v_termination_numberlist_item.src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist_item.dst_rewrite_rule, + v_termination_numberlist_item.dst_rewrite_result + ); + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=1 then + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW DST Numberlist. Drop by default action. Skipping route.',EXTRACT(MILLISECOND from v_end-v_start); + /*}dbg*/ + -- drop by default + RETURN null; + ELSIF v_termination_numberlist_item.action_id is null and v_termination_numberlist.default_action_id=2 then + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.src_prefix_out, + v_termination_numberlist.default_src_rewrite_rule, + v_termination_numberlist.default_src_rewrite_result + ); + + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand( + i_profile.dst_prefix_out, + v_termination_numberlist.default_dst_rewrite_rule, + v_termination_numberlist.default_dst_rewrite_result + ); + END IF; + END IF; + + + + /* + number rewriting _After_ routing _IN_ termination GW + */ + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. Before rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + i_profile.dst_prefix_out=yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out,i_vendor_gw.dst_rewrite_rule,i_vendor_gw.dst_rewrite_result); + i_profile.src_prefix_out=yeti_ext.regexp_replace_rand(i_profile.src_prefix_out,i_vendor_gw.src_rewrite_rule,i_vendor_gw.src_rewrite_result); + i_profile.src_name_out=yeti_ext.regexp_replace_rand(i_profile.src_name_out,i_vendor_gw.src_name_rewrite_rule,i_vendor_gw.src_name_rewrite_result, true); + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW. After rewrite src_prefix: % , dst_prefix: %',EXTRACT(MILLISECOND from v_end-v_start),i_profile.src_prefix_out,i_profile.dst_prefix_out; + /*}dbg*/ + + + IF cardinality(i_diversion) > 0 AND i_vendor_gw.diversion_send_mode_id > 1 THEN + v_diversion = yeti_ext.regexp_replace_rand(i_diversion, i_vendor_gw.diversion_rewrite_rule, i_vendor_gw.diversion_rewrite_result); + + IF i_vendor_gw.diversion_send_mode_id = 2 AND i_vendor_gw.diversion_domain is not null AND i_vendor_gw.diversion_domain!='' THEN + /* Diversion as SIP URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req = array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header, i_vendor_gw.diversion_domain)::varchar + ); + END LOOP; + ELSIF i_vendor_gw.diversion_send_mode_id = 3 THEN + /* Diversion as TEL URI */ + FOREACH v_diversion_header IN ARRAY v_diversion LOOP + v_bleg_append_headers_req=array_append( + v_bleg_append_headers_req, + format('Diversion: ', v_diversion_header)::varchar + ); + v_diversion_out = array_append( + v_diversion_out, + format('', v_diversion_header)::varchar + ); + END LOOP; + END IF; + + /* Field for CDR */ + i_profile.diversion_out = array_to_string(v_diversion_out, ','); + END IF; + + CASE i_vendor_gw.privacy_mode_id + WHEN 0 THEN + -- do nothing + WHEN 1 THEN + IF cardinality(array_remove(i_privacy,'none')) > 0 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 2 THEN + IF 'critical' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested but privacy_mode_is %. Skipping gw.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + return null; + END IF; + WHEN 3 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. Applying privacy.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) OR 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + END IF; + IF 'id' = ANY(i_privacy) OR 'header' = ANY(i_privacy) THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. removing PAI/PPI headers.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + v_allow_pai = false; + END IF; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + WHEN 4 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF cardinality(i_privacy)>0 THEN + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + WHEN 5 THEN + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> GW Privacy % requested, privacy_mode_is %. forwarding with anonymous From.',EXTRACT(MILLISECOND from v_end-v_start), i_privacy, i_vendor_gw.privacy_mode_id; + /*}dbg*/ + IF 'id' = ANY(i_privacy) or 'user' = ANY(i_privacy) THEN + i_profile.src_prefix_out='anonymous'; + i_profile.src_name_out='Anonymous'; + v_from_domain = 'anonymous.invalid'; + i_profile.privacy_out = array_to_string(i_privacy,';'); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('Privacy: %s', array_to_string(i_privacy,';')::varchar)); + END IF; + END CASE; + + IF v_allow_pai THEN + -- only if privacy mode allows to send PAI + IF i_vendor_gw.pai_send_mode_id = 1 THEN + -- TEL URI + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 2 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + -- SIP URL + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 3 and i_vendor_gw.pai_domain is not null and i_vendor_gw.pai_domain!='' THEN + v_pai_out = array_append(v_pai_out, format('', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: ', i_profile.src_prefix_out, i_vendor_gw.pai_domain)::varchar); + ELSIF i_vendor_gw.pai_send_mode_id = 4 THEN + -- relay + FOREACH v_pai IN ARRAY i_pai LOOP + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Asserted-Identity: %s', v_pai)::varchar); + END LOOP; + v_pai_out = i_pai; + IF i_ppi is not null and i_ppi!='' THEN + v_bleg_append_headers_req = array_append(v_bleg_append_headers_req, format('P-Preferred-Identity: %s', i_ppi)::varchar); + i_profile.ppi_out = i_ppi; + END IF; + END IF; + i_profile.pai_out = NULLIF(array_to_string(v_pai_out, ','),''); + END IF; + + IF i_vendor_gw.stir_shaken_mode_id IN (1,2) THEN + IF i_profile.lega_ss_status_id >0 THEN + -- relaying valid header from customer + i_profile.legb_ss_status_id = i_profile.lega_ss_status_id; + v_customer_transit_headers_from_origination = array_append(v_customer_transit_headers_from_origination,'Identity'); + v_vendor_transit_headers_from_origination = array_append(v_vendor_transit_headers_from_origination,'Identity'); + ELSIF COALESCE(i_profile.ss_attest_id,0) > 0 AND i_vendor_gw.stir_shaken_crt_id IS NOT NULL THEN + -- insert our signature + i_profile.ss_crt_id = i_vendor_gw.stir_shaken_crt_id; + i_profile.legb_ss_status_id = i_profile.ss_attest_id; + + IF i_vendor_gw.stir_shaken_mode_id = 1 THEN + i_profile.ss_otn = i_profile.src_prefix_routing; + i_profile.ss_dtn = i_profile.dst_prefix_routing; + ELSIF i_vendor_gw.stir_shaken_mode_id = 2 THEN + i_profile.ss_otn = i_profile.src_prefix_out; + i_profile.ss_dtn = i_profile.dst_prefix_out; + END IF; + END IF; + END IF ; + + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); + + i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + + i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled + i_profile.next_hop:=i_vendor_gw.term_next_hop; + i_profile.aleg_next_hop:=i_customer_gw.orig_next_hop; + -- i_profile.next_hop_for_replies:=v_dst_gw.term_next_hop_for_replies; + + i_profile.dlg_nat_handling=i_customer_gw.dialog_nat_handling; + + i_profile.call_id:=''; -- Generation by sems + + i_profile.enable_auth:=i_vendor_gw.auth_enabled; + i_profile.auth_pwd:=i_vendor_gw.auth_password; + i_profile.auth_user:=i_vendor_gw.auth_user; + i_profile.enable_aleg_auth:=false; + i_profile.auth_aleg_pwd:=''; + i_profile.auth_aleg_user:=''; + + if i_profile.enable_auth then + v_from_user=COALESCE(i_vendor_gw.auth_from_user,i_profile.src_prefix_out,''); + -- may be it already defined by privacy logic + v_from_domain=COALESCE(v_from_domain, i_vendor_gw.auth_from_domain, '$Oi'); + else + v_from_user=COALESCE(i_profile.src_prefix_out,''); + if i_vendor_gw.preserve_anonymous_from_domain and i_profile.from_domain='anonymous.invalid' then + v_from_domain='anonymous.invalid'; + else + v_from_domain=COALESCE(v_from_domain, '$Oi'); + end if; + end if; + + v_to_username = yeti_ext.regexp_replace_rand(i_profile.dst_prefix_out, i_vendor_gw.to_rewrite_rule, i_vendor_gw.to_rewrite_result); + + if i_vendor_gw.sip_schema_id = 1 then + v_schema='sip'; + elsif i_vendor_gw.sip_schema_id = 2 then + v_schema='sips'; + elsif i_vendor_gw.sip_schema_id = 3 then + v_schema='sip'; + -- user=phone param require e.164 with + in username, but we are not forcing it + v_from_uri_params = array_append(v_from_uri_params,'user=phone'); + v_to_uri_params = array_append(v_to_uri_params,'user=phone'); + v_ruri_params = array_append(v_ruri_params,'user=phone'); + else + RAISE exception 'Unknown termination gateway % SIP schema %', i_vendor_gw.id, i_vendor_gw.sip_schema_id; + end if; + + if i_vendor_gw.send_lnp_information and i_profile.lrn is not null then + if i_profile.lrn=i_profile.dst_prefix_routing then -- number not ported, but request was successf we musr add ;npdi=yes; + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + i_profile.lrn=nullif(i_profile.dst_prefix_routing,i_profile.lrn); -- clear lnr field if number not ported; + else -- if number ported + v_ruri_user_params = array_append(v_ruri_user_params, 'rn='||i_profile.lrn); + v_ruri_user_params = array_append(v_ruri_user_params, 'npdi=yes'); + end if; + end if; + + i_profile.registered_aor_mode_id = i_vendor_gw.registered_aor_mode_id; + if i_vendor_gw.registered_aor_mode_id > 0 then + i_profile.registered_aor_id=i_vendor_gw.id; + v_ruri_host = 'unknown.invalid'; + else + v_ruri_host = i_vendor_gw.host; + end if; + + i_profile."from" = switch21.build_uri(false, v_schema, i_profile.src_name_out, v_from_user, null, v_from_domain, null, v_from_uri_params); + + i_profile."to" = switch21.build_uri(false, v_schema, null, v_to_username, null, v_ruri_host, i_vendor_gw.port, v_to_uri_params); + i_profile.ruri = switch21.build_uri(true, v_schema, null, i_profile.dst_prefix_out, v_ruri_user_params, v_ruri_host, i_vendor_gw.port, v_ruri_params); + + i_profile.bleg_transport_protocol_id:=i_vendor_gw.transport_protocol_id; + i_profile.bleg_protocol_priority_id:=i_vendor_gw.network_protocol_priority_id; + + i_profile.aleg_media_encryption_mode_id:=i_customer_gw.media_encryption_mode_id; + i_profile.bleg_media_encryption_mode_id:=i_vendor_gw.media_encryption_mode_id; + + IF (i_vendor_gw.term_use_outbound_proxy ) THEN + i_profile.outbound_proxy:=v_schema||':'||i_vendor_gw.term_outbound_proxy; + i_profile.force_outbound_proxy:=i_vendor_gw.term_force_outbound_proxy; + i_profile.bleg_outbound_proxy_transport_protocol_id:=i_vendor_gw.term_proxy_transport_protocol_id; + ELSE + i_profile.outbound_proxy:=NULL; + i_profile.force_outbound_proxy:=false; + END IF; + + IF (i_customer_gw.orig_use_outbound_proxy ) THEN + i_profile.aleg_force_outbound_proxy:=i_customer_gw.orig_force_outbound_proxy; + i_profile.aleg_outbound_proxy=v_schema||':'||i_customer_gw.orig_outbound_proxy; + i_profile.aleg_outbound_proxy_transport_protocol_id:=i_customer_gw.orig_proxy_transport_protocol_id; + else + i_profile.aleg_force_outbound_proxy:=FALSE; + i_profile.aleg_outbound_proxy=NULL; + end if; + + i_profile.aleg_policy_id=i_customer_gw.orig_disconnect_policy_id; + i_profile.bleg_policy_id=i_vendor_gw.term_disconnect_policy_id; + + i_profile.transit_headers_a2b:=array_to_string(v_customer_transit_headers_from_origination,',')||';'||array_to_string(v_vendor_transit_headers_from_origination,','); + i_profile.transit_headers_b2a:=i_vendor_gw.transit_headers_from_termination||';'||i_customer_gw.transit_headers_from_termination; + + i_profile.sdp_filter_type_id:=0; + i_profile.sdp_filter_list:=''; + + i_profile.sdp_alines_filter_type_id:=i_vendor_gw.sdp_alines_filter_type_id; + i_profile.sdp_alines_filter_list:=i_vendor_gw.sdp_alines_filter_list; + + i_profile.enable_session_timer=i_vendor_gw.sst_enabled; + i_profile.session_expires =i_vendor_gw.sst_session_expires; + i_profile.minimum_timer:=i_vendor_gw.sst_minimum_timer; + i_profile.maximum_timer:=i_vendor_gw.sst_maximum_timer; + i_profile.session_refresh_method_id:=i_vendor_gw.session_refresh_method_id; + i_profile.accept_501_reply:=i_vendor_gw.sst_accept501; + + i_profile.enable_aleg_session_timer=i_customer_gw.sst_enabled; + i_profile.aleg_session_expires:=i_customer_gw.sst_session_expires; + i_profile.aleg_minimum_timer:=i_customer_gw.sst_minimum_timer; + i_profile.aleg_maximum_timer:=i_customer_gw.sst_maximum_timer; + i_profile.aleg_session_refresh_method_id:=i_customer_gw.session_refresh_method_id; + i_profile.aleg_accept_501_reply:=i_customer_gw.sst_accept501; + + i_profile.reply_translations:=''; + i_profile.disconnect_code_id:=NULL; + i_profile.enable_rtprelay:=i_vendor_gw.proxy_media OR i_customer_gw.proxy_media; + + i_profile.rtprelay_interface:=i_vendor_gw.rtp_interface_name; + i_profile.aleg_rtprelay_interface:=i_customer_gw.rtp_interface_name; + + i_profile.outbound_interface:=i_vendor_gw.sip_interface_name; + i_profile.aleg_outbound_interface:=i_customer_gw.sip_interface_name; + + i_profile.bleg_force_symmetric_rtp:=i_vendor_gw.force_symmetric_rtp; + i_profile.bleg_symmetric_rtp_nonstop=i_vendor_gw.symmetric_rtp_nonstop; + + i_profile.aleg_force_symmetric_rtp:=i_customer_gw.force_symmetric_rtp; + i_profile.aleg_symmetric_rtp_nonstop=i_customer_gw.symmetric_rtp_nonstop; + + i_profile.bleg_rtp_ping=i_vendor_gw.rtp_ping; + i_profile.aleg_rtp_ping=i_customer_gw.rtp_ping; + + i_profile.bleg_relay_options = i_vendor_gw.relay_options; + i_profile.aleg_relay_options = i_customer_gw.relay_options; + + + i_profile.filter_noaudio_streams = i_vendor_gw.filter_noaudio_streams OR i_customer_gw.filter_noaudio_streams; + i_profile.force_one_way_early_media = i_vendor_gw.force_one_way_early_media OR i_customer_gw.force_one_way_early_media; + i_profile.aleg_relay_reinvite = i_vendor_gw.relay_reinvite; + i_profile.bleg_relay_reinvite = i_customer_gw.relay_reinvite; + + i_profile.aleg_relay_hold = i_vendor_gw.relay_hold; + i_profile.bleg_relay_hold = i_customer_gw.relay_hold; + + i_profile.aleg_relay_prack = i_vendor_gw.relay_prack; + i_profile.bleg_relay_prack = i_customer_gw.relay_prack; + i_profile.aleg_rel100_mode_id = i_customer_gw.rel100_mode_id; + i_profile.bleg_rel100_mode_id = i_vendor_gw.rel100_mode_id; + + i_profile.rtp_relay_timestamp_aligning=i_vendor_gw.rtp_relay_timestamp_aligning OR i_customer_gw.rtp_relay_timestamp_aligning; + i_profile.allow_1xx_wo2tag=i_vendor_gw.allow_1xx_without_to_tag OR i_customer_gw.allow_1xx_without_to_tag; + + i_profile.aleg_sdp_c_location_id=i_customer_gw.sdp_c_location_id; + i_profile.bleg_sdp_c_location_id=i_vendor_gw.sdp_c_location_id; + i_profile.trusted_hdrs_gw=false; + + + + i_profile.aleg_codecs_group_id:=i_customer_gw.codec_group_id; + i_profile.bleg_codecs_group_id:=i_vendor_gw.codec_group_id; + i_profile.aleg_single_codec_in_200ok:=i_customer_gw.single_codec_in_200ok; + i_profile.bleg_single_codec_in_200ok:=i_vendor_gw.single_codec_in_200ok; + i_profile.try_avoid_transcoding = i_customer_gw.try_avoid_transcoding; + i_profile.ringing_timeout=i_vendor_gw.ringing_timeout; + i_profile.dead_rtp_time=GREATEST(i_vendor_gw.rtp_timeout,i_customer_gw.rtp_timeout); + i_profile.invite_timeout=i_vendor_gw.sip_timer_b; + i_profile.srv_failover_timeout=i_vendor_gw.dns_srv_failover_timer; + i_profile.fake_180_timer=i_vendor_gw.fake_180_timer; + i_profile.rtp_force_relay_cn=i_vendor_gw.rtp_force_relay_cn OR i_customer_gw.rtp_force_relay_cn; + i_profile.patch_ruri_next_hop=i_vendor_gw.resolve_ruri; + + i_profile.aleg_sensor_id=i_customer_gw.sensor_id; + i_profile.aleg_sensor_level_id=i_customer_gw.sensor_level_id; + i_profile.bleg_sensor_id=i_vendor_gw.sensor_id; + i_profile.bleg_sensor_level_id=i_vendor_gw.sensor_level_id; + + i_profile.aleg_dtmf_send_mode_id=i_customer_gw.dtmf_send_mode_id; + i_profile.aleg_dtmf_recv_modes=i_customer_gw.dtmf_receive_mode_id; + i_profile.bleg_dtmf_send_mode_id=i_vendor_gw.dtmf_send_mode_id; + i_profile.bleg_dtmf_recv_modes=i_vendor_gw.dtmf_receive_mode_id; + + + i_profile.aleg_rtp_filter_inband_dtmf=false; + i_profile.bleg_rtp_filter_inband_dtmf=false; + + if i_customer_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + elsif i_customer_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_vendor_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.aleg_rtp_filter_inband_dtmf=false; + elsif i_vendor_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.aleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + + if i_vendor_gw.rx_inband_dtmf_filtering_mode_id=3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + elsif i_vendor_gw.rx_inband_dtmf_filtering_mode_id=1 then -- inherit + if i_customer_gw.tx_inband_dtmf_filtering_mode_id in (1,2) then -- inherit or disable filtering + i_profile.bleg_rtp_filter_inband_dtmf=false; + elsif i_customer_gw.tx_inband_dtmf_filtering_mode_id = 3 then -- enable filtering + i_profile.bleg_rtp_filter_inband_dtmf=true; + end if; + end if; + + i_profile.aleg_rtp_acl = i_customer_gw.rtp_acl; + i_profile.bleg_rtp_acl = i_vendor_gw.rtp_acl; + + i_profile.rtprelay_force_dtmf_relay=i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_detection=NOT i_vendor_gw.force_dtmf_relay; + i_profile.rtprelay_dtmf_filtering=NOT i_vendor_gw.force_dtmf_relay; + i_profile.bleg_max_30x_redirects = i_vendor_gw.max_30x_redirects; + i_profile.bleg_max_transfers = i_vendor_gw.max_transfers; + + + i_profile.aleg_relay_update=i_customer_gw.relay_update; + i_profile.bleg_relay_update=i_vendor_gw.relay_update; + i_profile.suppress_early_media=i_customer_gw.suppress_early_media OR i_vendor_gw.suppress_early_media; + + i_profile.bleg_radius_acc_profile_id=i_vendor_gw.radius_accounting_profile_id; + i_profile.bleg_force_cancel_routeset=i_vendor_gw.force_cancel_routeset; + + /*dbg{*/ + v_end:=clock_timestamp(); + RAISE NOTICE '% ms -> DP. Finished: % ',EXTRACT(MILLISECOND from v_end-v_start),row_to_json(i_profile,true); + /*}dbg*/ + RETURN i_profile; +END; +$_$; + + set search_path TO switch21; + SELECT * from switch21.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 f07ba26ea..370e291b8 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -3086,8 +3086,8 @@ CREATE TABLE class4.gateways ( termination_capacity smallint, term_next_hop character varying, orig_next_hop character varying, - orig_append_headers_req character varying, - term_append_headers_req character varying, + orig_append_headers_req character varying[] DEFAULT '{}'::character varying[] NOT NULL, + term_append_headers_req character varying[] DEFAULT '{}'::character varying[] NOT NULL, dialog_nat_handling boolean DEFAULT true NOT NULL, orig_force_outbound_proxy boolean DEFAULT false NOT NULL, orig_use_outbound_proxy boolean DEFAULT false NOT NULL, @@ -3164,7 +3164,7 @@ CREATE TABLE class4.gateways ( termination_dst_numberlist_id smallint, lua_script_id smallint, rtp_acl inet[], - orig_append_headers_reply character varying[], + orig_append_headers_reply character varying[] DEFAULT '{}'::character varying[] NOT NULL, diversion_send_mode_id smallint DEFAULT 1 NOT NULL, diversion_domain character varying, try_avoid_transcoding boolean DEFAULT false NOT NULL, @@ -16771,10 +16771,10 @@ BEGIN i_profile.legb_ss_status_id = i_profile.ss_attest_id; END IF; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -17537,10 +17537,10 @@ BEGIN i_profile.legb_ss_status_id = i_profile.ss_attest_id; END IF; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -18226,10 +18226,10 @@ BEGIN i_profile.legb_ss_status_id = i_profile.ss_attest_id; END IF; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -24390,10 +24390,10 @@ BEGIN END IF; END IF ; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -25172,10 +25172,10 @@ BEGIN END IF; END IF ; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -25877,10 +25877,10 @@ BEGIN END IF; END IF ; - v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, string_to_array(i_vendor_gw.term_append_headers_req,'\r\n')::varchar[]); + v_bleg_append_headers_req = array_cat(v_bleg_append_headers_req, i_vendor_gw.term_append_headers_req); i_profile.append_headers_req = array_to_string(v_bleg_append_headers_req,'\r\n'); - i_profile.aleg_append_headers_req=i_customer_gw.orig_append_headers_req; + i_profile.aleg_append_headers_req = array_to_string(i_customer_gw.orig_append_headers_req,'\r\n'); i_profile.next_hop_1st_req=i_vendor_gw.auth_enabled; -- use low delay dns srv if auth enabled i_profile.next_hop:=i_vendor_gw.term_next_hop; @@ -41202,6 +41202,7 @@ INSERT INTO "public"."schema_migrations" (version) VALUES ('20240725135654'), ('20240805121644'), ('20240806205100'), -('20240822145410'); +('20240822145410'), +('20240824084143'); diff --git a/lib/active_admin/inputs/newline_array_of_headers_input.rb b/lib/active_admin/inputs/newline_array_of_headers_input.rb new file mode 100644 index 000000000..050b2c972 --- /dev/null +++ b/lib/active_admin/inputs/newline_array_of_headers_input.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module ActiveAdmin + module Inputs + class NewlineArrayOfHeadersInput < Formtastic::Inputs::TextInput + def input_html_options + super.merge(extra_input_html_options) + end + + def extra_input_html_options + { + value: value, + rows: 4 + } + end + + # ActiveAdmin has bug: Edit form do not uses Decorated object + # in this case we need to duplicate array-join here + # on update(render form) activeadmin uses Decorated object, and this is redundant here + def value + return options[:input_html][:value] if options[:input_html]&.key?(:value) + + val = object.public_send(method) + return val.join("\r\n") if val.is_a?(Array) + + val + end + + def hint_text + super || I18n.t(:hint_newline_array_of_headers) + end + end + end +end diff --git a/spec/controllers/api/rest/admin/gateways_controller_spec.rb b/spec/controllers/api/rest/admin/gateways_controller_spec.rb index 95157e3fd..fab160cfe 100644 --- a/spec/controllers/api/rest/admin/gateways_controller_spec.rb +++ b/spec/controllers/api/rest/admin/gateways_controller_spec.rb @@ -42,8 +42,6 @@ it_behaves_like :jsonapi_filters_by_number_field, :termination_capacity it_behaves_like :jsonapi_filters_by_string_field, :term_next_hop it_behaves_like :jsonapi_filters_by_string_field, :orig_next_hop - it_behaves_like :jsonapi_filters_by_string_field, :orig_append_headers_req - it_behaves_like :jsonapi_filters_by_string_field, :term_append_headers_req it_behaves_like :jsonapi_filters_by_boolean_field, :dialog_nat_handling it_behaves_like :jsonapi_filters_by_boolean_field, :orig_force_outbound_proxy it_behaves_like :jsonapi_filters_by_boolean_field, :orig_use_outbound_proxy diff --git a/spec/factories/gateways.rb b/spec/factories/gateways.rb index 2a51ed6b0..2620b577e 100644 --- a/spec/factories/gateways.rb +++ b/spec/factories/gateways.rb @@ -39,8 +39,8 @@ # max_30x_redirects :integer(2) default(0), not null # max_transfers :integer(2) default(0), not null # name :string not null -# orig_append_headers_reply :string is an Array -# orig_append_headers_req :string +# orig_append_headers_reply :string default([]), not null, is an Array +# orig_append_headers_req :string default([]), not null, is an Array # orig_force_outbound_proxy :boolean default(FALSE), not null # orig_next_hop :string # orig_outbound_proxy :string @@ -82,7 +82,7 @@ # sst_session_expires :integer(4) default(50) # suppress_early_media :boolean default(FALSE), not null # symmetric_rtp_nonstop :boolean default(FALSE), not null -# term_append_headers_req :string +# term_append_headers_req :string default([]), not null, is an Array # term_force_outbound_proxy :boolean default(FALSE), not null # term_next_hop :string # term_next_hop_for_replies :boolean default(FALSE), not null @@ -217,8 +217,9 @@ dst_rewrite_result { nil } term_next_hop { nil } orig_next_hop { nil } - orig_append_headers_req { nil } - term_append_headers_req { nil } + orig_append_headers_req { [] } + orig_append_headers_reply { [] } + term_append_headers_req { [] } dialog_nat_handling { true } orig_force_outbound_proxy { false } orig_use_outbound_proxy { false } diff --git a/spec/models/gateway_spec.rb b/spec/models/gateway_spec.rb index 1eb364ae6..d8f4ca63a 100644 --- a/spec/models/gateway_spec.rb +++ b/spec/models/gateway_spec.rb @@ -39,8 +39,8 @@ # max_30x_redirects :integer(2) default(0), not null # max_transfers :integer(2) default(0), not null # name :string not null -# orig_append_headers_reply :string is an Array -# orig_append_headers_req :string +# orig_append_headers_reply :string default([]), not null, is an Array +# orig_append_headers_req :string default([]), not null, is an Array # orig_force_outbound_proxy :boolean default(FALSE), not null # orig_next_hop :string # orig_outbound_proxy :string @@ -82,7 +82,7 @@ # sst_session_expires :integer(4) default(50) # suppress_early_media :boolean default(FALSE), not null # symmetric_rtp_nonstop :boolean default(FALSE), not null -# term_append_headers_req :string +# term_append_headers_req :string default([]), not null, is an Array # term_force_outbound_proxy :boolean default(FALSE), not null # term_next_hop :string # term_next_hop_for_replies :boolean default(FALSE), not null diff --git a/spec/requests/api/rest/admin/gateways_spec.rb b/spec/requests/api/rest/admin/gateways_spec.rb index 408fd06b4..89de27bce 100644 --- a/spec/requests/api/rest/admin/gateways_spec.rb +++ b/spec/requests/api/rest/admin/gateways_spec.rb @@ -501,6 +501,8 @@ 'term-next-hop-for-replies': gateway.term_next_hop_for_replies, 'term-next-hop': gateway.term_next_hop, 'term-append-headers-req': gateway.term_append_headers_req, + 'orig-append-headers-req': gateway.orig_append_headers_req, + 'orig-append-headers-reply': gateway.orig_append_headers_reply, 'sdp-alines-filter-list': gateway.sdp_alines_filter_list, 'ringing-timeout': gateway.ringing_timeout, 'relay-options': gateway.relay_options,