[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Magic Money Client/Server using IPC



	As I posted only a few hours ago, I have been working on
improving the Magic Money interface. I've written a server application
for the Magic Money server which allows the server to sit on a port
and wait for connections. When a connection comes in it forks and
processes the request, by just taking the input, passing it to the 's'
server released by Pr0duct Cypher, and then returning the server's
output.

	The client is a front end to Pr0duct Cypher's 'c' program,
which handles the communication between the 'c' client and the server
running on a socket. I have written the client so that it can be run
from any directory, but it looks in ~/.bank for the bank.asc,
rand.dat, and other files that the program uses.

	I just wrote this code today, so I'm sure it lacks many safety
checks. If you'd like to point out where it goes wrong, I'd appreciate
it greatly.
	
To invoke the server:

Edit server.pl and give it the port number you want.

Run 'server.pl' in the directory which has the 's' program and the files that
the 's' program uses. server.pl will fork and wait on the port specified.

To run the client:

Create the ~/.bank directory, and put rand.dat and bank.asc in that
directory.

Edit the client.pl to reflect the port number and the hostname of the
server, as well as the location of Pr0duct Cypher's 'c' binary.

client.pl -initialize

	Generates your account.

client.pl -incoming [filename]

	Takes in incoming coins (which someone has given you) either from
filename or stdin (if the filename argument is missing) and adds their
value to your wallet. (Doing the communication with the server that is
necessary)

client.pl -extract [filename]

	Extract coins that you own into filename, or if filename
doesn't exist pgp ascii-armor the coins and send them to stdout.

client.pl -exchange

	Exchange your old coins for new ones.


server.pl:
#!/usr/local/bin/perl
# Perl script to attach a Magic Money Server to a port
# Sameer <[email protected]>


($port) = @ARGV;
$port = 1992 unless $port;
$magicserver = "s";
$waitlock = "waiter.pid";
$processlock = "processor.pid";

require 'sys/socket.ph';
require './shlock.pl';

# First check to see if the process is running
unless(&shlock($waitlock))
{
    print "Process already running\n";
    exit;
}

$sockaddr = 'S n a4 x8';

($name, $aliases, $proto) = getprotobyname('tcp');
($name, $aliases, $port) = getservbyname($port, 'tcp')
    unless $port =~ /^\d+$/;

$this = pack($sockaddr, &AF_INET, $port, "\0\0\0\0");

select(NS); $| = 1; select(stdout);

socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
bind(S, $this) || die "bind: $!";
listen(S, 5) || die "connect: $!";

select(S); $| = 1; select(stdout);

# Ok the socket has been setup. Fork, wait for the parent lock to die
# and then lock again
if(fork)
{
    exit;
}

# Wait for the old process to die
sleep 10 unless(&shlock($waitlock));

for (;;) {
#    print "Listening again\n";
    ($addr = accept(NS,S)) || die $!;
    unless(fork)
    {
#        print "accept ok\n";
	($af,$port,$inetaddr) = unpack($sockaddr,$addr);
	@inetaddr = unpack('C4',$inetaddr);
#	print "$af $port @inetaddr\n";

	$tmpin = "/tmp/mmin." . $$ ;
	$tmpout = "/tmp/mmout." . $$ ;

	open(TIN, ">$tmpin") || die $!;

	print NS "Magic Money Bank: " . $bank . "\n";
	print NS "Feed server\n";
	while (<NS>) {
	    print TIN;
	    last if /^-----END/ ;
	}
	close(TIN);

	# Wait for the process lock to stop

	unless(&shlock($processlock))
	{
	    print NS "Please wait for other requests to finish.";
	    do
	    {
		print NS "." ;
		sleep 10;
	    }
	    until(&shlock($processlock));
	}
	
	print NS "order processing.";

	# Run magic money
	open(MM, "| $magicserver > $tmpout");
	open(TIN, $tmpin);
	while(<TIN>)
	{
	    print NS "." ;
	    print MM;
	}
	close(TIN);
	close(MM);

	print NS "done.\nServer response\n";
	open(OUTPUT, $tmpout);
	print NS <OUTPUT>;
	close OUTPUT;
	exit;
    }
}


client.pl:
#!/usr/local/bin/perl
# Perl script to make dealing with the magic money oh so much easier
# Sameer <[email protected]>

require 'sys/socket.ph';

$mmclient = "/usr/local/bin/mmclient" ;
$pgp = "/usr/local/bin/pgp" ;
$port = 1992;
$host = "localhost";

sub connectgrab
{
    local($them, $port, $infile, $outfile) = @_;

    $sockaddr = 'S n a4 x8';
    chop($hostname = `hostname`);

    ($name, $aliases, $proto) = getprotobyname('tcp');
    ($name, $aliases, $port) = getservbyname($port, 'tcp')
	unless $port =~ /^\d+$/;
    ($name, $aliases, $type, $len, $thisaddr) =
	gethostbyname($hostname);
    ($name, $aliases, $type, $len, $thataddr) = gethostbyname($them);
    
    $this = pack($sockaddr, &AF_INET, 0, $thisaddr);
    $that = pack($sockaddr, &AF_INET, $port, $thataddr);
    
    socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
    bind(S, $this) || die "bind: $!";
    connect(S, $that) || die "connect: $!";
    
    select(S); $| = 1; select(stdout);
    
    # Wait until we get the prompt to start
    while(<S>)
    {
	last if /^Feed server$/ ;
    }
   
    # Send the stuff to the server
    print "Sending to server.\n";
    open(INPUT, $infile) || die "can't open $infile: $!";
    while(<INPUT>)
    {
	print S;
    }
    close INPUT;

    # Wait for the server to finish processing.. tell the user it is processing
    print "Waiting for server to process.\n";
    while(<S>)
    {
	last if /^Server response$/;
    }

    # Now grab the server's response
    open(OUTPUT, "> $outfile") || die "can't open $outfile: $!";
    while(<S>)
    {
	print OUTPUT;
    }
    close(OUTPUT);

    close S;
    print "Finished with server.\n";
}

## Main
## Deal with user requests


# Process incoming money

sub processincoming
{
    if($ARGV[0] ne '-')
    {
	$ARGV[0] = &expandfile($ARGV[0]);
    }
    open(FILE, "> temp.dat") || die "can't create temp.dat: $!";
    print FILE <>;
    close FILE;

    system("$mmclient temp.dat");
    unlink("temp.dat");
    &deal;
}

# Initialize client

sub initialize
{
    system("$mmclient -i");
    &deal;
}

# Exchange coins

sub exchangecoins
{
    system("$mmclient -x");
    &deal;
}

sub deal
{
    &connectgrab($host, $port, "output.asc", "serverreply.asc");

    system("$mmclient serverreply.asc");
#    unlink("serverreply.asc");
#    unlink("output.asc");
}

sub extractcoins
{

#    if($ARGV[0] eq '-')
#    {
#	# Error
#	print "Must specify a filename to extract coins to\n";
#	exit;
#    }

    if($ARGV[0] ne '-')
    {
	$file = &expandfile($ARGV[0]);
	
	if( -e $file )
	{
	    # Error
	    print "File already exists\n";
	    exit;
	}
	# Check if the file can be made
	open(FILE, "> $file") || die "Can't create $file: $!";
	close FILE;
	unlink($file);
    }

    system("$mmclient -p");
    # Now move coins.dat away so that another extraction doesn't mean money
    # is lost

    # Send it to another file or stdout

    if($file)
    {
	rename("coins.dat", $file);
	print "Coins moved to $file\n";
    }
    else
    {
	print "Coins going out, ascii armored.\n";
	open(COINSDAT, "coins.dat");
	open(ASCII, "| $pgp -af 2>/dev/null");
	print ASCII <COINSDAT>;
	close ASCII;
	close COINSDAT;
#	unlink("coins.dat");
    }
}

sub expandfile
{
    # If a file has a leading / don't add the startdir
    # otherwise prepend $startdir

    local($fname) = @_;
    if(index($fname, '/') == 0)
    {
	return($fname);
    }
    else
    {
	return($startdir . "/" . $fname);
    }
}

#########
# THE MAIN
#########


# This bit of the program takes the cmdline arguments, etc.
$startdir = $ENV{'PWD'};
chdir($ENV{'HOME'} . "/.bank") || die "can't chdir to ~/.bank: $!";

$command = $ARGV[0];
shift;

unless($ARGV[0])
{
    unshift(ARGV, '-');
}


&processincoming if $command eq '-incoming';
&initialize if $command eq '-initialize';
&exchangecoins if $command eq '-exchange';
&extractcoins if $command eq '-extract';