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