Mobile-Location

 view release on metacpan or  search on metacpan

Location.pm  view on Meta::CPAN


    $self->_logger( "Location's PK+/PK- pairing generated." ) if $self->{ Web };

    # Remember the PK- in the object's state.

    $self->{ PrivateKey } = $private;

    # Write the PK+ to an appropriately named disk-file.

    my $pub_fn = $self->{ Host } . "." . $self->{ Port } . ".public";

    $self->_logger( "Writing PK+ to: $pub_fn." ) if $self->{ Web };

    $public->write( Filename => $pub_fn );

    # Determine the KEYSERVER address from the .scoobyrc file.

    open KEYFILE, SCOOBY_CONFIG_FILE
                or die "Mobile::Location: unable to access ~/.scoobyrc. Does it exist?\n";

    my $keyline = <KEYFILE>;

    close KEYFILE;

    # Note: format of 'rc' file is very strict.  No spaces!
    $keyline =~ /^KEYSERVER=(.+)/;

    $self->{ KeyServer } = $1;

    # Now that we know the address of the keyserver, we can register the PK+ of this
    # Location with the keyserver.  We read the PK+ from the just-created disk-file.

    $self->_logger( "Determined keyserver address as:", $self->{ KeyServer } ) if $self->{ Web };

    open KEYFILE, "$pub_fn"
        or die "Mobile::Location: KEYFILE does not exist: $!.\n";

    my @entire_keyfile = <KEYFILE>;

    close KEYFILE;

    my $keysock_obj = IO::Socket::INET->new( PeerAddr  => $self->{ KeyServer },
                                             PeerPort  => REGISTRATION_PPORT,
                                             Proto     => 'tcp' );

    if ( !defined( $keysock_obj ) )
    {
        die "Mobile::Location: could not create socket object to key server: $!.\n";
    }
    print $keysock_obj $self->{ Port }, "\n";
    print $keysock_obj @entire_keyfile;

    $keysock_obj->close;

    $self->_logger( "Location registered with keyserver." ) if $self->{ Web };
}

sub start_concurrent {

    # Start a passive server/location that executes concurrently.  For
    # each relocation request, a child process is spawned to process it.
    #
    # IN:  nothing.
    #
    # OUT: nothing.
    #
    # This method is never returned from.  Remember: servers are PERMANENT.
    
    my $self = shift;

    my $listening_socket = IO::Socket::INET->new( LocalPort => $self->{ Port },
                                                  Listen    => SOMAXCONN,
                                                  Proto     => 'tcp',
                                                  Reuse     => TRUE );

    if ( !defined( $listening_socket ) )
    {
        die "Mobile::Location: unable to bind to listening socket: $!.\n";
    }

    $self->_logger( "Location (concurrent) starting on port:", $self->{ Port } ) if $self->{ Web };

    warn "Location starting up on port: " . $self->{ Port } . ".\n" if $self->{ Debug };
    
    $self->_register_with_keyserver;   
 
    while ( TRUE )  # i.e., FOREVER, as servers are permanent.
    {
        next unless my $from_socket = $listening_socket->accept;

        next if my $child = fork;

        if ( $child == FALSE )
        {
            $self->_logger( "Servicing client from:", 
                                inet_ntoa( $from_socket->peeraddr ) ) if $self->{ Web };

            $listening_socket->close;
            $self->_service_client( $from_socket );
            exit FALSE;
        }

        $from_socket->close;
    }
}
    
