Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

TSHARK Child: Windows open2 non-blocking read, or redesign?

by cmv (Chaplain)
on Oct 11, 2010 at 20:22 UTC ( #864690=perlquestion: print w/replies, xml ) Need Help??
cmv has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks-

My goal is to fork a child process running tshark, and feed it messages (in pcap format) for it to decode, then grab the decoded output to do stuff with.

The attached example script works on unix (you need to have wireshark installed). I setup NBread() to handle the edge cases when the input message is bad, and I get stuck in the do-until loop, looking for a blank like that isn't coming. NOTE: The assumption that tshark always prints out a blank line after each decode seems reliable, except on these edge cases.

On unix, I'll get stuck for up to 2 seconds, then pop out and continue on.

On windows, I get stuck forever.

What are good options to make this work on both unix and windows? Should the solution be a non-blocking read for windows, or should I re-design in some other (better) way for both platforms?



Update: Also, when you hit ctrl-c in windows to get out, the tshark process ends up hanging around forever (yuk)!

use strict; use English; use IPC::Open2; use Data::Dumper; $|++; my $TSHARKOPTS = "-l -V -i -"; my $TSHARK = $ENV{TSHARK} || '/opt/exp/sbin/tshark' || 'tshark'; # Need to use elsif's here, since perl (-e) uses unix-type path names # and TSHARK needs dos-type path names... if($OSNAME eq 'MSWin32'){ if(-e $ENV{TSHARK}) { $TSHARK = $ENV{TSHARK}; }elsif(-e 'c:/Program Files/wireshark/tshark.exe' ) { $TSHARK = "c:\\\"Program Files\"\\wireshark\\tshark.exe"; }else{ die "Cannot find TSHARK"; } } # Startup child... my $CHILD = open2(\*READ, \*WRITE, "$TSHARK $TSHARKOPTS") || die "Can't open2 child process: $!"; print STDERR "tshark started CHILD=$CHILD...\n"; my @header = ( 0xa1b2, 0xc3d4, 0x0002, 0x0004, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xffff, 0x0000, 0x0001); my @msg1 = ( 0x4c, 0x52, 0x56, 0x67, 0x00, 0x0c, 0xc5, 0x88, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x56, 0x00, 0x21, 0x05, 0x6e, 0x7d, 0xcb, 0x00, 0x16, 0x4d, 0xc4, 0xdf, 0x64, 0x08, 0x00, 0x45, 0x02, 0x00, 0x48, 0x00, 0x00, 0x40, 0x00, 0x3f, 0x84, 0x1f, 0xdb, 0x0a, 0x98, 0x02, 0x21, 0x0a, 0x98, 0x04, 0x05, 0x0b, 0xb9, 0x04, 0x00, 0x78, 0xa1, 0x28, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x26, 0x4d, 0x2b, 0x6d, 0xf8, 0x00, 0x01, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x12, 0x00, 0x17, 0x00, 0x12, 0x00, 0x00, 0x02, 0x00, 0x63, 0x00, 0x05, 0x04, 0x46, 0xb3, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x02, 0x80, 0x00, 0x00, ); my $bhead = pack('n*', @header); my $bmsg1 = pack('c*', @msg1); # Output PCAP file header to tshark... print WRITE $bhead; # Count as we go through the message loop... my $c=0; while (1) { if(! $CHILD) { last }; $c++; # Force a blocking read after 2 rounds... if($c<3) { print WRITE $bmsg1; } my $got = NBread(\*READ); print STDERR "$c: ", scalar(split(/^/, $got)), " lines\n"; sleep 1; } sub NBread { my $fd = shift || die "Missing read file descriptor"; # Read from decoder... my $line; my $otext; eval { local $SIG{ALRM} = sub { die 'TIMEOUT' }; do { alarm 2; if( ! ($line = <$fd>) ) { # Child died for some reason... alarm 0; warn "Decoder pid=$CHILD, not available!\n"; undef($CHILD); last; } $otext .= $line; alarm 0; } until ($line =~ /^\s*$/); }; if ($@) { print STDERR "$@" }; return($otext); }

Replies are listed 'Best First'.
Re: TSHARK Child: Windows open2 non-blocking read, or redesign?
by Corion (Pope) on Oct 12, 2010 at 07:28 UTC

    When pipe-spawning children, I usually follow this pattern to clean up stray detached child processes:

    my $CHILD = open2(\*READ, \*WRITE, "$TSHARK $TSHARKOPTS") || die "Can't open2 child process: $!"; push @children, $CHILD; END { kill 9 => @children; };

    Of course, this simple approach is no good if you have a machine where PIDs get recycled very fast, or if you have a long running process with many children that have finished. Then a cleanup of @children if a child finishes is in order.

      I would collect the children's PIDs in a hash (as keys with meaningless values), remove them in a SIGCHLD handler from the hash, and kill() the remaining ones a litte bit more carefully (first SIGTERM, then SIGKILL). Of course, that won't work on Windows (no signals, no fork(), no exec(), no kill() in the API, just an incomplete emulation inside perl).


      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        kill works for processes outside of Perl as well on Win32.

Re: TSHARK Child: Windows open2 non-blocking read, or redesign?
by BrowserUk (Pope) on Oct 12, 2010 at 10:49 UTC

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://864690]
Approved by ahmad
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2017-12-16 11:39 GMT
Find Nodes?
    Voting Booth?
    What programming language do you hate the most?

    Results (450 votes). Check out past polls.