File Coverage

blib/lib/Net/DRI.pm
Criterion Covered Total %
statement 143 183 78.1
branch 43 92 46.7
condition 10 24 41.6
subroutine 22 30 73.3
pod 1 14 7.1
total 219 343 63.8


line stmt bran cond sub pod time code
1             ## Domain Registry Interface, Main entry point
2             ##
3             ## Copyright (c) 2005-2016 Patrick Mevzek . All rights reserved.
4             ##
5             ## This file is part of Net::DRI
6             ##
7             ## Net::DRI is free software; you can redistribute it and/or modify
8             ## it under the terms of the GNU General Public License as published by
9             ## the Free Software Foundation; either version 2 of the License, or
10             ## (at your option) any later version.
11             ##
12             ## See the LICENSE file that comes with this distribution for more details.
13             ####################################################################################################
14              
15             package Net::DRI;
16              
17 75     75   122556 use strict;
  75         81  
  75         3266  
18 75     75   1432 use warnings;
  75         68  
  75         1359  
19              
20 75     75   22593 use Net::DRI::Cache;
  75         156  
  75         367  
21 75     75   31141 use Net::DRI::Registry;
  75         115  
  75         346  
22 75     75   1990 use Net::DRI::Util;
  75         83  
  75         1155  
23 75     75   229 use Net::DRI::Exception;
  75         76  
  75         1201  
24              
25 75     75   214 use base qw(Class::Accessor::Chained::Fast Net::DRI::BaseClass);
  75         70  
  75         96999  
