The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
Build.PL 027
Changes 09
MANIFEST 23
META.json 1830
META.yml 1625
README 12
lib/Net/Frame/Dump/Offline.pm 22
lib/Net/Frame/Dump/Online.pm 22
lib/Net/Frame/Dump/Online2.pm 4484
lib/Net/Frame/Dump/Writer.pm 22
lib/Net/Frame/Dump.pm 55
11 files changed (This is a version diff) 92191
@@ -0,0 +1,27 @@
+#
+# $Id: Build.PL 363 2014-11-30 11:23:39Z gomor $
+#
+use strict;
+use warnings;
+
+use Module::Build;
+
+my $builder = Module::Build->new(
+   module_name => 'Net::Frame::Dump',
+   license => 'artistic',
+   dist_author => 'GomoR <gomor-cpan_at_gomor.org>',
+   dist_version_from => 'lib/Net/Frame/Dump.pm',
+   requires => {
+      'perl' => '5.6.1',
+      'Class::Gomor' => '1.00',
+      'Net::Pcap' => '0.12',
+      'Net::Frame' => 0,
+      'Time::HiRes' => 0,
+      'IO::Select' => 0,
+   },
+   configure_requires => {
+      'Module::Build' => 0,
+   },
+);
+
+$builder->create_build_script;
@@ -1,5 +1,14 @@
 Revision history for Perl extension Net::Frame::Dump.
 
+1.14 Tue Dec  9 19:12:25 CET 2014
+   - BUGFIX: Dump::Online2: do not eat 100% and do not block for timeoutOnNext 
+             seconds when it is not REALLY needed. We had to remove the 
+             setnonblock option and to use pcap_dispatch i/o pcap_next_ex.
+             This should be the final bugfix...
+             There was also an infinite loop condition.
+   - new: Dump::Online2: maxRunTime() option to stop looping on next() forever 
+          when we do not want. Default to loop forever.
+
 1.13 Sun Dec  2 15:44:14 CET 2012
    - BUGFIX: Dump::Online2: in non-blocking mode, we must handle our internal
              received frame ring buffer. Many packets were missed because of
@@ -1,3 +1,4 @@
+Build.PL
 Changes
 LICENSE
 LICENSE.Artistic
@@ -19,5 +20,5 @@ lib/Net/Frame/Dump/Writer.pm
 t/01-use.t
 t/02-pod-coverage.t
 t/03-test-pod.t
-META.yml                                 Module YAML meta-data (added by MakeMaker)
-META.json                                Module JSON meta-data (added by MakeMaker)
+META.yml
+META.json
@@ -4,7 +4,7 @@
       "GomoR <gomor-cpan_at_gomor.org>"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150",
+   "generated_by" : "Module::Build version 0.421",
    "license" : [
       "artistic_1"
    ],
@@ -13,34 +13,46 @@
       "version" : "2"
    },
    "name" : "Net-Frame-Dump",
-   "no_index" : {
-      "directory" : [
-         "t",
-         "inc"
-      ]
-   },
    "prereqs" : {
-      "build" : {
-         "requires" : {
-            "ExtUtils::MakeMaker" : 0
-         }
-      },
       "configure" : {
          "requires" : {
-            "ExtUtils::MakeMaker" : 0
+            "Module::Build" : "0"
          }
       },
       "runtime" : {
          "requires" : {
             "Class::Gomor" : "1.00",
-            "IO::Select" : 0,
-            "Net::Frame" : 0,
+            "IO::Select" : "0",
+            "Net::Frame" : "0",
             "Net::Pcap" : "0.12",
-            "Time::HiRes" : 0,
-            "perl" : "5.006001"
+            "Time::HiRes" : "0",
+            "perl" : "v5.6.1"
          }
       }
    },
+   "provides" : {
+      "Net::Frame::Dump" : {
+         "file" : "lib/Net/Frame/Dump.pm",
+         "version" : "1.14"
+      },
+      "Net::Frame::Dump::Offline" : {
+         "file" : "lib/Net/Frame/Dump/Offline.pm"
+      },
+      "Net::Frame::Dump::Online" : {
+         "file" : "lib/Net/Frame/Dump/Online.pm"
+      },
+      "Net::Frame::Dump::Online2" : {
+         "file" : "lib/Net/Frame/Dump/Online2.pm"
+      },
+      "Net::Frame::Dump::Writer" : {
+         "file" : "lib/Net/Frame/Dump/Writer.pm"
+      }
+   },
    "release_status" : "stable",
