Net-IMP

 view release on metacpan or  search on metacpan

lib/Net/IMP.pm  view on Meta::CPAN

    IMP_PAUSE
    IMP_CONTINUE
    IMP_LOG
    IMP_PORT_OPEN
    IMP_PORT_CLOSE
    IMP_ACCTFIELD
    IMP_FATAL
    IMP_MAXOFFSET
    IMP_DATA_STREAM
    IMP_DATA_PACKET
);

my @log_levels = qw(
    IMP_LOG_DEBUG
    IMP_LOG_INFO
    IMP_LOG_NOTICE
    IMP_LOG_WARNING
    IMP_LOG_ERR
    IMP_LOG_CRIT
    IMP_LOG_ALERT
    IMP_LOG_EMERG
);
our @EXPORT_OK = (@log_levels, 'IMP_DATA','IMP_DATA_TYPES', 'IMP_PASS_IF_BUSY');
our %EXPORT_TAGS = ( log => \@log_levels );

# data types/protocols
# These two are the basic types, more application specific types might
# be defined somewhere else and be mapped to a number within supported_dtypes.
# The only important thing is, that streaming data should be <0, while
# packetized data (like HTTP header or UDP datagrams) should be > 0
# If no explicit type is given in sub data, it will assume IMP_DATA_STREAM.
use constant IMP_DATA_STREAM  => dualvar(-1,'imp.data.stream');
use constant IMP_DATA_PACKET  => dualvar(+1,'imp.data.packet');


# the numerical order of the constants describes priority when
# cascading modules, e.g. replacement has a higher value then
# pass and gets thus forwarded as the cause for the data

### information only
use constant IMP_LOG          => dualvar(0x0001,"log");
use constant IMP_PORT_OPEN    => dualvar(0x0002,"port_open");
use constant IMP_PORT_CLOSE   => dualvar(0x0003,"port_close");
use constant IMP_ACCTFIELD    => dualvar(0x0004,"acctfield");
### flow control
use constant IMP_PAUSE        => dualvar(0x0010,"pause");
use constant IMP_CONTINUE     => dualvar(0x0011,"continue");
use constant IMP_REPLACE_LATER  => dualvar(0x0012,"replace_later");
### keep data
use constant IMP_PASS         => dualvar(0x1001,"pass");
use constant IMP_PASS_PATTERN => dualvar(0x1002,"pass_pattern");
use constant IMP_PREPASS      => dualvar(0x1003,"prepass");
### change data
use constant IMP_TOSENDER     => dualvar(0x1010,"tosender");
use constant IMP_REPLACE      => dualvar(0x1011,"replace");
### affect whole connection
use constant IMP_DENY         => dualvar(0x1100,"deny");
use constant IMP_DROP         => dualvar(0x1101,"drop");
use constant IMP_FATAL        => dualvar(0x1102,"fatal");

# these return values still get sent if the data provider is busy
# the most important are on top
use constant IMP_PASS_IF_BUSY => [
    IMP_FATAL,
    IMP_DENY,
    IMP_DROP,
    IMP_PAUSE,
    IMP_CONTINUE,
    IMP_ACCTFIELD
];


# marker for (pre)pass to Infinite for IMP_PASS, IMP_PREPASS
use constant IMP_MAXOFFSET    => -1;

# log levels for IMP_LOG
# these are modeled analog to syslog levels
use constant IMP_LOG_DEBUG    => dualvar(1,'debug');
use constant IMP_LOG_INFO     => dualvar(2,'info');
use constant IMP_LOG_NOTICE   => dualvar(3,'notice');
use constant IMP_LOG_WARNING  => dualvar(4,'warning');
use constant IMP_LOG_ERR      => dualvar(5,'error');
use constant IMP_LOG_CRIT     => dualvar(6,'critical');
use constant IMP_LOG_ALERT    => dualvar(7,'alert');
use constant IMP_LOG_EMERG    => dualvar(8,'emergency');


