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 <sameer@soda.berkeley.edu> ($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 <sameer@soda.berkeley.edu> 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';