-   "version" : "1.13"
+   "resources" : {
+      "license" : [
+         "http://www.perlfoundation.org/artistic_license_1_0"
+      ]
+   },
+   "version" : "1.14"
 }
@@ -2,26 +2,35 @@
 abstract: 'base-class for a tcpdump like implementation'
 author:
   - 'GomoR <gomor-cpan_at_gomor.org>'
-build_requires:
-  ExtUtils::MakeMaker: 0
+build_requires: {}
 configure_requires:
-  ExtUtils::MakeMaker: 0
+  Module::Build: '0'
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150'
+generated_by: 'Module::Build version 0.421, CPAN::Meta::Converter version 2.142060'
 license: artistic
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
-  version: 1.4
+  version: '1.4'
 name: Net-Frame-Dump
-no_index:
-  directory:
-    - t
-    - inc
+provides:
+  Net::Frame::Dump:
+    file: lib/Net/Frame/Dump.pm
+    version: '1.14'
+  Net::Frame::Dump::Offline:
+    file: lib/Net/Frame/Dump/Offline.pm
+  Net::Frame::Dump::Online:
+    file: lib/Net/Frame/Dump/Online.pm
+  Net::Frame::Dump::Online2:
+    file: lib/Net/Frame/Dump/Online2.pm
+  Net::Frame::Dump::Writer:
+    file: lib/Net/Frame/Dump/Writer.pm
 requires:
-  Class::Gomor: 1.00
-  IO::Select: 0
-  Net::Frame: 0
-  Net::Pcap: 0.12
-  Time::HiRes: 0
-  perl: 5.006001
-version: 1.13
+  Class::Gomor: '1.00'
+  IO::Select: '0'
+  Net::Frame: '0'
+  Net::Pcap: '0.12'
+  Time::HiRes: '0'
+  perl: v5.6.1
+resources:
+  license: http://www.perlfoundation.org/artistic_license_1_0
+version: '1.14'
@@ -19,6 +19,7 @@ This module requires these other modules and libraries:
   Net::Frame
   Net::Pcap
   Time::HiRes
+  IO::Select
 
 GETTING HELP
 
@@ -30,5 +31,5 @@ COPYRIGHT AND LICENSE
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.
 
-Copyright (c) 2006-2012, Patrice <GomoR> Auffret
+Copyright (c) 2006-2014, Patrice <GomoR> Auffret
 
@@ -1,5 +1,5 @@
 #
-# $Id: Offline.pm 353 2012-09-12 18:15:33Z gomor $
+# $Id: Offline.pm 364 2014-11-30 11:26:27Z gomor $
 #
 package Net::Frame::Dump::Offline;
 use strict;
@@ -199,7 +199,7 @@ Patrice E<lt>GomoRE<gt> Auffret
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2006-2012, Patrice E<lt>GomoRE<gt> Auffret
+Copyright (c) 2006-2014, Patrice E<lt>GomoRE<gt> Auffret
 
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.
@@ -1,5 +1,5 @@
 #
-# $Id: Online.pm 353 2012-09-12 18:15:33Z gomor $
+# $Id: Online.pm 364 2014-11-30 11:26:27Z gomor $
 #
 package Net::Frame::Dump::Online;
 use strict;
@@ -631,7 +631,7 @@ Patrice E<lt>GomoRE<gt> Auffret
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2006-2012, Patrice E<lt>GomoRE<gt> Auffret
+Copyright (c) 2006-2014, Patrice E<lt>GomoRE<gt> Auffret
 
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.
@@ -1,5 +1,5 @@
 #
-# $Id: Online2.pm 360 2012-12-02 14:44:41Z gomor $
+# $Id: Online2.pm 365 2014-12-09 18:08:01Z gomor $
 #
 package Net::Frame::Dump::Online2;
 use strict;
