tcpreplay
sets STDIN to use non-blocking I/O, which causes reads to return an error immediately if no data is available. You can see this by checking the return value of readline
:
use strict;
use warnings 'all';
use 5.010;
$| = 1;
while (<*.pcap>) {
say;
die "readline error: $!" if ! defined <STDIN>;
system("tcpreplay -i eth0 $_") == 0
or die "tcpreplay failed: $?";
}
After the first call to tcpreplay
, this dies with the message:
readline error: Resource temporarily unavailable at ./replay line 10, <STDIN> line 1.
This corresponds to errno EAGAIN
, which read
returns if a file descriptor marked as non-blocking would have to block to wait for I/O.
If your system implements fcntl
, you can get around this by setting STDIN to use blocking I/O after every call to tcpreplay
:
use strict;
use warnings 'all';
use 5.010;
use Fcntl;
$| = 1;
while (<*.pcap>) {
say;
die "readline error: $!" if ! defined <STDIN>;
system("tcpreplay -i eth0 $_") == 0
or die "tcpreplay failed: $?";
# Reset STDIN to use blocking I/O
my $flags = fcntl(STDIN, F_GETFL, 0)
or die "Couldn't get flags for STDIN: $!";
fcntl(STDIN, F_SETFL, $flags & ~O_NONBLOCK)
or die "Couldn't set flags for STDIN: $!";
}
This is just a workaround, though; tcpreplay
should be fixed.