# helper function to define new IMP_DATA_* types for protocols
{
    my @dualvars = ( IMP_DATA_STREAM, IMP_DATA_PACKET );
    sub IMP_DATA_TYPES { return @dualvars }

    my %atoi = map {( "$_" => $_+0 )} @dualvars;
    my %itoa = map {( $_+0 => "$_" )} @dualvars;

    # $basename - name which gets used in constant name, e.g. 'http' makes
    # IMP_DATA_HTTP_..... Best would be name of IP service.
    # - if name[number] will use number as base type number
    # - if name[other_name+number] will base types on already defined
    #   types with number added as offset
    # - if no number given it will use port name from getservbyname,
    #   multiplied with 0x10000 and die if no such service is defined
    # @def: list of defname => [+-]offset which will result in a definition
    # of IMP_DATA_BASENAME_DEFNAME => [+-](base+offset), e.g. '+' for packet
    # types and '-' for stream types
    sub IMP_DATA {
	my ($basename,@def) = @_;
	my $basenum;
	if ( $basename =~s{\[(?:(\w+)\+)?(\d+)\]$}{} ) {
	    (my $base,$basenum) = ($1,$2);
	    if ( $base ) {
		my $offset = $atoi{$base}
		    or croak("cannot find base type $base");
		$basenum += $offset;
	    }
	} else {
	    $basenum = getservbyname($basename,'tcp' )
		|| getservbyname($basename,'udp' )
		or croak("cannot determine id for $basename");
	    $basenum = $basenum << 16;
	}

lib/Net/IMP.pm  view on Meta::CPAN

C<$code> is a coderef while C<@args> are additional user specified arguments
which should be used in the callback (typically object reference or similar).
The callback is called with C<< $code->(@args,@results) >> whenever new results
are available.

If $code is undef, an existing callback will be removed.

If no callback is given, the results need to be polled with C<poll_results>.

=item $analyzer->data($dir,$data,$offset,$type)

Forwards new data to the analyzer.
C<$dir> is the direction, e.g. 0 from client and 1 from server.
C<$data> is the data.
C<$data> of '' means end of data.

C<$offset> is the current position (octet) in the data stream.
It must be set to a value greater than 0 after data got omitted as a result of
PASS or PASS_PATTERN, so that the analyzer can resynchronize the internal
position value with the original position in the data stream.
In any other case it should be set to 0.

C<$type> is the type of the data.
There are two global data type definitions:

=over 4

=item IMP_DATA_STREAM (-1)

This is for generic streaming data, e.g. chunks from these datatypes can be
concatenated and analyzed together, parts can be replaced etc.

=item IMP_DATA_PACKET (+1)

This is for generic packetized data, where each chunk (e.g. call to C<data>)
contains a single packet, which should be analyzed as a separate entity.
This means no concatenating with previous or future chunks and no replacing of
only parts of the packet.

Also, any offsets given in calls to C<data> or in the results should be at
packet boundary (or IMP_MAX_OFFSET), at least for data modifications.
It will ignore (pre)pass which are not a packet boundary in the hope, that more
(pre)pass will follow.
A (pre)pass for some parts of a packet followed by a replacement is not allowed
and will probably cause an exception.

=back

All other data types are considered either subtypes of IMP_DATA_PACKET
(value >0) or of IMP_DATA_STREAM (value<0) and share their restrictions.
Also only streaming data of the same type can be concatenated and
analyzed together.

Results will be delivered through the callback or via C<poll_results>.

=item $analyzer->poll_results => @results

Returns outstanding results.
If a callback is attached, no results will be delivered this way.

=item $analyzer->busy($dir,0|1)

Reports to the analyzer if the data provider is busy and cannot process all
requests. This is usually the case, if the upstream cannot keep up with the
data, so sending gets stalled.
While the data provider is busy the analyzer might still send return values,
which might resolve the busy state, like IMP_DENY, IMP_FATAL etc

=item Net::IMP->set_debug

This is just a convenient way to call C<< Net::IMP::Debug->set_debug >>.
See L<Net::IMP::Debug> for more information.

=back

=head1 TODO

=over 4

=item * sample integration into relayd

=item * protocol to add remote analyzers

=item * add more return types like IMP_PORT_*

Specify IMP_PORT_* and have sample implementation which uses it.
Should be used to inform data provider, that inside that protocol it found
dynamic port allocations (like for FTP data streams or SIP RTP streams) and
that caller should track these connections too.

=back

=head2 Helper Functions

The function C<IMP_DATA> is provided to simplify definition of new data types,
for example:

    our @EXPORT = IMP_DATA('http',
	'header'  => +1,   # packet type
	'body'    => -2,   # streaming type
	...
    );
    push @EXPORT = IMP_DATA('httprq[http+10]',
	'header'  => +1,   # packet type
	'content' => -2,   # streaming type
	...
    );

This call of IMP_DATA is equivalent to the following perl declaration:

    use Scalar::Util 'dualvar';
    our @EXPORT = (
	'IMP_DATA_HTTP', 'IMP_DATA_HTTP_HEADER','IMP_DATA_HTTP_BODY',...
	'IMP_DATA_HTTPRQ', 'IMP_DATA_HTTPRQ_HEADER','IMP_DATA_HTTPRQ_BODY',...
    );

    # getservbyname('http','tcp') -> 80
    use constant IMP_DATA_HTTP
	=> dualvar(80 << 16,'imp.data.http');
    use constant IMP_DATA_HTTP_HEADER
	=> dualvar((80 << 16) + 1,'imp.data.http.header');
    use constant IMP_DATA_HTTP_BODY
	=> dualvar( -( (80 << 16) + 2 ), 'imp.data.http.body');
    ...
    use constant IMP_DATA_HTTPRQ
	=> dualvar((80 << 16) + 10,'imp.data.httprq');
    use constant IMP_DATA_HTTPRQ_HEADER



( run in 0.563 second using v1.01-cache-2.11-cpan-39bf76dae61 )