The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Build.PL 03
Changes 09
MANIFEST 70
META.json 69
META.yml 45
README.md 05
lib/Net/APNs/Extended/Base.pm 1734
lib/Net/APNs/Extended.pm 410
minil.toml 01
t/05_retrieve_error.t 140
t/06_constants.t 01
t/base/02_accessors.t 01
xt/02_pod.t 60
xt/03_pod-coverage.t 110
xt/04_perlcritic.t 80
xt/05_script-shebang.t 190
xt/07_minimum_version.t 40
xt/08_cpan_meta.t 50
xt/perlcriticrc 30
19 files changed (This is a version diff) 10878
@@ -29,9 +29,12 @@ my %args = (
 
     script_files => [glob('script/*'), glob('bin/*')],
     c_source     => [qw()],
+    PL_files => {},
 
     test_files           => ((-d '.git' || $ENV{RELEASE_TESTING}) && -d 'xt') ? 't/ xt/' : 't/',
     recursive_test_files => 1,
+
+    
 );
 if (-d 'share') {
     $args{share_dir} = 'share';
@@ -1,5 +1,14 @@
 Revision history for Perl extension Net::APNs::Extended
 
+0.10 2014-02-25T12:23:28Z
+    - Added error status code `SHUTDOWN`
+
+0.09 2014-02-25T11:00:12Z
+    - Added write_timeout option
+
+0.08 2014-02-25T10:47:15Z
+    - Fixed error message from inet_aton
+
 0.07 2013-07-27T09:53:15Z
     - Fixed test for 5.18.0 (syohex++)
 
@@ -21,12 +21,5 @@ t/base/02_accessors.t
 t/base/03_hostname.t
 t/feedback/01_new.t
 t/feedback/02_retrive_feedback.t
-xt/02_pod.t
-xt/03_pod-coverage.t
-xt/04_perlcritic.t
-xt/05_script-shebang.t
-xt/07_minimum_version.t
-xt/08_cpan_meta.t
-xt/perlcriticrc
 META.yml
 MANIFEST
\ No newline at end of file
@@ -4,8 +4,10 @@
       "xaicron <xaicron {@} cpan.org>"
    ],
    "dynamic_config" : 0,
-   "generated_by" : "Minilla/v0.5.6",
-   "license" : "perl_5",
+   "generated_by" : "Minilla/v0.11.0",
+   "license" : [
+      "perl_5"
+   ],
    "meta-spec" : {
       "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
       "version" : "2"
@@ -19,7 +21,8 @@
          "share",
          "eg",
          "examples",
-         "author"
+         "author",
+         "builder"
       ]
    },
    "prereqs" : {
@@ -57,7 +60,7 @@
    "provides" : {
       "Net::APNs::Extended" : {
          "file" : "lib/Net/APNs/Extended.pm",
-         "version" : "0.07"
+         "version" : "0.10"
       },
       "Net::APNs::Extended::Base" : {
          "file" : "lib/Net/APNs/Extended/Base.pm"
@@ -77,9 +80,9 @@
          "web" : "https://github.com/xaicron/p5-Net-APNs-Extended"
       }
    },
-   "version" : "0.07",
+   "version" : "0.10",
    "x_contributors" : [
       "Syohei YOSHIDA <syohex@gmail.com>",
-      "Yuji Shimada <xaicron@gmail.com>"
+      "xaicron <xaicron@gmail.com>"
    ]
 }
@@ -10,7 +10,7 @@ configure_requires:
   CPAN::Meta::Prereqs: 0
   Module::Build: 0.38
 dynamic_config: 0
-generated_by: 'Minilla/v0.5.6, CPAN::Meta::Converter version 2.131560'
+generated_by: 'Minilla/v0.11.0, CPAN::Meta::Converter version 2.133380'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -25,10 +25,11 @@ no_index:
     - eg
     - examples
     - author
+    - builder
 provides:
   Net::APNs::Extended:
     file: lib/Net/APNs/Extended.pm
-    version: 0.07
+    version: 0.10
   Net::APNs::Extended::Base:
     file: lib/Net/APNs/Extended/Base.pm
   Net::APNs::Extended::Feedback:
@@ -43,7 +44,7 @@ resources:
   bugtracker: https://github.com/xaicron/p5-Net-APNs-Extended/issues
   homepage: https://github.com/xaicron/p5-Net-APNs-Extended
   repository: git://github.com/xaicron/p5-Net-APNs-Extended.git
-version: 0.07
+version: 0.10
 x_contributors:
   - 'Syohei YOSHIDA <syohex@gmail.com>'
