File Coverage

blib/lib/Net/EPP/Proxy.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             # Copyright (c) 2010 CentralNic Ltd. All rights reserved. This program is
2             # free software; you can redistribute it and/or modify it under the same
3             # terms as Perl itself.
4             #
5             # $Id: Proxy.pm,v 1.13 2007/12/03 11:44:19 gavin Exp $
6             package Net::EPP::Proxy;
7 1     1   19626 use Carp;
  1         2  
  1         75  
8 1     1   797 use Digest::SHA1 qw(sha1_hex);
  1         7253  
  1         272  
9 1     1   2599 use Net::EPP::Simple;
  0            
  0            
10             use Net::EPP::Protocol;
11             use POSIX qw(strftime);
12             use Time::HiRes qw(time);
13             use XML::LibXML;
14             use bytes;
15             use base qw(Net::Server::Multiplex);
16             use constant EPP_XMLNS => 'urn:ietf:params:xml:ns:epp-1.0';
17             use vars qw($VERSION);
18             use strict;
19              
20             our $VERSION = '0.04';
21              
22             sub new {
23             my $package = shift;
24             my $self = $package->SUPER::new;
25             $self->{epp} = {parser => XML::LibXML->new};
26             bless($self, $package);
27             return $self;
28             }
29              
30             sub init {
31             my ($self, %params) = @_;
32              
33             $self->{epp}->{host} = $params{remote_host};
34             $self->{epp}->{port} = $params{remote_port};
35             $self->{epp}->{ssl} = $params{ssl};
36             $self->{epp}->{timeout} = (int($params{req_timeout}) > 0 ? int($params{req_timeout}) : 5);
37             $self->{epp}->{clid} = $params{clid};
38             $self->{epp}->{pw} = $params{pw};
39             $self->{epp}->{svcs} = $params{svcs};
40             $self->{epp}->{debug} = $params{debug};
41              
42             # connect to the server:
43             my ($code, $msg) = $self->epp_connect;
44              
45             # check the response:
46             if ($code != 1000) {
47             carp('Unable to log into to server using supplied credentials: '.$msg);
48             return undef;
49             }
50              
51             # run the main server loop:
52             return $self->run(%params);
53             }
54              
55             sub epp_connect {
56             my $self = shift;
57              
58             # build our EPP client:
59             $self->{epp}->{client} = Net::EPP::Simple->new(
60             host => $self->{epp}->{host},
61             port => $self->{epp}->{port},
62             user => $self->{epp}->{user},
63             pass => $self->{epp}->{pass},
64             ssl => $self->{epp}->{ssl},
65             timeout => $self->{epp}->{timeout},
66             debug => $self->{epp}->{debug},
67             dom => 1,
68             );
69              
70             if (!$self->{epp}->{client}) {
71             carp("Error connecting: $Net::EPP::Simple::Error");
72             return ($Net::EPP::Simple::Code, "Error connecting: $Net::EPP::Simple::Error");
73             }
74              
75             $self->{epp}->{greeting} = $self->{epp}->{client}->{greeting};
76              
77             return ($Net::EPP::Simple::Code, $Net::EPP::Simple::Message);
78             }
79              
80             # new connection, send the greeting:
81             sub mux_connection {
82             my ($self, $mux, $peer) = @_;
83             print Net::EPP::Protocol->prep_frame($self->{net_server}->{epp}->{greeting}->toString);
84             }
85              
86             # a request frame was received, transmit to remote server and return response to client:
87             sub mux_input {
88             my ($self, $mux, $peer, $input) = @_;
89              
90             my $hdr = substr(${$input}, 0, 4);
91             my $length = unpack('N', $hdr) - 4;
92             my $question = substr(${$input}, 4, $length);
93              
94             my $oldsig = $SIG{PIPE};
95             $SIG{PIPE} = 'IGNORE';
96             my $answer;
97             eval {
98             local $SIG{ALRM} = sub { die("timed out") };
99             alarm($self->{net_server}->{epp}->{timeout});
100             $answer = $self->{net_server}->{epp}->{client}->request($question);
101             alarm(0);
102             };
103             $SIG{PIPE} = $oldsig;
104              
105             # initialise some things:
106             my $err = '';
107             my $fatal = 0;
108              
109             if ($@ ne '') {
110             $err = sprintf('error getting answer from remote server: %s timeout %ds)', $@, $self->{net_server}->{epp}->{timeout});
111              
112             } elsif (length($answer->toString) < 1) {
113             $err = sprintf('error getting answer from remote server: answer was %d bytes long', length($answer));
114              
115             } elsif ($self->get_result_code($answer) =~ /^(2500|2501|2502)$/) {
116             $err = sprintf('session error at remote server (code %d)', $self->get_result_code($answer));
117              
118             }
119              
120             if ($err ne '') {
121             $answer = $self->create_error_frame($question, $err);
122             $self->debug("Fatal error from remote server: $err");
123             $fatal = 1;
124             }
125              
126             # send answer to client:
127             print Net::EPP::Protocol->prep_frame($answer->toString);
128              
129             # clean up:
130             $self->server_close if ($err ne '' && $fatal == 1);
131              
132             # clear the buffer:
133             ${$input} = '';
134              
135             return 1;
136             }
137              
138             sub create_error_frame {
139             my ($self, $question, $err) = @_;
140             my $frame = Net::EPP::Frame::Response->new;
141              
142             my $clTRID;
143             eval {
144             my $doc = $self->{epp}->{parser}->parse_string($question);
145             my $nodes = $doc->getElementsByTagNameNS(EPP_XMLNS, 'clTRID');
146             my $node = $nodes->shift;
147             my $text = ($node->getChildNodes)[0];
148             $clTRID = $text->data;
149             print STDERR $question;
150             };
151              
152             my $msg = $frame->createElement('msg');
153             $msg->appendText($err);
154              
155             $frame->clTRID->appendText($clTRID);
156             $frame->svTRID->appendText(sha1_hex(ref($self).time().$$));
157              
158             $frame->result->setAttribute('code', 2500);
159             $frame->result->appendChild($msg);
160              
161             return $frame;
162             }
163              
164             sub get_result_code {
165             my ($self, $doc) = @_;
166             my $els = $doc->getElementsByTagNameNS(EPP_XMLNS, 'result');
167             if (defined($els)) {
168             my $el = $els->shift;
169             if (defined($el)) {
170             return $el->getAttribute('code');
171             }
172             }
173             return 2400;
174             }
175              
176             sub get_result_message {
177             my ($self, $doc) = @_;
178             my $els = $doc->getElementsByTagNameNS(EPP_XMLNS, 'msg');
179             if (defined($els)) {
180             my $el = $els->shift;
181             if (defined($el)) {
182             my @children = $el->getChildNodes;
183             if (defined($children[0])) {
184             my $txt = $children[0];
185             return $txt->data if (ref($txt) eq 'XML::LibXML::Text');
186             }
187             }
188             }
189             return 'Unknown message';
190             }
191              
192             1;
193              
194             __END__