Newsgroup: it.comp.lang.perl
Titolo: PERL IO::Socket

Dovrebbe essere semplice, vado di tcpdump
 
tcpdump -nnvvvS -s 0 -U -w sniff.ocsp.pcap port 2560
 
quindi tramite Wireshark faccio Analize -> Follow TCP Stream
====================
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105
 
0g0e0>0<0:0...+............$..Qp'....h.......qQ...4...j.v.?..s.......#0!0...+.....0......#P.Qd.;oa..M....
HTTP/1.0 200 OK
Content-type: application/ocsp-response
Content-Length: 1231
 
0...
......0.....+.....0......0...0....m0k1.0...U....IT1.0...U...
====================
 
In pratica il client invia 4 linee di header (compreso \r\n/) e il
file req.der il server (la parte che mi interessa) invia 4 linee di 
risposta ed il file di risposta, fine della trasmissione.
 
ora, qualcuno ha idea del perché se faccio:
 
#!/usr/bin/perl
use IO::Socket;
 
my $server = IO::Socket::INET->new(
     Listen => 5,
     LocalAddr => '192.168.1.10',
     LocalPort => 2560,
     Proto     => 'tcp'
) or die "Can't create server socket: $!";
$server->autoflush(1);
 
 
while ($client = $server->accept()) {
		$client->autoflush(1);
while (<$client>)
	{
	print $_;
	}
 
lancio il client
 
===================
#!/bin/bash
openssl ocsp -issuer cacert.pem \
	-nonce \
	-CAfile cacert.pem \
	-cert 03.pem \
	-url 
http://www.
...com:2560 \
	-resp_text
====================
 
e lato server vedo le 4 stringhe
 
======
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105
 
======
 
dopodiché s'impalla restando fermo, ma se lato client vado di ctrl+c
lato server riceve e stampa anche il resto.
 
Come la sfango?
 
 
 

 lato server riceve e stampa anche il resto.
 
Devi onorare Content-Length: il tuo server perl deve "sapere" che l'input
dovrà considerarsi concluso quando saranno stati trasmessi $contentLength 
byte (in questo caso 105) e comportarsi di conseguenza.
 
 
Fabio

 byte (in questo caso 105) e comportarsi di conseguenza.
 
Mi sarò espresso male, segue esempio:
 
se faccio un semplice client:
==============
#!/usr/bin/perl -w
use IO::Socket;
use strict;
my $server = IO::Socket::INET->new(
  				   PeerAddr => '192.168.1.10',
     				   PeerPort => 2560,
     				   Proto    => 'tcp',
				   );
die "Can't create client socket: $!\n" unless $server;;
 
print $server "POST / HTTP/1.0\n";
print $server "Content-Type: application/ocsp-request\n";
print $server "Content-Length: 105\n";
print $server "\r\n";
 
open FILE, "<req.pem" or die "Can't open: $!";
     binmode FILE;
         while (<FILE>) {
	print $server $_;
	}
	 close FILE;
 
close($server);
 
===============
 
lato server vedo correttamente come ci si aspetterebbe
 
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105
 
MGcwZTA+MDwwOjAJBgUrDgMCGgUABBT58QaHJAzeUXAn9g6XtGiy2IsVuQQUcVGA
mhc0nIWGagB2xD/OqnMd9xECAQOiIzAhMB8GCSsGAQUFBzABAgQSBBD9AtP24ybs
eYRCb8ilwDV4
 
ovvero l'header che ho inviato seguito dal contenuto del file req.pem, 
ora, che ci sia un *Content-Length* nel mezzo a Perl dubito che importi 
qualcosa, quello serve a me poi, ma per lui è una semplice sequenza di 
caratteri ASCII che invia al server..
 
Il problema è che se anziché il suddetto script utilizzo openssl per 
qualche motivo che al momento non comprendo si impalla dopo l'invio 
dell'header come se aspettasse una risposta dal server (che in genere 
può essere una stringa tipo HTTP/1.0 200 OK) ma dato che la 
comunicazione tra client e server è stata sniffata con tcpdump e non 
presenta nessuna risposta tra l'invio dell'header ed il body del file 
che si fa?
 
 
 
 
 
 

 caratteri ASCII che invia al server..
 
Visto che il problema te lo hanno evidenziato e visto che continui a dire 
che non ti interessa, il mio consiglio è di andarti a studiare qualche RFC 
giusto perchè procedere a tastoni di solito fa perdere tempo.
 
 
Poi se usi il tuo di server, allora il discorso, come ti ho detto, cambia.
Ed in particolare:
- se usi come trasporto il protocollo HTTP, allora studiatelo ed 
implementalo correttamente
- se usi come trasporto qualcosa di tua invenzione che è simile all'http, 
allora senza capire cosa vuoi fare c'è poco da aiutarti.
 
 
Ah, dimenticavo. 
icol.sys può non essere il NG Adatto.
Qualcosa sul perl o sulla programmazione lo è di più.

 print $server "\r\n";
 