sub start_sequential {

    # Start a passive server/location that executes sequentially.
    #
    # IN:  nothing.
    #
    # OUT: nothing.
    #
    # This method is never returned from.  Remember: servers are PERMANENT.

    my $self = shift;

    my $listening_socket = IO::Socket::INET->new( LocalPort => $self->{ Port },
                                                  Listen    => SOMAXCONN,
                                                  Proto     => 'tcp',

Location.pm  view on Meta::CPAN

    if ( !$verify )
    {
        $self->_logger( "WARNING: could not verify signature for:",
                            inet_ntoa( $socket_object->peeraddr ), 
                                "using $agent_ip/$agent_port." ) if $self->{ Web };

        die "Mobile::Location: could not verify signature of received mobile agent.  Aborting ... \n";    
    }

    $self->_logger( "Signature verified for $agent_ip/$agent_port." ) if $self->{ Web };

    # Remove the agents PK+ keyfile, as we no longer need it.

    unlink "$agent_ip.$agent_port.public";

    # At this stage, we have a mobile agent that is encrypted using the PK+
    # of this Location, and we have verified the signature to be correct.  
    # We use this Location's PK- to decrypt it.

    my $plaintext = $rsa->decrypt( 
                             Cyphertext => $data,
                             Key        => $self->{ PrivateKey },
                             Armour     => TRUE 
                          );

    if ( !defined( $plaintext ) )
    {
        $self->_logger( "WARNING: unable to decrypt Cyphertext for: $agent_ip/$agent_port." ) if $self->{ Web };

        die "Mobile::Location: decryption errors - aborting.\n";
    }

    # We have a plaintext representation of the mobile agent, which
    # we turn back into an array of lines.

    my @entire_thing = split /\n/, $plaintext;

    # Add a newline to each of the "lines" in @entire_thing.

    foreach my $line ( @entire_thing )
    {
        $line = $line . "\n";
    }

    # Ensure the Location is in the correct STARTUP directory.

    chdir $_PWD;

    # We enter the run-time directory if it exists.

    if ( -e RUN_LOCATION_DIR )
    {
        chdir( RUN_LOCATION_DIR );
    }
    else # Or, if it does NOT exist, we create it then change into it.
    {
        mkdir( RUN_LOCATION_DIR );
        chdir( RUN_LOCATION_DIR );
    }

    # As we are now in the run-time directory, we continue with the relocation.

    if ( $self->{ Log } )
    {
        my $logname = "last_agent_" . $$ . ".log";  # Note use of PID.
 
        # Put a copy of the mobile agent into the log file. 

        my $logOK = open AGENTLOGFILE, ">$logname"
            or warn "Mobile::Location: could not open log file: $!.\n";

        print AGENTLOGFILE @entire_thing if defined $logOK;

        close AGENTLOGFILE if defined $logOK;

        $self->_logger2( "Received agent logged to: $logname." ) if $self->{ Web };
    }

    # Untaint the filename received from Scooby, using a regex.

    $tmp_fn =~ /^([-\@\w_.]+)$/;
    $tmp_fn = $1;
  
    # Create the "mutated" agent on the local storage.

    open FILETOCHECK, ">$tmp_fn"
        or die "Location::Mobile: could not create agent disk-file: $!:";
    
    my $label = _generate_label( $tmp_fn, $tmp_linenum );
        
    # Start processing the agent one "line" at a time.

    my $chunk = shift @entire_thing;

    # Print the "magic" first line. 

    print FILETOCHECK $chunk;            

#    # Add the Opcode mask to the code.
#
#    print FILETOCHECK "\nuse ops qw( " . 
#
#        # Basic operation mask - relocating to a single Location.
#
#        'aassign add aelem av2arylen ' .
#        'backtick ' .
#        'caller chdir chomp chop closedir concat const ' .
#        'defined die ' .
#        'enter entereval enteriter entersub eq ' .
#        'ftdir fteexec ftewrite ' .
#        'gelem goto grepstart gv ' .
#        'helem ' .
#        'iter ' .
#        'join ' .
#        'last leaveeval leaveloop leavesub lstat ' .
#        'method method_named ' .
#        'ne negate next not null ' .
#        'open_dir ' .
#        'padany pop push pushmark ' .
#        'readdir refgen require return rv2av rv2cv rv2gv rv2hv rv2sv ' .
#        'sassign scalar seq shift sne split stat stringify stub substr ' .
#        'undef unshift unstack ' .
#
#        # Relocating to multiple Locations (requires more operations).
#        # Most of these are needed by Carp.pm, which is used by IO::Socket 
#        # (among other modules).
#
#        'anonhash anonlist ' .
#        'exists ' .
#        'keys ' .
#        'gt ' .
#        'length lt ' .
#        'mapstart ' .
#        'ord ' .
#        'postinc predec preinc ' .
#        'redo ref ' .
#        'sprintf subtract ' .
#        'wantarray ' .  
#
#        # Adding the ops required by Crypt::RSA and its support modules.
#
#        'anoncode ' . 
#        'bless bit_and bit_or bit_xor ' .
#        'chr close complement ' .
#        'divide delete dofile ' .
#        'each enterwrite eof ' .
#        'fcntl fileno flip flop formline fteread ftfile ftis ftsize ' .
#        'ge getc ' .
#        'hex ' 
#        'int index ioctl ' .
#        'lc le left_shift lslice '
#        'modulo multiply '
#        'oct open '
#        'pack padsv postdec pow print prtf '
#        'quotemeta ' .
#        'rand read readline repeat reverse regcreset ' . 
#        'select splice srand sysread syswrite '
#        'tell tie trans truncate '
#        'uc unpack '
#        'values vec '
#        'warn '
#        'xor ' 
#

Location.pm  view on Meta::CPAN

# Documentation starts here.
##########################################################################

=pod

=head1 NAME

"Mobile::Location" - a class that provides for the creation of Scooby mobile agent environments (aka Location, Site or Place).

=head1 VERSION

4.0x (the v1.0x, v2.0x and v3.0x series were never released).

=head1 SYNOPSIS

use Mobile::Location;

my $location = Mobile::Location->new;

$location->start_sequential;

or 

$location->start_concurrent;


=head1 SOME IMPORTANT NOTES FOR LOCATION WRITERS

1. Never, ever run a Location as 'root'.  If you do, this module will die.  Running as 'root' is a serious security risk, as a mobile agent is foreign code that you are trusting to execute in a non-threatening way on your computer.  (Can you spell th...

2. The B<Mobile::Location> class executes mobile agents within a restricted environment.  See the B<Ops> argument to the B<new> method, below, for more details.

3. Never, ever run a Location on the same machine that is acting as your keyserver (it's a really bad idea, so don't even think about it).

=head1 DESCRIPTION

Part of the Scooby mobile agent machinery, the B<Mobile::Location> class provides a convenient abstraction of a mobile agent environment.  Typical usage is as shown in the B<SYNOPSIS> section above.  This class allows for the creation of a passive, T...

=head1 Overview

Simply create an object of type B<Mobile::Location> with the B<new> method.  To start a sequential server, use the B<start_sequential> method.  To start a concurrent server, use the B<start_concurrent> method.

=head1 Construction and initialization

Create a new instance of the B<Mobile::Location> object by calling the B<new> method:

=over 4

my $location = Mobile::Location->new;

=back

Optional named parameters (with default values) are:

=over 4

B<Debug (0)> - set to 1 to receive STDERR status messages from the object.

B<Port (2001)> - sets the protocol port number to accept connections on.

B<Log (0)> - set to 1 to instruct the Location to log the received mobile agent to disk prior to performing any mutation.  The name of the logged agent is "last_agent_PID.log", where PID is the process identifier of the Location.  On sequential Locat...

B<Ops ('')> - add a list of Opcodes to the Opcode mask that is in effect when the mobile agent executes.  Study the standard B<Opcode> and B<Ops> modules for details on Opcodes and how they are set.  One way to secure your Location against attack is ...

B<Web (1)> - turns on the HTTP-based Monitoring Service running on port 8080 (HTTP_PORT), thus enabling remote monitoring of the Locations current status.  It also logs interactions with this Location into 'location.log' (LOGFILE).  Set to 0 to disab...

=back 

Note that any received mobile agent executes in a directory called "Location", which will be created (if needs be) in the directory that houses this Location.  Any "logs" are also created in the "Location" directory.

A constructor example is:

=over 4

my $place = Mobile::Location->new( Port => 5555, Debug => 1 );

=back

creates an object that will display all STDERR status messages, and use protocol port number 5555 for connections.  Logging of received agents to disk is off.  The standard Opcode mask is in effect.  And logging to disk is on, as is the HTTP server.

When the Location is constructed with B<new>, a second network service is created, running at protocol port number B<Port+1>.  In the example above, this second network service would run at protocol port number 5556.  When sent the names of a set of ...

Note: If a Location crashes (or is killed), the second network service can sometimes keeps running.  After all, it is a separate process (albeit a child of the original).  Trying to restart the Location results in an "bind to address failed" error me...

=head1 Class and object methods

=over 4

=item B<start_concurrent> 

Start the location as a passive server, which operates concurrently.  Once connected to a client, the server forks another process to receive and continue executing a mobile agent.  This is the preferred method to use when there exists the potential ...

=item B<start_sequential>

Start the location as a passive server, which operates sequentially.  Once connected to a client, the server sequentially processes the receipt and continued executing of a mobile agent.  This is OK if the agent is quick and not processor intensive. ...

=back

=head1 Internal methods/subroutines

The following list of subroutines are used within the class to provide support services to the class methods.  These subroutines should not be invoked through the object (and in some cases, cannot be invoked through the object).

=over 4

=item B<_generate_label>

Takes a filename and line number, then combines them with the current time to produce a random, unique label.

=item B<_check_for_modules>

Given a list of module names, checks to see if the Location's Perl system has the module installed or not.

=item B<_spawn_network_service>

Used by the B<new> constructor to spawn the Port+1 network service which listens for a list of modules names from a mobile agent, then checks for their existence within the locally installed Perl system.

=item B<_service_client>

Given a socket object (and the instances init data), service the relocation of a Scooby mobile agent.

=item B<_register_with_keyserver> 

Creates a PK+ and PK- value for the server, storing the PK+ in the keyserver, and the PK- in the object's state.

=item B<_logger> and B<_logger2>

Logs a message to the LOGFILE.

=item B<_build_index_dot_html>

Builds the INDEX.HTML page for use by the HTTP-based Monitoring Service.

=item B<_build_clearlog_dot_html>

Builds the CLEARLOG.HTML page for use by the HTTP-based Monitoring Service.

=item B<_start_web_service>

Starts a small web server running at port 8080 (HTTP_PORT), and uses the two "_build_*" routines just described.

=item B<_spawn_web_monitoring_service>

Creates a subprocess and starts the web server.

=back

=head1 SEE ALSO

The B<Mobile::Executive> module (for creating mobile agents), as well as B<Devel::Scooby> (for running mobile agents).

The Scooby Website: B<http://glasnost.itcarlow.ie/~scooby/>.

=head1 AUTHOR

Paul Barry, Institute of Technology, Carlow in Ireland, B<paul.barry@itcarlow.ie>, B<http://glasnost.itcarlow.ie/~barrypi/>.

=head1 COPYRIGHT

Copyright (c) 2003, Paul Barry.  All Rights Reserved.

This module is free software.  It may be used, redistributed and/or modified under the same terms as Perl itself.



( run in 0.829 second using v1.01-cache-2.11-cpan-5511b514fd6 )