]> git.ipfire.org Git - thirdparty/collectd.git/commitdiff
Collectd::Unixsock: Make code robust against socket errors and disconnections 3083/head
authorGuillem Jover <gjover@sipwise.com>
Fri, 7 Apr 2017 14:45:23 +0000 (16:45 +0200)
committerGuillem Jover <gjover@sipwise.com>
Mon, 18 Feb 2019 12:23:54 +0000 (13:23 +0100)
We should check the errors on socket operations, and in case of EPIPE,
which happens on socket disconnection, such as when the server gets
restarted, we should try to reconnect and retry the last operation
to avoid losing data.

bindings/perl/lib/Collectd/Unixsock.pm

index 4ec7993d0986e35c56eb0bcc0e4b351d9e3a5e89..28dbd57e6a9247d7645b7569ac418d0d12b74fcb 100644 (file)
@@ -57,6 +57,7 @@ use strict;
 use warnings;
 
 use Carp qw(cluck confess carp croak);
+use POSIX;
 use IO::Socket::UNIX;
 use Scalar::Util qw( looks_like_number );
 
@@ -146,6 +147,24 @@ sub _escape_argument
        return "\"$arg\"";
 }
 
+# Handle socket errors.
+sub _socket_error {
+       my ($self, $where) = @_;
+
+       # If the peer has reset the connection, try to reconnect,
+       # otherwise fail.
+       if ($! == EPIPE) {
+               _debug "^^ error on $where: $!; reconnecting\n";
+               $self->destroy;
+               $self->{sock} = _create_socket ($self->{path}) or return 1;
+               return;
+       } else {
+               carp ("error on $where: $!; aborting action\n");
+               $self->{error} = $!;
+               return 1;
+       }
+}
+
 # Send a command on a socket, including any required argument escaping.
 # Return a single line of result.
 sub _socket_command {
@@ -160,9 +179,16 @@ sub _socket_command {
                $command .= "\n";
        }
        _debug "-> $command";
-       $fh->print($command);
+       while (not $fh->print($command)) {
+               return if $self->_socket_error ('print');
+               $fh = $self->{sock};
+       }
 
-       my $response = $fh->getline;
+       my $response;
+       while (not defined ($response = $fh->getline)) {
+               return if $self->_socket_error ('getline');
+               $fh = $self->{sock};
+       }
        chomp $response;
        _debug "<- $response\n";
        return $response;
@@ -185,7 +211,11 @@ sub _socket_chat
 
        for (1 .. $nresults)
        {
-               my $entry = $fh->getline;
+               my $entry;
+               while (not defined($entry = $fh->getline)) {
+                       return if $self->_socket_error ('getline');
+                       $fh = $self->{sock};
+               }
                chomp $entry;
                _debug "<- $entry\n";
                $callback->($entry, $cbdata);
@@ -207,9 +237,15 @@ sub _send_message
        warn "Collectd::Unixsock->_send_message(\$msg): message is too long!" if length($msg) > 1024;
        
        _debug "-> $msg";
-       $fh->print($msg);
+       while (not $fh->print($msg)) {
+               return if $self->_socket_error ('print');
+               $fh = $self->{sock};
+       }
 
-       $msg = <$fh>;
+       while (not defined ($msg = <$fh>)) {
+               return if $self->_socket_error ('readline');
+               $fh = $self->{sock};
+       }
        chomp ($msg);
        _debug "<- $msg\n";
 
@@ -396,7 +432,10 @@ sub listval_filter
 
        for (1 .. $nresults)
        {
-               $msg = <$fh>;
+               while (not defined ($msg = <$fh>)) {
+                       return if $self->_socket_error ('readline');
+                       $fh = $self->{sock};
+               }
                chomp $msg;
                _debug "<- $msg\n";
                next unless $msg =~ $pattern;
@@ -438,7 +477,10 @@ sub listval
 
        for (1 .. $nresults)
        {
-               $msg = <$fh>;
+               while (not defined ($msg = <$fh>)) {
+                       return if $self->_socket_error ('readline');
+                       $fh = $self->{sock};
+               }
                chomp $msg;
                _debug "<- $msg\n";