-  - 'Yuji Shimada <xaicron@gmail.com>'
+  - 'xaicron <xaicron@gmail.com>'
@@ -1,3 +1,4 @@
+[![Build Status](https://travis-ci.org/xaicron/p5-Net-APNs-Extended.png?branch=master)](https://travis-ci.org/xaicron/p5-Net-APNs-Extended)
 # NAME
 
 Net::APNs::Extended - Client library for APNs that support the extended format.
@@ -62,6 +63,10 @@ Supported arguments are:
 
     Sets read timeout.
 
+- write\_timeout : Num
+
+    Sets write timeout.
+
 ## $apns->send($device\_token, $payload \[, $extra \])
 
 Send notification for APNs.
@@ -27,13 +27,15 @@ __PACKAGE__->mk_accessors(qw[
     key
     key_type
     read_timeout
+    write_timeout
     json
 ]);
 
 my %default = (
-    cert_type    => Net::SSLeay::FILETYPE_PEM(),
-    key_type     => Net::SSLeay::FILETYPE_PEM(),
-    read_timeout => 3,
+    cert_type     => Net::SSLeay::FILETYPE_PEM(),
+    key_type      => Net::SSLeay::FILETYPE_PEM(),
+    read_timeout  => 3,
+    write_timeout => undef,
 );
 
 sub new {
@@ -78,7 +80,7 @@ sub _create_socket {
     socket(my $sock, PF_INET, SOCK_STREAM, 0) or die "can't create socket: $!";
     my $sock_addr = do {
         my $iaddr = inet_aton($self->hostname)
-            or die sprintf "can't create iaddr from %s: %s", $self->hostname, $!;
+            or die sprintf "can't create iaddr from %s", $self->hostname;
         pack_sockaddr_in $self->port, $iaddr or die "can't create sock_addr: $!";
     };
     CORE::connect($sock, $sock_addr) or die "can't connect socket: $!";
@@ -162,42 +164,57 @@ sub _send {
     my $self = shift;
     my $data = \$_[0];
     my ($sock, $ctx, $ssl) = @{$self->_connect};
-    Net::SSLeay::ssl_write_all($ssl, $data) or _die_if_ssl_error("ssl_write_all error: $!");
 
+    return unless $self->_do_select($sock, 'write', $self->write_timeout);
+
+    Net::SSLeay::ssl_write_all($ssl, $data) or _die_if_ssl_error("ssl_write_all error: $!");
     return 1;
 }
 
 sub _read {
     my $self = shift;
+    my ($sock, $ctx, $ssl) = @{$self->_connect};
 
-    my $begin_time = Time::HiRes::time();
-    my $timeout = $self->read_timeout;
+    return unless $self->_do_select($sock, 'read', $self->read_timeout);
 
-    my ($sock, $ctx, $ssl) = @{$self->_connect};
+    my $data = Net::SSLeay::ssl_read_all($ssl) or _die_if_ssl_error("ssl_read_all error: $!");
+    return $data;
+}
+
+sub _do_select {
+    my ($self, $sock, $act, $timeout) = @_;
 
-    my $data;
+    my $begin_time = Time::HiRes::time();
+
+    vec(my $bits = '', fileno($sock), 1) = 1;
     while (1) {
-        vec(my $rin = '', fileno($sock), 1) = 1;
-        my $nfound = select($rin, undef, undef, $timeout);
+        my $nfound;
+        if ($act eq 'read') {
+            $nfound = select my $rout = $bits, undef, undef, $timeout;
+        }
+        else {
+            $nfound = select undef, my $wout = $bits, undef, $timeout;
+        }
         return unless $nfound; # timeout
 
         # returned error
         if ($nfound == -1) {
             if ($! == EINTR) {
                 # can retry
-                $timeout -= ($begin_time - Time::HiRes::time());
+                $timeout -= (Time::HiRes::time() - $begin_time) if defined $timeout;
                 next;
             }
-
-            $self->disconnect;
-            return;
+            else {
+                # other error
+                $self->disconnect;
+                return;
+            }
         }
 
-        $data = Net::SSLeay::ssl_read_all($ssl) or _die_if_ssl_error("ssl_read_all error: $!");
         last;
     }
 
-    return $data;
+    return 1;
 }
 
 sub DESTROY {
@@ -3,7 +3,7 @@ package Net::APNs::Extended;
 use strict;
 use warnings;
 use 5.008_001;
-our $VERSION = '0.07';
+our $VERSION = '0.10';
 
 use parent qw(Exporter Net::APNs::Extended::Base);
 use Carp qw(croak);
@@ -18,6 +18,7 @@ use constant {
     INVALID_TOPIC_SIZE   => 6,
     INVALID_PAYLOAD_SIZE => 7,
     INVALID_TOKEN        => 8,
+    SHUTDOWN             => 10,
     UNKNOWN_ERROR        => 255,
 };
 
@@ -31,6 +32,7 @@ our @EXPORT_OK = qw{
     INVALID_TOPIC_SIZE
     INVALID_PAYLOAD_SIZE
     INVALID_TOKEN
+    SHUTDOWN
     UNKNOWN_ERROR
 };
 our %EXPORT_TAGS = (constants => \@EXPORT_OK);
@@ -92,9 +94,9 @@ sub retrieve_error {
 
     my ($command, $status, $identifier) = unpack 'C C L', $data;
     my $error = {
-        command    => $command    || 8,
-        status     => $status     || PROCESSING_ERROR,
-        identifier => $identifier || 0,
+        command    => $command,
+        status     => $status,
+        identifier => $identifier,
     };
 
     $self->disconnect;
@@ -228,6 +230,10 @@ Sets private key password.
 
 Sets read timeout.
 
+=item write_timeout : Num
+
+Sets write timeout.
+
 =back
 
 =head2 $apns->send($device_token, $payload [, $extra ])
@@ -1 +1,2 @@
 name = "Net-APNs-Extended"
+badges = ["travis"]
@@ -38,18 +38,4 @@ subtest 'backward compatibility' => sub {
     is $guard->call_count($apns, 'disconnect'), 1;
 };
 
-subtest 'broken response' => sub {
-    my $guard = mock_guard $apns => {
-        _read      => sub { '' },
-        disconnect => 1,
-    };
-    my $error = $apns->retrive_error;
-    is_deeply $error, {
-        command    => 8,
-        status     => 1,
-        identifier => 0,
-    };
-    is $guard->call_count($apns, 'disconnect'), 1;
-};
-
 done_testing;
@@ -12,6 +12,7 @@ is INVALID_TOKEN_SIZE, 5;
 is INVALID_TOPIC_SIZE, 6;
 is INVALID_PAYLOAD_SIZE, 7;
 is INVALID_TOKEN, 8;
+is SHUTDOWN, 10;
 is UNKNOWN_ERROR, 255;
 
 done_testing;
@@ -18,6 +18,7 @@ for my $method (qw{
     key
     key_type
     read_timeout
+    write_timeout
     json
 }) {
     ok $apns->$method(1);
@@ -1,6 +0,0 @@
-use strict;
-use warnings;
-use Test::More;
-use Test::Requires { 'Test::Pod' => 1.00 };
-
-all_pod_files_ok();
@@ -1,11 +0,0 @@
-use strict;
-use warnings;
-use Test::More;
-use Test::Requires { 'Test::Pod::Coverage' => 1.04 };
-
-unless ($ENV{TEST_POD_COVERAGE}) {
-    plan skip_all => "\$ENV{TEST_POD_COVERAGE} is not set.";
-    exit;
-}
-
-all_pod_coverage_ok({also_private => [qw(unimport BUILD DEMOLISH)]});
@@ -1,8 +0,0 @@
-use strict;
-use warnings;
-use Test::More;
-use Test::Requires { 'Test::Perl::Critic' => 1.02 };
-
-Test::Perl::Critic->import(-profile => 'xt/perlcriticrc');
-
-all_critic_ok('lib');
@@ -1,19 +0,0 @@
-use strict;
-use warnings;
-use Test::More;
-use Test::Requires 'Test::Script::Shebang';
-use File::Find qw/find/;
-
-my @files;
-for my $dir (qw/bin script/) {
-    next unless -d $dir;
-    find {
-        no_chdir => 1,
-        wanted   => sub { push @files, $_ if -f },
-    }, $dir;
-}
-plan skip_all => 'script not found' unless @files;
-
-check_shebang(@files);
-
-done_testing;
@@ -1,4 +0,0 @@
-use Test::More;
-eval "use Test::MinimumVersion 0.101080";
-plan skip_all => "Test::Minimumversion required for testing perl minimum version" if $@;
-all_minimum_version_from_metayml_ok();
@@ -1,5 +0,0 @@
-use Test::More;
-eval "use Test::CPAN::Meta";
-plan skip_all => "Test::CPAN::Meta required for testing META.yml" if $@;
-plan skip_all => "There is no META.yml" unless -f "META.yml";
-meta_yaml_ok();
@@ -1,3 +0,0 @@
-[TestingAndDebugging::ProhibitNoStrict]
-allow=refs
-[-Subroutines::ProhibitSubroutinePrototypes]