diff --git a/lib/NGCP/Panel/Controller/API/Interceptions.pm b/lib/NGCP/Panel/Controller/API/Interceptions.pm index 6118b2ecc8..8c31e16159 100644 --- a/lib/NGCP/Panel/Controller/API/Interceptions.pm +++ b/lib/NGCP/Panel/Controller/API/Interceptions.pm @@ -10,6 +10,7 @@ use HTTP::Headers qw(); use HTTP::Status qw(:constants); use MooseX::ClassAttribute qw(class_has); use NGCP::Panel::Utils::DateTime; +use NGCP::Panel::Utils::Interception; use Path::Tiny qw(path); use Safe::Isa qw($_isa); use UUID qw/generate unparse/; @@ -210,9 +211,24 @@ sub POST :Allow { $resource = $self->resnames_to_dbnames($resource); try { $item = $c->model('DB')->resultset('voip_intercept')->create($resource); + my $res = NGCP::Panel::Utils::Interception::request($c, 'POST', undef, { + liid => $resource->{liid}, + uuid => $resource->{uuid}, + number => $resource->{number}, + sip_username => $sub->username, + sip_domain => $sub->domain->domain, + delivery_host => $resource->{x2_host}, + delivery_port => $resource->{x2_port}, + delivery_user => $resource->{x2_user}, + delivery_password => $resource->{x2_password}, + cc_required => $resource->{x3_required}, + cc_delivery_host => $resource->{x3_host}, + cc_delivery_port => $resource->{x3_port}, + }); + die "Failed to populate capture agents\n" unless($res); } catch($e) { $c->log->error("failed to create interception: $e"); # TODO: user, message, trace, ... - $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create interception."); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to create interception"); last; } diff --git a/lib/NGCP/Panel/Controller/API/InterceptionsItem.pm b/lib/NGCP/Panel/Controller/API/InterceptionsItem.pm index 9a9b891267..11c44e64da 100644 --- a/lib/NGCP/Panel/Controller/API/InterceptionsItem.pm +++ b/lib/NGCP/Panel/Controller/API/InterceptionsItem.pm @@ -8,6 +8,7 @@ use HTTP::Status qw(:constants); use MooseX::ClassAttribute qw(class_has); use NGCP::Panel::Utils::DateTime; use NGCP::Panel::Utils::ValidateJSON qw(); +use NGCP::Panel::Utils::Interception; use Path::Tiny qw(path); use Safe::Isa qw($_isa); BEGIN { extends 'Catalyst::Controller::ActionRole'; } @@ -107,6 +108,26 @@ sub PATCH :Allow { $item = $self->update_item($c, $item, $old_resource, $resource, $form); last unless $item; + my ($sub, $reseller) = $self->subres_from_number($c, $resource->{number}); + last unless($sub && $reseller); + + my $res = NGCP::Panel::Utils::Interception::request($c, 'PUT', $item->uuid, { + number => $resource->{number}, + sip_username => $sub->username, + sip_domain => $sub->domain->domain, + delivery_host => $resource->{x2_host}, + delivery_port => $resource->{x2_port}, + delivery_user => $resource->{x2_user}, + delivery_password => $resource->{x2_password}, + cc_required => $resource->{x3_required}, + cc_delivery_host => $resource->{x3_host}, + cc_delivery_port => $resource->{x3_port}, + }); + unless($res) { + $c->log->error("failed to update capture agents"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update capture agents"); + last; + } $guard->commit; @@ -147,6 +168,26 @@ sub PUT :Allow { $item = $self->update_item($c, $item, $old_resource, $resource, $form); last unless $item; + my ($sub, $reseller) = $self->subres_from_number($c, $resource->{number}); + last unless($sub && $reseller); + + my $res = NGCP::Panel::Utils::Interception::request($c, 'PUT', $item->uuid, { + number => $resource->{number}, + sip_username => $sub->username, + sip_domain => $sub->domain->domain, + delivery_host => $resource->{x2_host}, + delivery_port => $resource->{x2_port}, + delivery_user => $resource->{x2_user}, + delivery_password => $resource->{x2_password}, + cc_required => $resource->{x3_required}, + cc_delivery_host => $resource->{x3_host}, + cc_delivery_port => $resource->{x3_port}, + }); + unless($res) { + $c->log->error("failed to update capture agents"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update capture agents"); + last; + } $guard->commit; @@ -173,6 +214,7 @@ sub DELETE :Allow { my $guard = $c->model('DB')->txn_scope_guard; { my $item = $self->item_by_id($c, $id); + my $uuid = $item->uuid; last unless $self->resource_exists($c, interception => $item); $item->update({ deleted => 1, @@ -190,6 +232,12 @@ sub DELETE :Allow { sip_domain => undef, uuid => undef, }); + my $res = NGCP::Panel::Utils::Interception::request($c, 'DELETE', $uuid); + unless($res) { + $c->log->error("failed to update capture agents"); + $self->error($c, HTTP_INTERNAL_SERVER_ERROR, "Failed to update capture agents"); + last; + } $guard->commit; diff --git a/lib/NGCP/Panel/Role/API/Interceptions.pm b/lib/NGCP/Panel/Role/API/Interceptions.pm index 86b7c8aef1..6a4afe6615 100644 --- a/lib/NGCP/Panel/Role/API/Interceptions.pm +++ b/lib/NGCP/Panel/Role/API/Interceptions.pm @@ -129,29 +129,17 @@ sub update_item { resource => $resource, ); - my $num_rs = $c->model('DB')->resultset('voip_numbers')->search( - \[ 'concat(cc,ac,sn) = ?', [ {} => $resource->{number} ]] - ); - unless($num_rs->first) { - $c->log->error("invalid number '$$resource{number}'"); - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number does not exist"); - last; - } - $resource->{reseller_id} = $num_rs->first->reseller_id; - - my $sub = $num_rs->first->subscriber; - unless($sub) { - $c->log->error("invalid number '$$resource{number}', not assigned to any subscriber"); - $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number is not active"); - last; - } + my ($sub, $reseller) = $self->subres_from_number($c, $resource->{number}); + return unless($sub && $reseller); + + $resource->{reseller_id} = $reseller->id; $resource->{sip_username} = $sub->username; $resource->{sip_domain} = $sub->domain->domain; if($resource->{x3_required} && (!defined $resource->{x3_host} || !defined $resource->{x3_port})) { $c->log->error("Missing parameter 'x3_host' or 'x3_port' with 'x3_required' activated"); $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Missing parameter 'x3_host' or 'x3_port' with 'x3_required' activated"); - last; + return; } $resource->{x3_host} = $resource->{x3_port} = undef unless($resource->{x3_required}); @@ -163,5 +151,32 @@ sub update_item { return $item; } +sub subres_from_number { + my ($self, $c, $number) = @_; + my $num_rs = $c->model('DB')->resultset('voip_numbers')->search( + \[ 'concat(cc,ac,sn) = ?', [ {} => $number ]] + ); + unless($num_rs->first) { + $c->log->error("invalid number '$number'"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number does not exist"); + return; + } + my $sub = $num_rs->first->subscriber; + unless($sub) { + $c->log->error("invalid number '$number', not assigned to any subscriber"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number is not active"); + return; + } + + my $res = $num_rs->first->reseller; + unless($res) { + $c->log->error("invalid number '$number', not assigned to any reseller"); + $self->error($c, HTTP_UNPROCESSABLE_ENTITY, "Number is not active"); + return; + } + + return ($sub, $res); +} + 1; # vim: set tabstop=4 expandtab: diff --git a/lib/NGCP/Panel/Utils/Interception.pm b/lib/NGCP/Panel/Utils/Interception.pm new file mode 100644 index 0000000000..9b8c284607 --- /dev/null +++ b/lib/NGCP/Panel/Utils/Interception.pm @@ -0,0 +1,84 @@ +package NGCP::Panel::Utils::Interception; + +use Data::Dumper; +use LWP::UserAgent; +use TryCatch; + +sub request { + my ($c, $method, $uuid, $data) = @_; + + my $a = _init($c); + return unless($a); + + return unless($method eq 'POST' || $method eq 'PUT' || $method eq 'DELETE'); + + my @agents = @{ $a->{ua} }; + my @urls = @{ $a->{url} }; + for(my $i = 0; $i < scalar(@agents); ++$i) { + my $ua = $agents[$i]; + my $url = $urls[$i]; + if($method eq 'PUT' or $method eq 'DELETE') { + return unless($uuid); + $url .= '/'.$uuid; + } + $c->log->debug("performing $method for interception at $url"); + try { + _request($c, $ua, $url, $method, $data); + } catch($e) { + # skip errors + } + } + return 1; +} + +sub _request { + my ($c, $ua, $url, $method, $data) = @_; + + my $req = HTTP::Request->new($method => $url); + if($data) { + $req->content_type('application/json'); + $req->content($jdata); + } + my $res = $ua->request($req); + if($res->is_success) { + return 1; + } else { + $c->log->error("Failed to do $method on $url: " . $res->status_line); + return; + } +} + +sub _init { + my ($c) = @_; + + my @ua = (); + my @url = (); + my @cfgs = (); + if(ref $c->config->{intercept}->{agent} eq 'HASH') { + push @cfgs, $c->config->{intercept}->{agent}; + } elsif(ref $c->config->{intercept}->{agent} eq 'ARRAY') { + @cfgs = @{ $c->config->{intercept}->{agent} }; + } + unless(@cfgs) { + $c->log->error("No intercept agents configured in ngcp_panel.conf, rejecting request"); + return; + } + foreach my $cfg(@cfgs) { + my $agent = LWP::UserAgent->new(); + $agent->agent("Sipwise NGCP X1/0.2"); + $agent->timeout(2); + if($cfg->{user} && $cfg->{pass}) { + $agent->credentials( + $cfg->{host}.":".$cfg->{port}, + $cfg->{realm}, + $cfg->{user}, + $cfg->{pass} + ); + } + push @ua, $agent; + push @url, $cfg->{schema}.'://'.$cfg->{host}.':'.$cfg->{port}.$cfg->{url}; + } + return { ua => \@ua, url => \@url }; +} + +1;