line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Net::Analysis::Listener::Base; |
2
|
|
|
|
|
|
|
# $Id: Base.pm 131 2005-10-02 17:24:31Z abworrall $ |
3
|
|
|
|
|
|
|
|
4
|
1
|
|
|
1
|
|
762
|
use 5.008000; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
46
|
|
5
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
6
|
1
|
|
|
1
|
|
4
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
26
|
|
7
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
10
|
|
|
1
|
|
|
|
|
56
|
|
8
|
1
|
|
|
1
|
|
6
|
use overload q("") => sub { $_[0]->as_string() }; # OO style stringify |
|
1
|
|
|
1
|
|
1
|
|
|
1
|
|
|
|
|
11
|
|
|
1
|
|
|
|
|
5
|
|
9
|
|
|
|
|
|
|
|
10
|
1
|
|
|
1
|
|
64
|
use Carp qw(carp croak); |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
53
|
|
11
|
|
|
|
|
|
|
|
12
|
1
|
|
|
1
|
|
5
|
use Params::Validate qw(:all); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1052
|
|
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# {{{ POD |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 NAME |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
Net::Analysis::Listener::Base - base class for event listeners |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
=head1 SYNOPSIS |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
This module should be subclassed as follows: |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
package Net::Analysis::Listener::MyThing; |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
use base 'Net::Analysis::Listener::Base'; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
sub event_listener { |
29
|
|
|
|
|
|
|
my ($self, $args_hash) = @_; |
30
|
|
|
|
|
|
|
... do something ... |
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
if (event_is_exciting($args_hash)) { |
33
|
|
|
|
|
|
|
$self->emit (name => 'my_event', |
34
|
|
|
|
|
|
|
args => {what => 'listeners to this event will get'}); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
This module is a virtual base class for Listeners. To create a new listener, |
41
|
|
|
|
|
|
|
just subclass this, and add methods. If you want to listen to an event, create |
42
|
|
|
|
|
|
|
a method with the name of that event - the dispatcher takes care of the rest. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
If you want to store state between events (such as a hash of open sessions), |
45
|
|
|
|
|
|
|
stuff it into C<$self>. Any configuration for your listener will also be |
46
|
|
|
|
|
|
|
exploded all over $<$self>, so take care. Subclasses can use anything in $self |
47
|
|
|
|
|
|
|
they want, except the key '_', which contains private stuff used by the base |
48
|
|
|
|
|
|
|
class. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
You can emit events if you like; if you add new types of event, take care not |
51
|
|
|
|
|
|
|
to collide with existing ones (e.g. tcp_blah, http_blah). The best way to do |
52
|
|
|
|
|
|
|
this is to select a prefix for your event names based on your protocol. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head1 INHERITED METHODS |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
B, you don't need to implement them. |
57
|
|
|
|
|
|
|
They're documented here for reference, so don't be put off - they can be safely |
58
|
|
|
|
|
|
|
ignored :) |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
=cut |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# }}} |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
# These should not be overridden |
65
|
|
|
|
|
|
|
# XXXX Create a DESTROY method that breaks all the circular refs. |
66
|
|
|
|
|
|
|
# {{{ new |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
# {{{ POD |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head2 new (dispatcher => $obj [, config => $hash] [, pos => 'first|last']) |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
Mandatory argument is the dispatcher object which will dispatch any events |
73
|
|
|
|
|
|
|
that originate from this module, or any that subclass from it. |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
Note that we immediately register this new object with the dispatcher; this |
76
|
|
|
|
|
|
|
will create circular references. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
The config hash is optional. Standard key/val pairs are: |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
* v => 0..3 (verbosity; 0==silent, 9==noisy) |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
The pos parameter is optional. It specifies if the listener sould catch events |
83
|
|
|
|
|
|
|
first, or last. Only one listener can be first, or last. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
The rest of the hash varies on a per-listener basis. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
The returned object has one reserved field: C<$self->{_}>. This is used for the |
88
|
|
|
|
|
|
|
behind-the-scenes plumbing. All other fields in C<$self> are free for the |
89
|
|
|
|
|
|
|
subclass to use. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
Note that the config hash is exploded over C<$self>; that is, C<$self->{v}> |
92
|
|
|
|
|
|
|
will contain the verbosity value passed in via the config hash (or a |
93
|
|
|
|
|
|
|
default, if no config is passed in.) |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=cut |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# }}} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub new { |
100
|
1
|
|
|
1
|
1
|
905
|
my ($class) = shift; |
101
|
|
|
|
|
|
|
|
102
|
1
|
|
|
|
|
98
|
my %args = validate (@_, { |
103
|
|
|
|
|
|
|
dispatcher => { can => 'emit_event' }, |
104
|
|
|
|
|
|
|
pos => { regex => qr/^(first|last)$/, |
105
|
|
|
|
|
|
|
optional => 1}, |
106
|
|
|
|
|
|
|
config => { type => HASHREF, |
107
|
|
|
|
|
|
|
default => {v => 0}, }, |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
); |
110
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# Place the dispatcher into our private subhash |
112
|
1
|
|
|
|
|
14
|
my %h = ('_' => {dispatcher => $args{dispatcher}}); |
113
|
|
|
|
|
|
|
|
114
|
1
|
|
|
|
|
5
|
my ($self) = bless (\%h, $class); |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Allow the module to validate the configuration, if it wants |
117
|
1
|
|
|
|
|
2
|
my $cnf = $self->validate_configuration (%{$args{config}}); |
|
1
|
|
|
|
|
6
|
|
118
|
1
|
50
|
|
|
|
6
|
if (! defined $cnf) { |
119
|
0
|
|
|
|
|
0
|
carp "no configuration, despite default setting above ?"; |
120
|
0
|
|
|
|
|
0
|
return undef; |
121
|
|
|
|
|
|
|
} |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# Explode the config all over self, provided we haven't already used it |
124
|
1
|
|
|
|
|
2
|
foreach my $k (keys %{$cnf}) { |
|
1
|
|
|
|
|
5
|
|
125
|
1
|
50
|
|
|
|
6
|
croak "bad config '$k': '$k' is reserved !\n" if (exists $h{$k}); |
126
|
1
|
|
|
|
|
3
|
$h{$k} = $cnf->{$k}; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# If a position was specified, put it where the dispatcher will look for it |
130
|
1
|
50
|
|
|
|
7
|
$self->{pos} = $args{pos} if (exists $args{pos}); |
131
|
|
|
|
|
|
|
|
132
|
1
|
|
|
|
|
6
|
$h{_}{dispatcher}->add_listener (listener => $self); # Circular ref joy |
133
|
|
|
|
|
|
|
|
134
|
1
|
|
|
|
|
5
|
return $self; |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# }}} |
138
|
|
|
|
|
|
|
# {{{ emit |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
=head2 emit (...) |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
This is a convenience wrapper on top of |
143
|
|
|
|
|
|
|
L. It takes exactly the same arguments. |
144
|
|
|
|
|
|
|
Please refer to that module for documentation. |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=cut |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub emit { |
149
|
1
|
|
|
1
|
1
|
11
|
my ($self) = shift; |
150
|
1
|
|
|
|
|
5
|
$self->{_}{dispatcher}->emit_event (@_); |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# }}} |
154
|
|
|
|
|
|
|
# {{{ trace |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub trace { |
157
|
0
|
|
|
0
|
0
|
0
|
my ($self) = shift; |
158
|
|
|
|
|
|
|
|
159
|
0
|
|
|
|
|
0
|
foreach (@_) { |
160
|
0
|
|
|
|
|
0
|
my $l = $_; # Skip 'Modification of a read-only value' errors |
161
|
0
|
|
|
|
|
0
|
chomp ($l); |
162
|
0
|
|
|
|
|
0
|
print "$l\n"; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
} |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
# }}} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# These can (should) be overridden |
169
|
|
|
|
|
|
|
# {{{ as_string |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
# This should really be overridden by our subclass |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub as_string { |
174
|
1
|
|
|
1
|
0
|
2
|
my ($self) = @_; |
175
|
1
|
|
|
|
|
2
|
my $s = ''; |
176
|
|
|
|
|
|
|
|
177
|
1
|
|
|
|
|
4
|
$s .= "[".ref($self)."]"; |
178
|
|
|
|
|
|
|
|
179
|
1
|
|
|
|
|
10
|
return $s; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
# }}} |
183
|
1
|
|
|
1
|
0
|
2
|
sub validate_configuration { my $self=shift; return {@_}; } |
|
1
|
|
|
|
|
35
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
#sub setup {} |
186
|
|
|
|
|
|
|
#sub teardown {} |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Utilities for viewing binary data |
190
|
|
|
|
|
|
|
# {{{ sanitize_raw |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub sanitize_raw { |
193
|
0
|
|
|
0
|
0
|
|
my ($self, $raw, $max, $append_binary) = @_; |
194
|
0
|
0
|
0
|
|
|
|
$raw = substr($raw,0,$max) if ($max && length($raw) > $max); |
195
|
|
|
|
|
|
|
|
196
|
0
|
|
|
|
|
|
my $s = $raw; |
197
|
0
|
|
|
|
|
|
$s =~ s {([^\x20-\x7e])} {.}g; |
198
|
0
|
0
|
|
|
|
|
$s .= " ".$self->map2bin($raw) if ($append_binary); |
199
|
0
|
|
|
|
|
|
return "{$s}"; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# }}} |
203
|
|
|
|
|
|
|
# {{{ map2bin |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
sub map2bin { |
206
|
0
|
|
|
0
|
0
|
|
my ($self,$raw) = @_; |
207
|
0
|
|
|
|
|
|
my $bin = unpack("B*", $raw); |
208
|
0
|
|
|
|
|
|
$bin =~ s{([^ ]{8})(?! )}{ $1}g; |
209
|
0
|
|
|
|
|
|
$bin =~ s{(^ *| *$)}{}g; |
210
|
0
|
|
|
|
|
|
return "<$bin>"; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
# }}} |
214
|
|
|
|
|
|
|
# {{{ map2hex |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
sub map2hex { |
217
|
0
|
|
|
0
|
0
|
|
my ($self,$raw, $prefix, $append_binary) = @_; |
218
|
|
|
|
|
|
|
|
219
|
0
|
|
0
|
|
|
|
$prefix ||= ''; |
220
|
0
|
|
|
|
|
|
my $hex = unpack("H*", $raw); |
221
|
|
|
|
|
|
|
|
222
|
0
|
|
|
|
|
|
$hex =~ s {([0-9a-f]{2}(?! ))} { $1}mg; |
223
|
|
|
|
|
|
|
|
224
|
0
|
|
|
|
|
|
$hex =~ s {(( [0-9a-f]{2}){16})} |
225
|
0
|
|
|
|
|
|
{"$1 ".$self->hex2saferaw($1,$append_binary)."\n"}emg; |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
# Unfinished last line |
228
|
0
|
|
|
|
|
|
$hex =~ s {(( [0-9a-f]{2})*)$} |
229
|
0
|
|
|
|
|
|
{sprintf("%-47.47s ",$1) .$self->hex2saferaw($1,$append_binary)."\n"}es; |
230
|
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
chomp($hex); |
232
|
|
|
|
|
|
|
|
233
|
0
|
|
|
|
|
|
$hex =~ s/^/$prefix/msg; |
234
|
|
|
|
|
|
|
|
235
|
0
|
|
|
|
|
|
return $hex."\n"; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub hex2saferaw { |
239
|
0
|
|
|
0
|
0
|
|
my ($self, $hex, $append_binary) = @_; |
240
|
|
|
|
|
|
|
|
241
|
0
|
|
|
|
|
|
$hex =~ s {\s+} {}mg; |
242
|
0
|
|
|
|
|
|
my $raw = pack("H*", $hex); |
243
|
|
|
|
|
|
|
|
244
|
0
|
|
|
|
|
|
return $self->sanitize_raw($raw,undef,$append_binary); |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# }}} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
1; |
250
|
|
|
|
|
|
|
__END__ |