che indica al tuo server perl che la trasmisisone è finita e ti stampa
il contenuto del buffer. Openssl invece parla HTTP vero e non ti invia 
alcun "\r\n", perchè si aspetta che il server dall'altra parte parli a 
a sua volta HTTP e usi Content-Lenght per il controllo di flusso.
 
Se vuoi ti riassumo così: il tuo server perl non è una implementazione
valida di HTTP e quindi non può parlare con un client HTTP.
 
 
Fabio

 valida di HTTP e quindi non può parlare con un client HTTP.
 
Mi pare abbia incollato il codice di un client, non di un server.
 

Il 13/12/11 13.27, CtRiX ha scritto:

Ok ho fatto un passo avanti spero..
 
se invio al server un file encoded base64 vedo
 
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105
 
MGcwZTA+MDwwOjAJBgUrDgMCGgUABBT58QaHJAzeUXAn9g6XtGiy2IsVuQQUcVGA
mhc0nIWGagB2xD/OqnMd9xECAQOiIzAhMB8GCSsGAQUFBzABAgQSBBD9AtP24ybs
eYRCb8ilwDV4
 
ma se lo invio in formato .der il server s'impalla dopo l'header ed il 
client resta appeso
 
Ovviamente il server è ultra minimale ed ha il solo scopo di 
visualizzare ciò che arriva effettivamente dal client
 
#!/usr/bin/perl -w
use IO::Socket;
$local = IO::Socket::INET->new(
                 Proto     => 'tcp',
                 LocalPort => '2560',
  		Listen => SOMAXCONN,
                 Reuse     => 1
                 ) or die "$!";
$local->autoflush(1);
 
my $addr;
while ($addr = $local->accept()) {
         my $result;
         while (<$addr>) {
                 print "$_";
	       }
         close $addr;
}
 
 
quindi penso sia legato alla modalità di invio binario del file.. indago.
 

 Mi pare abbia incollato il codice di un client, non di un server.
 
Quello del server è nel post precedente.
 
 
Fabio

 indago.
 
Ancora non si è capito cosa vuoi fare.
Consiglio:
 
1) leggiti le RFC di HTTP/1.0 e 1.1. Servono.
 
2) chiarisci bene *cosa* devi fare. Se il tuo scopo è scrivere un client, 
scrivere un server o scriverli entrambi.
 

 Come la sfango?
 
Comunque con quel codice il perl va a leggere riga per riga.
 
Se la fine della riga (Del payload) non contiene un EOL, la lettura non 
ritorna e quindi il server rimane in attesa.
Quando interrompi il client, chiudi il socket ed il server esce dal loop.
 
Come ti è stato detto devi andare a ONORARE il content length e leggere 
in input SOLO quei bytes indicati nel content length.

Il 13/12/11 14.44, CtRiX ha scritto:

Vorrei fare il server, come client useremo openssl.
 
Ricapitolando, da qualche test fatto il problema stà nell'invio del file 
binario,
 
In pratica il file binario è privo di eof il ché impalla il server
 
Questo lo si capisce manipolando il client PERL dato che il client 
openssl non è manipolabile, per cui se inserisco un
 
print $server "\n";
 
dopo aver inviato il contenuto del file .der ed imposto il server in 
binmode passa tutto e vedo
 
POST / HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 105
 
0g0e0>0<0:0	+???$
                      ?Qp'???h?؋?qQ??4???jv??Ϊs??#0!0	+0???g	?4?Eo~5^?<?
 
il problema quindi è riuscire a far si che il server non si pianti ma 
come impedirlo se il file è privo di eof?
 

Il 13/12/11 15.06, CtRiX ha scritto:

Ok e come si fa?


Conti i byte ricevuti!
 

 Conti i byte ricevuti!
 
Ok ma mi sono impallato con la lettura
 
#!/usr/bin/perl -w
  use IO::Socket;
  my $port=shift || die "Usage 
server.pl
 <port>\n";
  my $server = IO::Socket::INET->new( Proto => 'tcp',
  LocalPort => $port,
  Listen => SOMAXCONN,
  Reuse => 1);
  die "can't setup server" unless $server;
 