@@ -10,14 +10,16 @@ our @AS = qw(
    dev
    timeoutOnNext
    timeout
+   maxRunTime
    promisc
    snaplen
    file
    overwrite
-   _firstTime
+   _startTime
    _pid
    _sel
    _frames
+   _timeWithoutReceiving
 );
 __PACKAGE__->cgBuildIndices;
 __PACKAGE__->cgBuildAccessorsScalar(\@AS);
@@ -56,8 +58,10 @@ sub new {
       snaplen => 1514,
       file => '',
       overwrite => 0,
-      _firstTime => 0,
+      maxRunTime => 0,
+      _startTime => 0,
       _frames => [],
+      _timeWithoutReceiving => 0,
       @_,
    );
 
@@ -89,7 +93,7 @@ sub start {
       $self->dev,
       $self->snaplen,
       $self->promisc,
-      100,
+      100, # 100 ms timeout
       \$err,
    );
    unless ($pd) {
@@ -115,19 +119,24 @@ sub start {
       return;
    }
 
-   # Avoid nonblock mode when capture only mode chosen: don't eat 100% CPU
    if (! length($self->file)) {
-      my $r = Net::Pcap::setnonblock($pd, 1, \$err);
-      if ($r == -1) {
-         print("[-] ".__PACKAGE__.": setnonblock: $err\n");
-         return;
-      }
+      #my $r = Net::Pcap::setnonblock($pd, 1, \$err);
+      #if ($r == -1) {
+         #print("[-] ".__PACKAGE__.": setnonblock: $err\n");
+         #return;
+      #}
 
       # Gather a file descriptor to use by select()
-      my $fd  = Net::Pcap::get_selectable_fd($pd);
+      # Avoid eating 100% CPU
+      my $fd = Net::Pcap::get_selectable_fd($pd);
+      if ($fd < 0) {
+         print("[-] ".__PACKAGE__.": get_selectable_fd failed\n");
+         return;
+      }
       my $sel = IO::Select->new;
       $sel->add($fd);
       $self->_sel($sel);
+      $self->_startTime(gettimeofday());
    }
 
    $self->_pcapd($pd);
@@ -236,35 +245,34 @@ sub _printStats {
    return 1;
 }
 
-sub _getNextAwaitingFrame {
+sub timeoutReset {
    my $self = shift;
-   return $self->nextEx;
+
+   $self->_timeWithoutReceiving(0);
+   $self->timeout(0);
+
+   return 1;
 }
 
-sub _nextTimeoutHandle {
-   my $self = shift;
+sub _dispatch {
+   my ($user, $header, $packet) = @_;
 
-   # Handle timeout
-   my $thisTime = gettimeofday();
-   if ($self->timeoutOnNext && !$self->_firstTime) {
-      $self->_firstTime($thisTime);
-   }
+   my $self = $user->{self};
+   my $frames = $user->{frames};
 
-   if ($self->timeoutOnNext && $self->_firstTime) {
-      if (($thisTime - $self->_firstTime) > $self->timeoutOnNext) {
-         $self->timeout(1);
-         $self->_firstTime(0);
-         $self->cgDebugPrint(1, "Timeout occured");
-         return;
-      }
-   }
+   my $ts = $self->keepTimestamp ? $self->_getTimestamp($header)
+                                 : $self->_setTimestamp;
 
-   return 1;
-}
+   my $frame = {
+      firstLayer => 'ETH',
+      timestamp => $ts,
+      raw => $packet,
+   };
 
-sub _nextTimeoutReset { shift->_firstTime(0) }
+   push @$frames, $frame;
 
-sub timeoutReset { shift->timeout(0) }
+   $user->{frames} = $frames;
+}
 
 sub next {
    my $self = shift;
@@ -274,27 +282,59 @@ sub next {
           "capture mode.\n");
    }
 
+   # We look ar our internal ring buffer
    my $frames = $self->_frames;
    if (@$frames > 0) {
-      $self->_nextTimeoutReset;
       my $next = shift @$frames;
       $self->_frames($frames);
       return $next;
    }
 
+   # If we reach here, we don't have frames anymore in our buffer,
+   # we ask for more except if we have a timeout condition.
+   if ($self->timeout) {
+      return;
+   }
+
+   # We fetch new awaiting frames, if no timeout occured yet.
+   # can_read will return as soon as there is something to read,
+   # or will block if nothing to read for timeoutOnNext seconds.
    my $sel = $self->_sel;
-   if (my @read = $sel->can_read($self->timeoutOnNext)) {
-      $self->_nextTimeoutReset;
-      while (my $frame = $self->_getNextAwaitingFrame) {
-         push @$frames, $frame;
-      }
-      my $next = shift @$frames;
-      $self->_frames($frames);
-      return $next;
+   my $some_received = 0;
+   my $thisTime = gettimeofday();
+
+   # Gather all available frames
+   my $h = { self => $self, frames => $frames };
+   Net::Pcap::pcap_dispatch($self->_pcapd, -1, \&_dispatch, $h);
+   $some_received = scalar(@{$h->{frames}});
+
+   # Update the ring buffer, or we loose those frames
+   $self->_frames($frames);
+
+   # Check if we didn't received frames during $timeoutOnNext seconds, 
+   my $endTime = gettimeofday();
+   my $diff = $endTime - $thisTime;
+   if (! $some_received) {
+      $self->_timeWithoutReceiving($self->_timeWithoutReceiving + $diff);
+   }
+   else {
+      $self->_timeWithoutReceiving(0);
    }
 
-   # If we are here, a timeout has occured
-   $self->_nextTimeoutHandle;
+   #print STDERR "*** diff [$diff] received [$some_received] thisTime [$thisTime] endTime [$endTime]\n";
+
+   if ($self->_timeWithoutReceiving > $self->timeoutOnNext) {
+      #print STDERR "*** Timeout occured\n";
+      $self->timeout(1);
+   }
+
+   # Check if maximum run time has been reached
+   my $maxRunTime = $self->maxRunTime;
+   my $startTime = $self->_startTime;
+   if ($maxRunTime && ($endTime - $startTime) > $startTime) {
+      #print STDERR "*** Max running time reached\n";
+      $self->timeout(1);
+   }
 
    return;
 }
@@ -451,7 +491,7 @@ Patrice E<lt>GomoRE<gt> Auffret
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2006-2012, Patrice E<lt>GomoRE<gt> Auffret
+Copyright (c) 2006-2014, Patrice E<lt>GomoRE<gt> Auffret
 
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.
@@ -1,5 +1,5 @@
 #
-# $Id: Writer.pm 353 2012-09-12 18:15:33Z gomor $
+# $Id: Writer.pm 364 2014-11-30 11:26:27Z gomor $
 #
 package Net::Frame::Dump::Writer;
 use strict;
@@ -239,7 +239,7 @@ Patrice E<lt>GomoRE<gt> Auffret
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2006-2012, Patrice E<lt>GomoRE<gt> Auffret
+Copyright (c) 2006-2014, Patrice E<lt>GomoRE<gt> Auffret
 
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.
@@ -1,11 +1,11 @@
 #
-# $Id: Dump.pm 360 2012-12-02 14:44:41Z gomor $
+# $Id: Dump.pm 364 2014-11-30 11:26:27Z gomor $
 #
 package Net::Frame::Dump;
 use strict;
 use warnings;
 
-our $VERSION = '1.13';
+our $VERSION = '1.14';
 
 use base qw(Class::Gomor::Array Exporter);
 
@@ -163,8 +163,8 @@ sub nextEx {
 
    my %hdr;
    my $raw;
-   my $r;
-   if ($r = Net::Pcap::next_ex($self->_pcapd, \%hdr, \$raw) > 0) {
+   my $r = Net::Pcap::next_ex($self->_pcapd, \%hdr, \$raw);
+   if ($r > 0) {
       my $ts = $self->keepTimestamp ? $self->_getTimestamp(\%hdr)
                                     : $self->_setTimestamp;
       return {
@@ -252,7 +252,7 @@ Patrice E<lt>GomoRE<gt> Auffret
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright (c) 2006-2012, Patrice E<lt>GomoRE<gt> Auffret
+Copyright (c) 2006-2014, Patrice E<lt>GomoRE<gt> Auffret
 
 You may distribute this module under the terms of the Artistic license.
 See LICENSE.Artistic file in the source distribution archive.