#defines

my ( $argc ) = scalar @ARGV;

if ( $argc > 2 )
{
    my ( $command ) = $ARGV[2];

    if ( $command eq "stats" )
    {
        if ( $argc > 3 )
        {
            usage();
        }
        else
        {
            command( $command );
        }
    }
    elsif ( $command eq "init" )
    {
        if ( $argc > 4 )
        {
            usage();
        }
        else
        {
            if ( $argc == 3 )
            {
                command( $command );
            }
            else
            {
                command( $command." ".$ARGV[3] );
            }
        }
    }
    elsif ( $command eq "start" )
    {
        if ( $argc > 4 )
        {
            usage();
        }
        else
        {
            if ( $argc == 3 )
            {
                command( $command );
            }
            else
            {
                command( $command." ".$ARGV[3] );
            }
        }
    }
    elsif ( $command eq "stop" )
    {
        if ( $argc > 4 )
        {
            usage();
        }
        else
        {
            if ( $argc == 3 )
            {
                command( $command );
            }
            else
            {
                command( $command." ".$ARGV[3] );
            }
        }
    }
    elsif ( $command eq "shutdown" )
    {
        if ( $argc > 3 )
        {
            usage();
        }
        else
        {
            if ( $argc == 3 )
            {
                command( $command );
            }
        }
    }
    elsif ( $command eq "reset" )
    {
        if ( $argc > 4 )
        {
            usage();
        }
        else
        {
            if ( $argc == 3 )
            {
                command( $command );
            }
            else
            {
                command( $command." ".$ARGV[3] );
            }
        }
    }
    elsif ( $command eq "forward" )
    {
        if ( $argc < 5 )
        {
            usage();
        }
        else
        {
            my ( $i ) = 0;
            my ( $commandToSend ) = "";

            for ( $i = 2; $i < $argc; $i++ )
            {
                $commandToSend = $commandToSend.$ARGV[ $i ];

                if ( $i != ( $argc - 1 ) )
                {
                    $commandToSend = $commandToSend." ";
                }
            }

            command ( $commandToSend );
        }
    }
    else
    {
        usage();
    }
}
else
{
    usage();
}

sub usage
{
    printf( "usage:\n" );
    printf( "ip port stats                        returns XML statistics for each process\n" );
    printf( "ip port reset <processName>          resets the number of times started to 0 for the process specifed/each process\n" );
    printf( "ip port init <processName>           returns XML style run level for the process specified/each process\n" );
    printf( "ip port start <processName>          starts the process specified/each process\n" );
    printf( "ip port stop <processName>           terminates the process specified/each process\n" );
    printf( "ip port shutdown                     terminates all processes and the process manager\n" );
    printf( "ip port forward processName command  forwards the command to the process specified\n" );
    printf( "\n");
    printf( "where:\n" );
    printf( "- ip is the ip address of the target process manager\n" );
    printf( "- port is the port used by the target process manager\n" );
    printf( "- processName must match a processName returned by the stats command\n" );
    printf( "- command is a process specific command shell command with appropriate arguments\n" );
}

sub command
{
    my ( $command ) = @_;
    my ( $rmask, $nfound, $nread );
    my ( $buf, $response );

    use IO::Socket;

    # create the server socket, do not allow pending connections
    # do not allow the socket to be bound to an address that is already in use
    my ( $CLIENT ) = IO::Socket::INET->new( PeerAddr => $ARGV[0],
                                            PeerPort => $ARGV[1],
                                            Proto => 'tcp' );

    if ( ! defined($CLIENT) || $CLIENT == 0 )
    {
        die "Cannot create client socket on port $PORT";
    }

    # protocol 1, client sends
    $CLIENT->send("$command\n", 0) || die "Cannot send command to Process Monitor\n";
    
    # protocol 2, prevent further data being sent
    $CLIENT->shutdown( 1 );

    # protocol 3, client receives
    while (1)
    {
        $rmask = "";
        $buf = "";
        vec($rmask, $CLIENT->fileno(), 1) = 1;
        $nfound = select($rmask, "","", 60);
        if ($nfound) 
        {
            $nread = $CLIENT->sysread($buf, 1024);
            if ($nread > 0) 
            {
                $response .= $buf;
            }
            else
            {
                die "ERROR: EOF reached before end of message";
            }

            if ( $response =~ s/end\n$// )
            {
                print $response;
                last;
            }
        }
        else 
        {
            die "ERROR: Timeout waiting for response from Process Manager\n";
        }

    } 

    # protocol 4, client closes
    $CLIENT->close();
}