26             __PACKAGE__->mk_ro_accessors(qw/trid_factory logging cache/);
27              
28             our $AUTOLOAD;
29             our $VERSION='0.96_08';
30              
31             =pod
32              
33             =head1 NAME
34              
35             Net::DRI - Interface to Domain Name Registries/Registrars/Resellers
36              
37             =head1 VERSION
38              
39             This documentation refers to Net::DRI version 0.96_08
40              
41             =head1 SYNOPSIS
42              
43             use Net::DRI;
44             my $dri=Net::DRI->new({ cache_ttl => 10, trid_factory => ..., logging => .... });
45              
46             ... various operations ...
47              
48             $dri->end();
49              
50             =head1 DESCRIPTION
51              
52             Net::DRI is a Perl library to access services offered by domain name
53             providers, such as registries or registrars. DRI stands for
54             Domain Registration Interface and it aims to be
55             for domain name registries/registrars/resellers what DBI is for databases:
56             an abstraction over multiple providers, with multiple policies, transports
57             and protocols all used through a uniform API.
58              
59             It is an object-oriented framework implementing RRP (RFC 2832/3632),
60             EPP (core EPP in RFC 5730/5731/5732/5733/5734 aka STD69, extensions in
61             RFC 3915/4114/4310/5076 and various extensions of ccTLDs/gTLDs
62             - currently more than 60 TLDs are directly supported with extensions),
63             RRI (.DE registration protocol), Whois, DAS (Domain Availability Service used by .BE, .EU, .AU, .NL),
64             IRIS (RFC3981) DCHK (RFC5144) over LWZ (RFC4993) for .DE currently and XCP (RFC4992),
65             .FR/.RE email and webservices interface, and resellers interface of some registrars
66             (Gandi, OpenSRS, etc.).
67             It has transports for connecting with UDP/TCP/TLS, HTTP/HTTPS,
68             Web Services (XML-RPC and SOAP with/without WSDL),
69             or SMTP-based registries/registrars.
70              
71             It is not limited to handling of domain names, it can be easily extended.
72             For example, it supports ENUM registrations and validations, or DNSSEC provisioning.
73              
74             A shell is included for easy prototyping and debugging, see L.
75             Caching and logging features are also included by default.
76              
77             Please see the included README file for full details.
78              
79             =head1 EXAMPLES
80              
81             Please see the C subdirectory of the distribution, it contains various
82             examples. Please also see all unit tests under C, they show all parts of the API.
83              
84             =head1 SUBROUTINES/METHODS
85              
86             After having used Net::DRI (which is the only module you should need to C from
87             this distribution), you create an object as instance of this class,
88             and every operation will be carried through it.
89              
90             =head2 trid_factory()
91              
92             This is an accessor to the trid factory (code reference) used to generate client
93             transaction identificators, that are useful for logging and asynchronous operations.
94              
95             During the C call, a C is initialized to a default safe value
96             (being Net::DRI::Util::create_trid_1).
97              
98             You need to call this method only if you wish to use another function to generate transaction identificators.
99              
100             All other objects (registry profiles and transports)
101             created after that will inherit this value. If you call again C
102             the change will only apply to new objects (registry profiles and transports) created after the change,
103             it will not apply to already existing objects (registry profiles and transports).
104              
105             =head2 logging()
106              
107             This is an accessor to the underlying Logging object. During the C call you can
108             provide the object, or just a string ("null", "stderr", "files" or "syslog" which are the
109             current logging modules available in Net::DRI), or a reference to an array
110             with the first parameter a string (same as previously) and the second parameter a reference to
111             an hash with data needed by the logging class used (see for example L).
112              
113             If you want to log the application data (what is exchanged with remote server, such as EPP XML streams),
114             you need to use logging level of 'notice', or higher.
115              
116             =head2 cache()
117              
118             This is an accessor to the underlying Cache object. See L.
119             This object has a C method to access and change the current time to live
120             for cached data.
121              
122             =head1 SUPPORT
123              
124             For now, support questions should be sent to:
125              
126             Enetdri@dotandco.comE
127              
128             Please also see the SUPPORT file in the distribution.
129              
130             =head1 SEE ALSO
131              
132             L
133              
134             =head1 AUTHOR
135              
136             Patrick Mevzek, Enetdri@dotandco.comE
137             and various contributors (see Changes file and web page above)
138              
139             =head1 COPYRIGHT
140              
141             Copyright (c) 2005-2016 Patrick Mevzek .
142             All rights reserved.
143              
144             =head1 LICENSE
145              
146             This program is free software; you can redistribute it and/or modify
147             it under the terms of the GNU General Public License as published by
148             the Free Software Foundation; either version 2 of the License, or
149             (at your option) any later version.
150              
151             See the LICENSE file that comes with this distribution for more details.
152              
153             =cut
154              
155             ####################################################################################################
156              
157             sub new
158             {
159 68     68 1 121511 my ($class,$rh)=@_;
160              
161             my $self={ cache => Net::DRI::Cache->new(Net::DRI::Util::has_key($rh,'cache_ttl') ? $rh->{cache_ttl} : 0),
162             current_registry => undef, ## registry name (key of following hash)
163             registries => {}, ## registry name => Net::DRI::Registry object
164             tlds => {}, ## tld => [ registries name ]
165             time_created => time(),
166 68 100 66     383 trid_factory => (Net::DRI::Util::has_key($rh,'trid_factory') && ref $rh->{trid_factory} eq 'CODE')? $rh->{trid_factory} : \&Net::DRI::Util::create_trid_1,
    100          
167             };
168              
169 68         116 my ($logname,@logdata);
170 68 100       185 if (Net::DRI::Util::has_key($rh,'logging'))
171             {
172 5 50       22 ($logname,@logdata)=ref $rh->{logging} eq 'ARRAY' ? @{$rh->{logging}} : ($rh->{logging});
  0         0  
173             } else
174             {
175 63         141 $logname='null';
176             }
177 68 50       253 if ($logname !~ s/^\+//) { $logname='Net::DRI::Logging::'.ucfirst($logname); }
  68         222  
178 68         247 Net::DRI::Util::load_module($logname,'DRI');
179 68         489 $self->{logging}=$logname->new(@logdata);
180              
181 68         177 bless($self,$class);
182 68         401 $self->logging()->setup_channel(__PACKAGE__,'core');
183 68         523 $self->log_output('notice','core','Successfully created Net::DRI object with logging='.$logname);
184 68         146 return $self;
185             }
186              
187             sub add_current_registry
188             {
189 0     0 0 0 my ($self,@p)=@_;
190 0         0 $self->add_registry(@p);
191 0         0 $self->target($self->{last_registry});
192 0         0 return $self;
193             }
194              
195             sub add_registry
196             {
197 68     68 0 213 my ($self,$reg,@data)=@_;
198 68 50       240 Net::DRI::Exception::usererr_insufficient_parameters('add_registry needs a registry name') unless Net::DRI::Util::all_valid($reg);
199 68 50       295 $reg='Net::DRI::DRD::'.$reg unless $reg=~m/^\+/;
200 68         215 Net::DRI::Util::load_module($reg,'DRI');
201              
202 66         397 my $drd=$reg->new(@data);
203 66 50 33     456 Net::DRI::Exception->die(1,'DRI',9,'Failed to initialize registry '.$reg) unless ($drd && ref $drd);
204              
205 66 50       474 Net::DRI::Exception::method_not_implemented('name',$reg) unless $drd->can('name');
206 66         221 my $regname=$drd->name();
207 66 50       288 Net::DRI::Exception->die(1,'DRI',10,'No dot allowed in registry name: '.$regname) unless index($regname,'.') == -1;
208 66 50       253 Net::DRI::Exception->die(1,'DRI',11,'New registry name already in use') if exists $self->{registries}->{$regname};
209              
210 66         637 my $ndr=Net::DRI::Registry->new($regname,$drd,$self->{cache},$self->{trid_factory},$self->{logging});
211 66 50       281 Net::DRI::Exception::method_not_implemented('tlds',$reg) unless $drd->can('tlds');
212 66         210 foreach my $tld ($drd->tlds())
213             {
214 529         491 $tld=lc($tld);
215 529 50       1151 $self->{tlds}->{$tld}=[] unless exists $self->{tlds}->{$tld};
216 529         385 push @{$self->{tlds}->{$tld}},$regname;
  529         1129  
217             }
218              
219 66         404 $self->log_output('notice','core','Successfully added registry "'.$regname.'"');
220 66         157 $self->{registries}->{$regname}=$ndr;
221 66         244 $self->{last_registry}=$regname;
222 66         162 return $self;
223             }
224              
225             sub del_registry
226             {
227 0     0 0 0 my ($self,$name)=@_;
228 0 0       0 if (defined $name)
229             {
230 0 0       0 err_registry_name_does_not_exist($name) unless exists $self->{registries}->{$name};
231             } else
232             {
233 0 0       0 err_no_current_registry() unless defined $self->{current_registry};
234 0         0 $name=$self->{current_registry};
235             }
236 0         0 $self->{registries}->{$name}->end();
237 0         0 delete($self->{registries}->{$name});
238 0 0       0 $self->{current_registry}=undef if $self->{current_registry} eq $name;
239 0         0 $self->log_output('notice','core','Successfully deleted registry "'.$name.'"');
240 0         0 return $self;
241             }
242              
243             ####################################################################################################
244              
245 0     0 0 0 sub err_no_current_registry { Net::DRI::Exception->die(0,'DRI',1,'No current registry available'); } ## no critic (Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn)
246 0     0 0 0 sub err_registry_name_does_not_exist { Net::DRI::Exception->die(0,'DRI',2,'Registry name '.$_[0].' does not exist'); } ## no critic (Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn)
247              
248             ####################################################################################################
249             ## Accessor functions
250              
251 0     0 0 0 sub available_registries { my ($self)=@_; my @r=sort { $a cmp $b } keys %{$self->{registries}}; return @r; }
  0         0  
  0         0  
  0         0  
  0         0  
252             sub available_registries_profiles
253             {
254 0     0 0 0 my ($self,$full)=@_;
255 0         0 my %r;
256 0         0 foreach my $reg (keys(%{$self->{registries}}))
  0         0  
257             {
258 0         0 $r{$reg}=[ $self->{registries}->{$reg}->available_profiles($full) ];
259             }
260 0         0 return \%r;
261             }
262 108     108 0 235 sub registry_name { return shift->{current_registry}; }
263              
264             sub registry
265             {
266 108     108 0 149 my ($self)=@_;
267 108         319 my $regname=$self->registry_name();
268 108 50 33     553 err_no_current_registry() unless (defined($regname) && $regname);
269 108 50       297 err_registry_name_does_not_exist($regname) unless (exists($self->{registries}->{$regname}));
270 108         160 my $ndr=$self->{registries}->{$regname};
271 108 50       460 return wantarray? ($regname,$ndr) : $ndr;
272             }
273              
274             sub tld2reg
275             {
276 12     12 0 20 my ($self,$tld)=@_;
277 12 50 33     64 return unless defined($tld) && $tld;
278 12         24 $tld=lc($tld);
279 12 50       71 $tld=$1 if ($tld=~m/\.([a-z0-9]+)$/);
280 12 50       57 return unless exists($self->{tlds}->{$tld});
281 12         17 my @t=@{$self->{tlds}->{$tld}};
  12         35  
282 12         28 return @t;
283             }
284              
285             sub installed_registries
286             {
287 0     0 0 0 return qw/AdamsNames AERO AFNIC AG ARNES ASIA AT AU BE BIZ BookMyName BR BZ CAT CentralNic CIRA CoCCA COOP COZA CZ DENIC EURid Gandi GL HN ICMRegistry ID IENUMAT IM INFO IRegistry ISPAPI IT LC LU ME MN MOBI NAME Nominet NO NU OpenSRS ORG OVH PL PRO PT SC SE SIDN SO SWITCH TCI Telnic TRAVEL UPU US VC VNDS WS/;
288             }
289              
290             ####################################################################################################
291              
292             sub target
293             {
294 66     66 0 158 my ($self,$driver,$profile)=@_;
295              
296             ## Try to convert if given a domain name or a tld instead of a driver's name
297 66 100 66     493 if (defined $driver && ! exists $self->{registries}->{$driver})
298             {
299 12         54 my @t=$self->tld2reg($driver);
300 12 50       43 Net::DRI::Exception->die(0,'DRI',7,'Registry not found for domain name/TLD '.$driver) unless (@t==1);
301 12         21 $driver=$t[0];
302             }
303              
304 66 50       231 $driver=$self->registry_name() unless defined $driver;
305 66 50 33     445 err_registry_name_does_not_exist($driver) unless defined $driver && $driver;
306              
307 66 50       345 if (defined $profile)
308             {
309 0         0 $self->{registries}->{$driver}->target($profile);
310             }
311              
312 66         127 $self->{current_registry}=$driver;
313 66         252 return $self;
314             }
315              
316             ####################################################################################################
317             ## The meat of everything
318             ## See Cookbook, page 468
319             sub AUTOLOAD
320             {
321 108     108   716 my ($self,@args)=@_;
322 108         155 my $attr=$AUTOLOAD;
323 108         587 $attr=~s/.*:://;
324 108 50       492 return unless $attr=~m/[^A-Z]/; ## skip DESTROY and all-cap methods
325              
326 108         295 my ($name,$ndr)=$self->registry();
327 108 50 33     652 Net::DRI::Exception::method_not_implemented($attr,$ndr) unless ref $ndr && $ndr->can($attr);
328 108         653 $self->log_output('debug','core','Calling '.$attr.' from Net::DRI');
329 108         556 return $ndr->$attr(@args); ## is goto beter here ?
330             }
331              
332             sub end
333             {
334 68     68 0 118 my $self=shift;
335 68         116 while(my ($name,$v)=each(%{$self->{registries}}))
  134         606  
336             {
337 66 50 33     416 $v->end() if (ref($v) && $v->can('end'));
338 66         397 $self->log_output('notice','core','Successfully ended registry "'.$name.'"');
339 66         160 $v={};
340             }
341 68         157 $self->{tlds}={};
342 68         397 $self->{registries}={};
343 68         858 $self->{current_registry}=undef;
344 68 50       239 if (defined $self->{logging})
345             {
346 68         228 $self->log_output('notice','core','Successfully ended Net::DRI object');
347 68         113 $self->{logging}=undef;
348             }
349              
350 68         1056 return 1; ## this makes it easy to test if everything before was ok or not, if we are inside an eval {} and $dri->end() is the last operation inside the eval block
351             }
352              
353 68     68   1195 sub DESTROY { my $self=shift; return $self->end(); }
  68         242  
354              
355             ####################################################################################################
356              
357             package Net::DRI::TrapExceptions; ## no critic (Modules::ProhibitMultiplePackages)
358              
359 75     75   358 use base qw/Net::DRI/;
  75         90  
  75         26525  
360              
361             our $AUTOLOAD;
362              
363             ## Some methods may die in Net::DRI, we specifically trap them
364 57 100   57   438 sub add_registry { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::add_registry(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  57 50       78  
  57         76  
  57         292  
  55         106  
  57         251  
  2         13  
365 0 0   0   0 sub del_registry { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::del_registry(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  0 0       0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
366 93 50   93   133 sub registry { my ($self,@p)=@_; my @r; my $ok=eval { @r=$self->SUPER::registry(@p); 1; }; if ($ok) { return wantarray ? @r : $r[0]; } die(ref $@ ? $@->as_string() : $@); }
  93 50       109  
  93 0       104  
  93         321  
  93         142  
  93         213  
  93         325  
  0         0  
367 55 50   55   264 sub target { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::target(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  55 0       72  
  55         72  
  55         349  
  55         116  
  55         819  
  0         0  
368 57 50   57   121 sub end { my ($self,@p)=@_; my $r; my $ok=eval { $r=$self->SUPER::end(@p); 1; }; return $r if $ok; die(ref $@ ? $@->as_string() : $@); }
  57 0       77  
  57         100  
  57         553  
  57         104  
  57         2012  
  0         0  
369              
370             sub AUTOLOAD
371             {
372 93     93   5695 my $self=shift;
373 93         115 my @r;
374 93         151 $Net::DRI::AUTOLOAD=$AUTOLOAD;
375 93         121 my $ok=eval { @r=$self->SUPER::AUTOLOAD(@_); 1; };
  93         365  
  39         55  
376 93 100       249 if (! $ok)
377             {
378 54         92 my $err=$@;
379 54 50       310 die(ref $err ? $err->as_string() : $err);
380             }
381 39 50       136 return wantarray ? @r : $r[0];
382             }
383              
384             ####################################################################################################
385             1;