Christopher Fowler wrote:
On Tue, 2006-10-10 at 09:23 -0500, Michael J. Pomraning wrote:
Perhaps pass an unblest reference through perl's prefab Thread::Queue
class?
That should be the best way. Is there any great way to share objects
between threads?
Sharing objects between threads is simple: just make sure that you
use a shared array or hash for your object, and only assign either
simple scalars or shared refs to its members. Then you can pass
the objects between threads via a simple Thread::Queue object.
I've done a quick rewrite of your example (note I have no idea what
the function of your script is, but the Packet class is a pretty simple
container
class, so hopefully this captures what you're attempting).
Some major issues I've noticed:
1) using a `host $addr` to do resolution may be a problem, since
you're shelling out from a thread...I'm not certain how well that's going to
work.
I've noted the use of gethostbyaddr() as an alternate (tho I don't know how
thread
safe it is either)
2) You never waited to join() your threads; I don't know what effect that
might have on your exit condition
3) The way you setup your object sharing was a bit obtuse; I've simplified it
4) I've replaced your @obj ad-hoc queue with Thread::Queue, which handles
the needed locking (which it appears you weren't applying)
Code below. NOTE: I've not run it, it likely has some syntax errors.
HTH,
Dean Arnold
Presicient Corp.
package Packet;
use threads;
use threads::shared;
use strict;
use warnings;
sub new {
my ($class, $v1, $v2) = @_;
#
# NOTE: this assume that the packet and timestamp
# elements are simple scalars; if not, then you'll
# need more share()'ing to coerce them into something
# that can be assigned to a shared hash
#
my %pkt : shared = (
packet => $v1,
timestamp => $v2
);
return bless \%pkt, $class;
}
sub get_timestamp {
my $self = shift;
#
# FYI/Warning: I've encountered some instances where
# derefencing an element off a shared hash would
# silently discard the returned value, and had to do
# an intermediate assignment to a lexical variable
# before using the value; I've not yet determined
# the cause of the issue yet
#
return $self->{'timestamp'};
}
sub get_packet {
my $self = shift;
#
# see caveat above
#
return $self->{'packet'};
}
1;
package main;
use Net::PcapUtils;
use NetPacket::Ethernet;
use NetPacket::IP;
use NetPacket::TCP;
use threads;
use threads::shared;
use Thread::Queue;
use Data::Dumper;
use strict;
use warnings;
$| = 1;
my $prog = "tcp[13] = 2 and src net not 192.168.2";
#
# create a thread queue
#
my $q = Thread::Queue->new();
sub get_timestamp {
my $ti = shift;
$ti = time() unless $ti;
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
localtime($ti);
my $text = sprintf("%02d-%02d %02d:%02d:%02d",
($mon+1), $mday, $hour, $min, $sec);
return $text;
}
sub now {
return time();
}
sub resolv {
my $addr = shift;
#
# OUCH! this may never work properly...forking from a thread
# may lead to chaos, esp. on Win32...isn't there a better
# Perlish solution (e.g., get host by addr ?
#
# my $host = gethostbyaddr($addr, AF_INET);
#
my $host = `host $addr`;
chomp $host;
return $addr if $host =~ m/not found/;
return $addr unless $host =~ m/pointer\s(.+?)\.$/;
$addr = $1;
return $addr;
}
sub process_thread {
while(1) {
#
# wait for a packet (or for 'DIE')
#
my $pktobj = $q->dequeue();
#
# if not a ref, then it must be 'DIE'
#
return 1
unless ref $pktobj;
#
# Get the packet off the list and unpack the time
#
my $pkt = $pktobj->get_packet();
my $ti = $pktobj->get_timestamp();
# get the source IP adrress
my $src_ip = NetPacket::IP->decode(
NetPacket::Ethernet::strip($pkt))->{src_ip};
# I want incoming
next if $src_ip =~ m/209\.168\.246\.233/;
my $pt = NetPacket::TCP->decode(
NetPacket::IP::strip(
NetPacket::Ethernet::strip($pkt)));
print get_timestamp($ti)." SYN ".resolv($src_ip)."($src_ip) ->
$pt->{'dest_port'}\n";
}
}
sub catch {
my ($arg,$hdr,$pkt) = @_ ;
#
# enqueue the packet for processing
#
$q->enqueue(Packet->new($pkt, now()));
}
#
# spawn the thread
#
my $pthr = threads->new(\&process_thread);
#
# start snooping
#
Net::PcapUtils::loop(\&catch, FILTER=> $prog);
#
# I don't know what your exit condition is ???
# but here's how I've instrumented cleanup
# NOTE that if you start >1 thread, you'll need
# to send multiple DIE's, and join all the threads
#
$q->enqueue('DIE');
$pthr->join();