Newsgroup: it.comp.lang.perl
Titolo: Progetto iNaio NAT

Progetto: iNaio NAT (share your music over the internet)
Versione: 1.1
                 HOST A                                HOST B
                          |                       |
                          |      UDP TUNNEL       |
     SEVER <-- +-------+--|-----------------------|--+-------+ <-- CLIENT
               | MED A |  |       INTERNET        |  | MED B |
      MP3  --> +-------+--|-----------------------|--+-------+ -->  MP3
                          |                       |
                          |                       |
                         NAT                     NAT
                        HOST A                  HOST B
MED A = mediatore su HOST A
MED B = mediatore su HOST B
Su "HOST A" ho un Client MP3, esso non fa altro che creare una 
connessione con il server per richiedere un file mp3 o parte di esso 
(Range: bytes=$bytes-). Quindi non ci sono connessioni 
contemporanee...solo un mp3 alla volta. Tuttavia il Server mp3 su "HOST 
B" non direttamente raggiungibile in quanto dietro NAT. Per questo viene 
utilizzato "Nat-Traverse" che crea un tunnel UDP che permette di 
collegare entrambi gli hosts (tutti e due dietro NAT). Una volta 
stabilita la connessione "Nat-Traverse" duplica il proprio socket UDP su 
STDIN e STDOUT (quindi se da "HOST A" faccio print STDOUT $_; ricever il 
messaggio su "HOST B" con $_ = <STDIN> ... e viceversa).
Lo Scenario è il seguente: su "HOST A" ho un Client MP3 (una finestra 
con lista di files...doppio click su un file crea una connessione 
IO::Socket::INET che attende una response...raw mp3 data). Tuttavia non 
posso collegare il Client MP3 direttamente con il tunnel UDP. Ho Bisogno 
di un mediatore, un semplice server che riceve la request dal Client MP3 
e la redirige tramite STDOUT nel tunnel UDP. Tutto quello che arriver 
dal tunnel lo andr a leggere con <STDIN> ... questa sar la response alla 
richiesta fatta dal Client MP3.
Passiamo ora a "HOST B". Anche in questo caso ho bisogno di un mediatore 
tra tunnel UDP e Server MP3 (il Server MP3 prende come request un id 
univoco del file mp3 e risponde con il file mp3 grezzo). In questo caso 
il mediatore su "HOST B" aspetter di leggere tramite <STDIN> la request 
in arrivo dal tunnel, creer una conessione IO::Socket::INET con il 
Server MP3 e inoltrer la response nel tunnel tramite STDOUT. 
Questo è solo un primo stadio dell'applicazione, so che facendo 
viaggiare svariati MB di dati su UDP (tutti a chunks di 1024) potrei 
essere soggetto a perdite dei dati stessi, cmq essendo dati audio non 
sar un gran problema (almeno per adesso).
Ora vorrei parlare della necessit del multitasking del mediatore su 
"HOST A" (ovvero l'applicazione server che si pone tra Client MP3 e 
tunnel UDP). Avrei bisogno che ogni connessione dal Client MP3 crei un 
nuovo processo, che venga in seguito killato dal prossimo nuovo processo 
(selezione di un altro mp3) per liberare <STDIN> che sta ricevendo dati 
e per chiudere il socket (di response) con il Client MP3. Lo stesso 
dovrebbe avvenire sul mediatore su "HOST B" ovvero all'arrivo  di una 
nuova richiesta killare subito il processo che sta inoltrando dati nel 
tunnel UDP tramite STDOUT.
MED A.source
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Handle;
STDOUT->autoflush(1);
my $key;
my %header;
my $req;
my $line;
while(1)
{
   chomp($line = <STDIN>);
   while( defined($_ = <STDIN>) )
   {  
      s/[\r\n]+$//;
      last unless length $_;
      /^ ([\w\-]+) :[\ \t]+ (.+) $/x;
      $key = uc($1);
      $key =~ tr/-/_/;
      $header{$key} = $2
   }
 
   $req = "$line\n";
 
   foreach (sort keys %header)
   {
      $req .= $_ . ':' . " $header{$_}\n";
   }
 
   $req .= "\n";
 
   {
   my ($buff, $sock);
   $sock = IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => 
'80', Proto => 'tcp') || die "$!";
   $sock->autoflush(1);
 
   syswrite $sock, $req;
 
   while ( sysread($sock, $buff, 1024) )
   {
      print STDOUT $buff;
   }
 
   close($sock);
   }
}
MED B.source
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use IO::Handle;
STDOUT->autoflush(1);
my $server = IO::Socket::INET->new(LocalPort => '65001', Proto => 'tcp', 
Reuse => 1) || die $!;
my $client;
my $buff;
while ( $server->listen() )
{
   $client = $server->accept();
   $client->autoflush(1);
 
   recv($client, $buff, 1024, 0);
 
   print STDOUT $buff;
 
   syswrite $client, $_ while sysread \*STDIN, $_, 1024;
   close($client);
}
close($server);

 Versione: 1.1
http://www.theartofweb.net/figura.txt