File Coverage

blib/lib/Net/EPP/Client.pm
Criterion Covered Total %
statement 32 105 30.4
branch 0 56 0.0
condition 0 24 0.0
subroutine 9 19 47.3
pod 0 8 0.0
total 41 212 19.3


line stmt bran cond sub pod time code
1             package Net::EPP::Client;
2 1     1   641 use bytes;
  1         18  
  1         5  
3 1     1   446 use Net::EPP::Protocol;
  1         4  
  1         26  
4 1     1   6 use Carp;
  1         2  
  1         49  
5 1     1   507 use IO::Socket;
  1         23985  
  1         3  
6 1     1   1298 use IO::Socket::SSL;
  1         64514  
  1         9  
7 1     1   175 use vars qw($XMLDOM $EPPFRAME);
  1         3  
  1         54  
8 1     1   6 use strict;
  1         3  
  1         22  
9 1     1   5 use warnings;
  1         2  
  1         92  
10              
11             =pod
12              
13             =head1 NAME
14              
15             Net::EPP::Client - a client library for the TCP transport for EPP, the
16             Extensible Provisioning Protocol.
17              
18             =head1 SYNOPSIS
19              
20             #!/usr/bin/perl
21             use Net::EPP::Client;
22             use strict;
23              
24             my $epp = Net::EPP::Client->new(
25             host => 'epp.nic.tld',
26             port => 700,
27             ssl => 1,
28             frames => 1,
29             );
30              
31             my $greeting = $epp->connect;
32              
33             $epp->send_frame('login.xml');
34              
35             my $answer = $epp->get_frame;
36              
37             $epp->send_frame('');
38              
39             my $answer = $epp->get_frame;
40              
41             =head1 DESCRIPTION
42              
43             L defines a TCP based
44             transport model for EPP, and this module implements a client for that model.
45             You can establish and manage EPP connections and send and receive responses
46             ver this connection.
47              
48             C also provides some time-saving features, such as being
49             able to provide request and response frames as C objects.
50              
51             =cut
52              
53             BEGIN {
54 1     1   3 our $XMLDOM = 0;
55 1         3 our $EPPFRAME = 0;
56 1         2 eval {
57 1         746 require XML::LibXML;
58 1         44609 $XMLDOM = 1;
59             };
60 1         3 eval {
61 1         505 require Net::EPP::Frame;
62 1         1156 $EPPFRAME = 1;
63             };
64             }
65              
66             =pod
67              
68             =head1 CONSTRUCTOR
69              
70             my $epp = Net::EPP::Client->new(PARAMS);
71              
72             The constructor method creates a new EPP client object. It accepts a number of
73             parameters:
74              
75             =over
76              
77             =item * host
78              
79             C specifies the computer to connect to. This may be a DNS hostname or
80             an IP address.
81              
82             =item * port
83              
84             C specifies the TCP port to connect to. This is usually 700.
85              
86             =item * ssl
87              
88             If the C parameter is defined, then L will be used to
89             provide an encrypted connection. If not, then a plaintext connection will be
90             created.
91              
92             =item * dom (deprecated)
93              
94             If the C parameter is defined, then all response frames will be returned
95             as L objects.
96              
97             =item * frames
98              
99             If the C parameter is defined, then all response frames will be
100             returned as L objects (actually, L
101             objects reblessed as L objects).
102              
103             =back
104              
105             =cut
106              
107             sub new {
108 0     0 0   my ($package, %params) = @_;
109              
110 0           my $self;
111 0 0         if (defined($params{'sock'})) {
112             $self = {
113             'sock' => $params{'sock'},
114             ssl => 0,
115             'dom' => (defined($params{'dom'}) ? 1 : 0),
116 0 0         'frames' => (defined($params{'frames'}) ? 1 : 0),
    0          
117             }
118             } else {
119 0 0         croak("missing hostname") if (!defined($params{'host'}));
120 0 0         croak("missing port") if (!defined($params{'port'}));
121              
122             $self = {
123             'host' => $params{'host'},
124             'port' => $params{'port'},
125             'ssl' => (defined($params{'ssl'}) ? 1 : 0),
126             'dom' => (defined($params{'dom'}) ? 1 : 0),
127 0 0         'frames' => (defined($params{'frames'}) ? 1 : 0),
    0          
    0          
128             };
129             }
130              
131 0 0         if ($self->{'frames'} == 1) {
    0          
132 0 0         if ($EPPFRAME == 0) {
133 0           croak("Frames requested but Net::EPP::Frame isn't available");
134              
135             } else {
136 0           $self->{'class'} = 'Net::EPP::Frame';
137              
138             }
139              
140             } elsif ($self->{'dom'} == 1) {
141 0 0         if ($XMLDOM == 0) {
142 0           croak("DOM requested but XML::LibXML isn't available");
143              
144             } else {
145 0           $self->{'class'} = 'XML::LibXML::Document';
146              
147             }
148              
149             }
150              
151 0           return bless($self, $package);
152             }
153              
154             =pod
155              
156             =head1 METHODS
157              
158             =head2 Connecting to a server:
159              
160             my $greeting = $epp->connect(%PARAMS);
161              
162             This method establishes the TCP connection. You can use the C<%PARAMS> hash to
163             specify arguments that will be passed on to the constructors for
164             L (such as a timeout) or L (such as
165             certificate information). See the relevant manpage for examples.
166              
167             This method will C if connection fails, so be sure to use C if
168             you want to catch the error.
169              
170             By default, the return value for C will be the EPP EgreetingE
171             frame returned by the server. Please note that the same caveat about blocking
172             applies to this method as to C (see below).
173              
174             If you want to get the greeting yourself, set C<$params{no_greeting}>.
175              
176             =cut
177              
178             sub connect {
179 0     0 0   my ($self, %params) = @_;
180              
181 0 0         if (defined($self->{'sock'})) {
182 0           $self->_connect_unix(%params);
183              
184             } else {
185 0           $self->_connect_tcp(%params);
186              
187             }
188              
189 0 0         return ($params{'no_greeting'} ? 1 : $self->get_frame);
190              
191             }
192              
193             sub _connect_tcp {
194 0     0     my ($self, %params) = @_;
195              
196 0 0         my $SocketClass = ($self->{'ssl'} == 1 ? 'IO::Socket::SSL' : 'IO::Socket::INET');
197              
198             $self->{'connection'} = $SocketClass->new(
199             PeerAddr => $self->{'host'},
200 0           PeerPort => $self->{'port'},
201             Proto => 'tcp',
202             Type => SOCK_STREAM,
203             %params
204             );
205              
206 0 0 0       if (!defined($self->{'connection'}) || ($@ && $@ ne '')) {
      0        
207 0           chomp($@);
208 0           $@ =~ s/^$SocketClass:? ?//;
209 0           croak("Connection to $self->{'host'}:$self->{'port'} failed: $@")
210             };
211              
212 0           return 1;
213             }
214              
215             sub _connect_unix {
216 0     0     my ($self, %params) = @_;
217              
218             $self->{'connection'} = IO::Socket::UNIX->new(
219 0           Peer => $self->{'sock'},
220             Type => SOCK_STREAM,
221             %params
222             );
223              
224 0 0 0       croak("Connection to $self->{'host'}:$self->{'port'} failed: $@") if (!defined($self->{'connection'}) || ($@ && $@ ne ''));
      0        
225              
226 0           return 1;
227              
228             }
229              
230             =pod
231              
232             =head2 Communicating with the server:
233              
234             my $answer = $epp->request($question);
235              
236             This is a simple wrapper around C and C (see below).
237             This method accepts a "question" frame as an argument, sends it to the server,
238             and then returns the next frame the server sends back.
239              
240             =cut
241              
242             sub request {
243 0     0 0   my ($self, $frame) = @_;
244 0 0         return $self->get_frame if ($self->send_frame($frame));
245             }
246              
247             =pod
248              
249             =head2 Getting a frame from the server:
250              
251             my $frame = $epp->get_frame;
252              
253             This method returns an EPP response frame from the server. This may either be a
254             scalar filled with XML, an L object (or an
255             L object), depending on whether you defined the C
256             parameter to the constructor.
257              
258             B: this method will block your program until it receives the
259             full frame from the server. That could be a bad thing for your program, so you
260             might want to consider using the C function to apply a timeout, like
261             so:
262              
263             my $timeout = 10; # ten seconds
264              
265             eval {
266             local $SIG{ALRM} = sub { die "alarm\n" };
267             alarm($timeout);
268             my $frame = $epp->get_frame;
269             alarm(0);
270             };
271              
272             if ($@ ne '') {
273             alarm(0);
274             print "timed out\n";
275             }
276              
277             If the connection to the server closes before the response can be received, or
278             the server returned a mal-formed frame, this method will C.
279              
280             =cut
281              
282             sub get_frame {
283 0     0 0   my $self = shift;
284 0           return $self->get_return_value(Net::EPP::Protocol->get_frame($self->{'connection'}));
285             }
286              
287             sub get_return_value {
288 0     0 0   my ($self, $xml) = @_;
289              
290 0 0         if (!defined($self->{'class'})) {
291 0           return $xml;
292              
293             } else {
294 0           my $document;
295 0           eval { $document = $self->parser->parse_string($xml) };
  0            
296 0 0 0       if (!defined($document) || $@ ne '') {
297 0           chomp($@);
298 0           croak(sprintf("Frame from server wasn't well formed: %s\n\nThe XML looks like this:\n\n%s\n\n", $@, $xml));
299 0           return undef;
300              
301             } else {
302 0           my $class = $self->{'class'};
303 0           return bless($document, $class);
304              
305             }
306             }
307             }
308              
309             =pod
310              
311             =head2 Sending a frame to the server:
312              
313             $epp->send_frame($frame, $wfcheck);
314              
315             This sends a request frame to the server. C<$frame> may be one of:
316              
317             =over
318              
319             =item * a scalar containing XML
320              
321             =item * a scalar containing a filename
322              
323             =item * an L object (or an instance of a subclass)
324              
325             =item * an L object (or an instance of a subclass)
326              
327             =back
328              
329             Unless C<$wfcheck> is false, the first two of these will be checked for
330             well-formedness. If the XML data is broken, then this method will croak.
331              
332             =cut
333              
334             sub send_frame {
335 0     0 0   my ($self, $frame, $wfcheck) = @_;
336              
337 0           my $xml;
338 0 0 0       if (ref($frame) ne '' && ($frame->isa('XML::DOM::Document') || $frame->isa('XML::LibXML::Document'))) {
    0 0        
      0        
339 0           $xml = $frame->toString;
340 0           $wfcheck = 0;
341              
342             } elsif ($frame !~ /
343 0 0         if (!open(FRAME, $frame)) {
344 0           croak("Couldn't open file '$frame' for reading: $!");
345              
346             } else {
347 0           $xml = join('', );
348 0           close(FRAME);
349 0           $wfcheck = 1;
350              
351             }
352              
353             } else {
354 0           $xml = $frame;
355 0 0         $wfcheck = ($wfcheck ? 1 : 0);
356              
357             }
358              
359 0 0         if ($wfcheck == 1) {
360 0           eval { $self->parser->parse_string($xml) };
  0            
361 0 0         if ($@ ne '') {
362 0           chomp($@);
363 0           croak(sprintf("Frame from server wasn't well formed: %s\n\nThe XML looks like this:\n\n%s\n\n", $@, $xml));
364             }
365             }
366              
367 0           return Net::EPP::Protocol->send_frame($self->{'connection'}, $xml);
368             }
369              
370             =pod
371              
372             =head2 Disconnecting from the server:
373              
374             $epp->disconnect;
375              
376             This closes the connection. An EPP server should always close a connection after
377             a ElogoutE frame has been received and acknowledged; this method
378             is provided to allow you to clean up on the client side, or close the
379             connection out of sync with the server.
380              
381             =cut
382              
383             sub disconnect {
384 0     0 0   my $self = shift;
385 0 0         $self->{'connection'}->close if ($self->{'connection'});
386 0           return 1;
387             }
388              
389             sub parser {
390 0     0 0   my $self = shift;
391 0 0         $self->{'parser'} = XML::LibXML->new if (!$self->{'parser'});
392 0           return $self->{'parser'};
393             }
394              
395             1;