about summary refs log tree commit
diff options
context:
space:
mode:
authorDavid Golden <xdg@xdg.me>2015-12-25 20:44:44 -0500
committerDavid Golden <xdg@xdg.me>2015-12-25 22:08:23 -0500
commit852982580b27fdc9e90d03215913b6652dccdfa9 (patch)
tree6444354d19005487d15f6991a6fdd5a3325a9abb
parente73fbd3e36de3699c5caa22b20b65d1c553bfa6e (diff)
downloadperl-libnet-852982580b27fdc9e90d03215913b6652dccdfa9.tar.gz
Refactor syswrite with timeout
-rw-r--r--lib/Net/Cmd.pm109
1 files changed, 57 insertions, 52 deletions
diff --git a/lib/Net/Cmd.pm b/lib/Net/Cmd.pm
index e9d0d25..bd4857b 100644
--- a/lib/Net/Cmd.pm
+++ b/lib/Net/Cmd.pm
@@ -18,6 +18,7 @@ use warnings;
 use Carp;
 use Exporter;
 use Symbol 'gensym';
+use Errno 'EINTR';
 
 BEGIN {
   if ($^O eq 'os390') {
@@ -189,7 +190,57 @@ sub set_status {
   1;
 }
 
+sub _syswrite_with_timeout {
+  my $cmd = shift;
+  my $line = shift;
+
+  my $len    = length($line);
+  my $offset = 0;
+  my $win    = "";
+  vec($win, fileno($cmd), 1) = 1;
+  my $timeout = $cmd->timeout || undef;
+  my $initial = time;
+  my $pending = $timeout;
+
+  local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
+
+  while ($len) {
+    my $wout;
+    my $nfound = select(undef, $wout = $win, undef, $pending);
+    if ((defined $nfound and $nfound > 0) or -f $cmd)    # -f for testing on win32
+    {
+      my $w = syswrite($cmd, $line, $len, $offset);
+      if (! defined($w) ) {
+        my $err = $!;
+        $cmd->close;
+        $cmd->_set_status_closed($err);
+        return;
+      }
+      $len -= $w;
+      $offset += $w;
+    }
+    elsif ($nfound == -1) {
+      if ( $! == EINTR ) {
+        if ( defined($timeout) ) {
+          redo if ($pending = $timeout - ( time - $initial ) ) > 0;
+          $cmd->_set_status_timeout;
+          return;
+        }
+        redo;
+      }
+      my $err = $!;
+      $cmd->close;
+      $cmd->_set_status_closed($err);
+      return;
+    }
+    else {
+      $cmd->_set_status_timeout;
+      return;
+    }
+  }
 
+  return 1;
+}
 
 sub _set_status_timeout {
   my $cmd = shift;
@@ -201,11 +252,12 @@ sub _set_status_timeout {
 
 sub _set_status_closed {
   my $cmd = shift;
+  my $err = shift;
   my $pkg = ref($cmd) || $cmd;
 
   $cmd->set_status($cmd->DEF_REPLY_CODE, "[$pkg] Connection closed");
   carp(ref($cmd) . ": " . (caller(1))[3]
-    . "(): unexpected EOF on command channel: $!") if $cmd->debug;
+    . "(): unexpected EOF on command channel: $err") if $cmd->debug;
 }
 
 sub _is_closed {
@@ -463,33 +515,8 @@ sub datasend {
 
   ${*$cmd}{'net_cmd_last_ch'} = substr($line, -1, 1);
 
-  my $len    = length($line);
-  my $offset = 0;
-  my $win    = "";
-  vec($win, fileno($cmd), 1) = 1;
-  my $timeout = $cmd->timeout || undef;
-
-  local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
-
-  while ($len) {
-    my $wout;
-    my $s = select(undef, $wout = $win, undef, $timeout);
-    if ((defined $s and $s > 0) or -f $cmd)    # -f for testing on win32
-    {
-      my $w = syswrite($cmd, $line, $len, $offset);
-      unless (defined($w) && $w == $len) {
-        $cmd->close;
-        $cmd->_set_status_closed;
-        return;
-      }
-      $len -= $w;
-      $offset += $w;
-    }
-    else {
-      $cmd->_set_status_timeout;
-      return;
-    }
-  }
+  $cmd->_syswrite_with_timeout($line)
+    or return;
 
   1;
 }
@@ -511,30 +538,8 @@ sub rawdatasend {
     print STDERR $b, join("\n$b", split(/\n/, $line)), "\n";
   }
 
-  my $len    = length($line);
-  my $offset = 0;
-  my $win    = "";
-  vec($win, fileno($cmd), 1) = 1;
-  my $timeout = $cmd->timeout || undef;
-
-  local $SIG{PIPE} = 'IGNORE' unless $^O eq 'MacOS';
-  while ($len) {
-    my $wout;
-    if (select(undef, $wout = $win, undef, $timeout) > 0) {
-      my $w = syswrite($cmd, $line, $len, $offset);
-      unless (defined($w) && $w == $len) {
-        $cmd->close;
-        $cmd->_set_status_closed;
-        return;
-      }
-      $len -= $w;
-      $offset += $w;
-    }
-    else {
-      $cmd->_set_status_timeout;
-      return;
-    }
-  }
+  $cmd->_syswrite_with_timeout($line)
+    or return;
 
   1;
 }