binmode $server;
 
  while ($client = $server->accept()) {
                 $client->autoflush(1);
 
binmode $client;
my $cl;
my $content;
my $n;
while(my $line = <$client>)
         {
         next if($line =~ /^POST \/ HTTP\/1.0/);
         next if($line =~ /^Content-Type: application\/ocsp-request/);
         if($line =~ /Content-length:/isg)
                 {
                 ($cl) = $line =~ /Content-Length: ([0-9]+)/i;
                 }
         next if($line =~ /^Content-Length:/);
         next if($line =~ /^\r\n/);
 
#print "$line";
#qui andrebbe la funzione di lettura
#read FILEHANDLE, SCALAR, LENGTH
 
         open(IN, ">in.der") or die "can't open in.der\n";
         binmode(IN);
         print IN $content;
         close IN;
 
 
}
 
#risposta al client <>
 
   close $client;
}
 
 
 

 Ok e come si fa?
 
Guarda, i consigli sono due:
1) cerca di capire i socket, l'accesso concorrente di più client e l'HTTP 
come protocollo.
Questo ti serve per capire cosa stai facendo e i potenziali problemi a 
cui vai incontro.
Se un giorno avrai bug o problemi col codice, le informazioni che ti ho 
consigliato di studiare sono *fondamentali* per il problem solving
 
2) parallelamente al punto 1) il perl ha il vantaggio che esiste già 
scritto quasi tutto.
Quindi, senza reinventare la ruota, usa google per trovare un modulo 
carino che implementi già un server web.
Risparmi sicuramente tempo.
 

Io bazzico il Perl da poco, e non vorrei per questo dire un'amenità,
però credo che il problema sia nel while(my $line = <$client>), nel
senso che tu tenti di leggere dal sock una "linea" di testo, quindi
resti in attesa di ricevere un dato con un \n alla fine e questo va
bene finché devi ricevere le prime quattro linee del client.
Però una volta intercettata la linea "\r\n" dovresti uscire dal while
e leggere i dati dal sock in modo "binario" fino ad aver ricevuto la
quantità di byte indicati in precedenza nel content-length. Solo a
quel punto il tuo script può tornare ad effettuare la lettura nella
modalità "testo" del tipo while ($line = <$client>).
 

Il 14/12/11 13.04, Darkbyte ha scritto:

E qui si impiastra il tutto, se leggo while(my $line =<$client>) 
estrapolo il content-length  e tento di leggere in binario non funziona, 
se invece leggo tutto in binario allora funziona ma non posso leggere il 
parametro content-length.
 
al momento ho una versione perfettamente funzionante con
 
my ($header, $data);
my $data_header = recv($client, $header, 80, 0);
my $from_client = recv( $client, $data, 106,0);
my $length = length($data);
 
ma questo funziona solo a patto che l'header sia 80 e i dati 105 cosa 
non sempre vera dato che openssl legge dal certificato l'Authority 
Information Access e nel caso trova
 
OCSP - URI:
http://ocsp.infocert.it/OCSPServer_ICE/OCSPServlet
 
 
imposta l'header con
 
POST /OCSPServer_ICE/OCSPServlet HTTP/1.0
Content-Type: application/ocsp-request
Content-Length: 107
 
il ché ci riporta al problema di leggere sto benedetto Content-Length

Il 14/12/11 13.04, Darkbyte ha scritto:

Ecco come ho risolto:
 
 
while ($client = $server->accept()) {
                 $client->autoflush(1);
 
my $data;
my $from_client = recv( $client, $data, 1024,0);
 
open(IN, ">in.der") or die "can't open in.der\n";
         binmode(IN);
         print IN $data;
         close IN;
 
open(FILE, "<in.der");
open(FILEOUT,">myout.der");
binmode(FILEOUT);
binmode(FILE);
 
while(my $line =<FILE>)
         {
         next if($line =~ /^POST \/ HTTP\/1.0/);
         next if($line =~ /^Content-Type: application\/ocsp-request/);
         next if($line =~ /^Content-Length:/);
         next if($line =~ /^\r\n/);
 
         print FILEOUT $line;
         }
close FILE;
close FILEOUT;
 
a questo punto si può processare myout.der e rispedire al client la risposta

Come leggi in binario? Usi $client->recv()?

 Ecco come ho risolto:
 
Come ti avevo suggerito, io avrei usato HTTP::Daemon o qualcosa di simile.
Il tuo codice gestisce sempre un client solo alla volta (e quindi non 
scala).

 scala).
 
Se il problema fosse solo quello, basterebbe forkare il processo con
 
while ($client = $server->accept()) {
   		$client->autoflush(1);
 
next if my $pid = fork;
die "fork - $!\n" unless defined $pid;
 
e killarlo alla chiusura del client
 
close $client;
exit(fork);
 
Ma prima bisognerebbe implementare la gestione dei nomi dei file 
temporanei con qualcosa tipo File::Temp, nonché pensare ad un Timeout di 
eventuali sessioni aperte