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 $_ = ... 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 ... 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 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 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 = ); while( defined($_ = ) ) { 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);