Risistemato tutto il primo esempio di server echo e le funzioni FullWrite e
authorSimone Piccardi <piccardi@gnulinux.it>
Sun, 27 Jul 2003 23:41:04 +0000 (23:41 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sun, 27 Jul 2003 23:41:04 +0000 (23:41 +0000)
FullRead.

13 files changed:
elemtcp.tex
listati/ClientEcho.c
listati/FullRead.c
listati/FullWrite.c
listati/PrintErr.c
listati/ServEcho_first.c [new file with mode: 0644]
socket.tex
sources/FullRead.c
sources/FullWrite.c
sources/TCP_echo.c
sources/TCP_echo_first.c
sources/TCP_echod.c
sources/TCP_echod_first.c

index 1ae67f4a24b6bc29b1806b2b3e737b08ac5c01dc..b366d5f12b0d08e5a46fb16684486dcfb315c752 100644 (file)
@@ -71,7 +71,7 @@ scambiati) che porta alla creazione di una connessione 
   client, inoltre anche il server deve inviare il suo SYN al client (e
   trasmettere il suo numero di sequenza iniziale) questo viene fatto
   ritrasmettendo un singolo segmento in cui sono impostati entrambi i flag SYN
-  ACK.
+  ACK.
   
 \item una volta che il client ha ricevuto l'acknowledge dal server la funzione
   \func{connect} ritorna, l'ultimo passo è dare dare il ricevuto del SYN del
@@ -101,7 +101,7 @@ stabilisce la connessione.
 \end{figure}
 
 Si è accennato in precedenza ai \textsl{numeri di sequenza} (che sono anche
-riportati in \figref{fig:TCP_TWH}); per gestire una connessione affidabile
+riportati in \figref{fig:TCP_TWH}): per gestire una connessione affidabile
 infatti il protocollo TCP prevede nell'header la presenza di un numero a 32
 bit (chiamato appunto \textit{sequence number}) che identifica a quale byte
 nella sequenza del flusso corrisponde il primo byte della sezione dati
@@ -170,29 +170,27 @@ elevati. In ogni caso Linux supporta pienamente entrambe le opzioni.
 \subsection{La terminazione della connessione}
 \label{sec:TCP_conn_term}
 
-Mentre per creare una connessione occorre un interscambio di tre segmenti, la
-procedura di chiusura ne richiede quattro; ancora una volta si può fare
-riferimento al codice degli esempi \figref{fig:TCP_daytime_client_code} e
-\figref{fig:TCP_daytime_iter_server_code}, in questo caso la successione degli
-eventi è la seguente:
+Mentre per la creazione di una connessione occorre un interscambio di tre
+segmenti, la procedura di chiusura ne richiede normalmente quattro. In questo
+caso la successione degli eventi è la seguente:
 
 \begin{enumerate}
 \item Un processo ad uno dei due capi chiama la funzione \func{close}, dando
   l'avvio a quella che viene chiamata \textsl{chiusura attiva} (o
   \textit{active close}). Questo comporta l'emissione di un segmento FIN, che
-  significa che si è finito con l'invio dei dati sulla connessione.
+  serve ad indicare che si è finito con l'invio dei dati sulla connessione.
   
-\item L'altro capo della connessione riceve il FIN ed esegue la
-  \textsl{chiusura passiva} (o \textit{passive close}); al FIN, come ad ogni
-  altro pacchetto, viene risposto con un ACK. Inoltre il ricevimento del FIN
+\item L'altro capo della connessione riceve il FIN e dovrà eseguire la
+  \textsl{chiusura passiva} (o \textit{passive close}). Al FIN, come ad ogni
+  altro pacchetto, viene risposto con un ACK, inoltre il ricevimento del FIN
   viene segnalato al processo che ha aperto il socket (dopo che ogni altro
   eventuale dato rimasto in coda è stato ricevuto) come un end-of-file sulla
-  lettura, questo perché il ricevimento di un FIN significa che non si
+  lettura: questo perché il ricevimento di un FIN significa che non si
   riceveranno altri dati sulla connessione.
-
-\item Dopo un certo tempo anche il secondo processo chiamerà la funzione
-  \func{close} sul proprio socket, causando l'emissione di un altro segmento
-  FIN. 
+  
+\item Una volta rilevata l'end-of-file anche il secondo processo chiamerà la
+  funzione \func{close} sul proprio socket, causando l'emissione di un altro
+  segmento FIN.
 
 \item L'altro capo della connessione riceverà il FIN conclusivo e risponderà
   con un ACK.
@@ -352,10 +350,8 @@ Ogni implementazione del TCP deve scegliere un valore per la MSL
 (l'\href{http://www.ietf.org/rfc/rfc1122.txt}{RFC~1122} raccomanda 2 minuti,
 Linux usa 30 secondi), questo comporta una durata dello stato
 \texttt{TIME\_WAIT} che a seconda delle implementazioni può variare fra 1 a 4
-minuti.
-
-Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due motivi
-principali:
+minuti.  Lo stato \texttt{TIME\_WAIT} viene utilizzato dal protocollo per due
+motivi principali:
 \begin{enumerate}
 \item implementare in maniera affidabile la terminazione della connessione
   in entrambe le direzioni.
@@ -379,13 +375,13 @@ verrebbe interpretato come un errore.
 Se il TCP deve poter chiudere in maniera pulita entrambe le direzioni della
 connessione allora deve essere in grado di affrontare la perdita di uno
 qualunque dei quattro segmenti che costituiscono la chiusura. Per questo
-motivo lo stato \texttt{TIME\_WAIT} deve essere mantenuto anche dopo l'invio
-dell'ultimo ACK per poter essere in grado di poterne gestire l'eventuale
-ritrasmissione in caso di perdita.
+motivo un socket deve rimanere attivo nello stato \texttt{TIME\_WAIT} anche
+dopo l'invio dell'ultimo ACK, per potere essere in grado di gestirne
+l'eventuale ritrasmissione, in caso esso venga perduto.
 
 Il secondo motivo è più complesso da capire, e necessita di una spiegazione
-degli scenari in cui accade che i pacchetti si possano perdere nella rete o
-restare intrappolati, per poi riemergere in un secondo tempo.
+degli scenari in cui può accadere che i pacchetti TCP si possano perdere nella
+rete o restare intrappolati, per poi riemergere in un secondo tempo.
 
 Il caso più comune in cui questo avviene è quello di anomalie
 nell'instradamento; può accadere cioè che un router smetta di funzionare o che
@@ -397,13 +393,13 @@ pacchetti verso un'altro e quest'ultimo li rispedisce indietro, o li manda ad
 un terzo router che li rispedisce al primo, si creano cioè dei circoli (i
 cosiddetti \textit{routing loop}) in cui restano intrappolati i pacchetti.
 
-Se uno di questi pacchetti intrappolati è un segmento TCP chi l'ha inviato,
+Se uno di questi pacchetti intrappolati è un segmento TCP, chi l'ha inviato,
 non ricevendo un ACK in risposta, provvederà alla ritrasmissione e se nel
 frattempo sarà stata stabilita una strada alternativa il pacchetto ritrasmesso
 giungerà a destinazione.
 
 Ma se dopo un po' di tempo (che non supera il limite dell'MSL, dato che
-altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare il circolo di
+altrimenti verrebbe ecceduto il TTL) l'anomalia viene a cessare, il circolo di
 instradamento viene spezzato i pacchetti intrappolati potranno essere inviati
 alla destinazione finale, con la conseguenza di avere dei pacchetti duplicati;
 questo è un caso che il TCP deve essere in grado di gestire.
@@ -411,7 +407,8 @@ questo 
 Allora per capire la seconda ragione per l'esistenza dello stato
 \texttt{TIME\_WAIT} si consideri il caso seguente: si supponga di avere una
 connessione fra l'IP \texttt{195.110.112.236} porta 1550 e l'IP
-\texttt{192.84.145.100} porta 22, che questa venga chiusa e che poco dopo si
+\texttt{192.84.145.100} porta 22 (affronteremo il significato delle porte
+nella prossima sezione), che questa venga chiusa e che poco dopo si
 ristabilisca la stessa connessione fra gli stessi IP sulle stesse porte
 (quella che viene detta, essendo gli stessi porte e numeri IP, una nuova
 \textsl{incarnazione} della connessione precedente); in questo caso ci si
@@ -445,8 +442,8 @@ Quando un client contatta un server deve poter identificare con quale dei vari
 possibili server attivi intende parlare. Sia TCP che UDP definiscono un gruppo
 di \textsl{porte conosciute} (le cosiddette \textit{well-known port}) che
 identificano una serie di servizi noti (ad esempio la porta 22 identifica il
-servizio \textit{ssh}) effettuati da appositi server che rispondono alle
-connessioni verso tali porte.
+servizio SSH) effettuati da appositi server che rispondono alle connessioni
+verso tali porte.
 
 D'altra parte un client non ha necessità di usare un numero di porta
 specifico, per cui in genere vengono usate le cosiddette \textsl{porte
@@ -460,7 +457,7 @@ La lista delle porte conosciute 
 dall'\href{http://www.ietf.org/rfc/rfc1700.txt}{RFC~1700} che contiene
 l'elenco delle porte assegnate dalla IANA (la \textit{Internet Assigned Number
   Authority}) ma l'elenco viene costantemente aggiornato e pubblicato su
-internet (una versione corrente si può trovare all'indirizzo
+internet (una versione aggiornata si può trovare all'indirizzo
 \texttt{ftp://ftp.isi.edu/in-notes/iana/assignements/port-numbers}); inoltre
 in un sistema unix-like un analogo elenco viene mantenuto nel file
 \file{/etc/services}, con la corrispondenza fra i vari numeri di porta ed il
@@ -470,7 +467,7 @@ nome simbolico del servizio.  I numeri sono divisi in tre intervalli:
 \item \textsl{le porte conosciute}. I numeri da 0 a 1023. Queste sono
   controllate e assegnate dalla IANA. Se è possibile la stessa porta è
   assegnata allo stesso servizio sia su UDP che su TCP (ad esempio la porta 22
-  è assegnata a ssh su entrambi i protocolli, anche se viene usata solo dal
+  è assegnata a SSH su entrambi i protocolli, anche se viene usata solo dal
   TCP).
   
 \item \textsl{le porte registrate}. I numeri da 1024 a 49151. Queste porte non
@@ -503,15 +500,16 @@ tabelle.
 I sistemi Unix hanno inoltre il concetto di \textsl{porte riservate} (che
 corrispondono alle porte con numero minore di 1024 e coincidono quindi con le
 porte conosciute). La loro caratteristica è che possono essere assegnate a un
-socket solo da un processo con i privilegi di amministratore, per far si che solo
-l'amministratore possa allocare queste porte per far partire i relativi
+socket solo da un processo con i privilegi di amministratore, per far si che
+solo l'amministratore possa allocare queste porte per far partire i relativi
 servizi.
 
-Si tenga conto poi che ci sono alcuni client (in particolare \cmd{rsh} e
-\cmd{rlogin}) che richiedono una connessione su una porta riservata anche
-dal lato client come parte dell'autenticazione. Questo viene fatto tramite la
-funzione \func{rresvport} assegnando al socket una porta libera
-nell'intervallo fra 512 e 1023.
+Si tenga conto poi che ci sono alcuni client, in particolare \cmd{rsh} e
+\cmd{rlogin}, che richiedono una connessione su una porta riservata anche dal
+lato client come parte dell'autenticazione, contando appunto sul fatto che
+solo l'amministratore può usare queste porte. Data l'assoluta inconsistenza in
+termini di sicurezza di un tale metodo, al giorno d'oggi esso è in completo
+disuso.
 
 Data una connessione TCP si suole chiamare \textit{socket pair}\footnote{da
   non confondere con la coppia di socket della omonima funzione
@@ -532,7 +530,7 @@ queste informazioni nei campi \textit{Local Address} e \textit{Foreing
 \label{sec:TCP_port_cliserv}
 
 Per capire meglio l'uso delle porte e come vengono utilizzate quando si ha a
-che fare con un'applicazione client/server (come quelle che scriveremo in
+che fare con un'applicazione client/server (come quelle che descriveremo in
 \secref{sec:TCP_daytime_application} e \secref{sec:TCP_echo_application})
 esamineremo cosa accade con le connessioni nel caso di un server TCP che deve
 gestire connessioni multiple.
@@ -546,10 +544,10 @@ tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
 tcp        0      0 0.0.0.0:25              0.0.0.0:*               LISTEN
 tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN
 \end{verbatim}
-essendo presenti e attivi un server ssh, un server di posta e un DNS per il
+essendo presenti e attivi un server SSH, un server di posta e un DNS per il
 caching locale.
 
-Questo ci mostra ad esempio che il server ssh ha compiuto un'apertura passiva,
+Questo ci mostra ad esempio che il server SSH ha compiuto un'apertura passiva,
 mettendosi in ascolto sulla porta 22 riservata a questo servizio, e che si è
 posto in ascolto per connessioni provenienti da uno qualunque degli indirizzi
 associati alle interfacce locali. La notazione \texttt{0.0.0.0} usata da
@@ -625,13 +623,13 @@ dalla porta remota 21100 vanno al primo figlio e quelli che arrivano alla
 porta 21101 al secondo.
 
 
-\section{Le funzioni dei socket TCP}
+\section{Le funzioni di base per la gestione dei socket}
 \label{sec:TCP_functions}
 
-In questa sezione descriveremo in dettaglio le varie funzioni necessarie per
-l'uso dei socket TCP, con l'eccezione della funzione \func{socket} che è già
-stata esaminata in dettaglio nel capitolo precedente in
-\secref{sec:sock_socket}. 
+In questa sezione descriveremo in maggior dettaglio le varie funzioni che
+vengono usate per la gestione di base dei socket TCP, non torneremo però sulla
+funzione \func{socket}, che è già stata esaminata accuratamente nel capitolo
+precedente in \secref{sec:sock_socket}.
 
 
 \subsection{La funzione \func{bind}}
@@ -669,8 +667,8 @@ Il primo argomento 
 l'indirizzo (locale) del socket e la dimensione della struttura che lo
 contiene, secondo quanto già trattato in \secref{sec:sock_sockaddr}. 
 
-Con il TCP la chiamata \func{bind} permette di specificare l'indirizzo, la
-porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
+Con i socket TCP la chiamata \func{bind} permette di specificare l'indirizzo,
+la porta, entrambi o nessuno dei due. In genere i server utilizzano una porta
 nota che assegnano all'avvio, se questo non viene fatto è il kernel a
 scegliere una porta effimera quando vengono eseguite la funzioni
 \func{connect} o \func{listen}, ma se questo è normale per il client non lo è
@@ -690,7 +688,7 @@ alle connessioni che arrivano verso tale indirizzo.
 
 Normalmente un client non specifica mai l'indirizzo di un socket, ed il kernel
 sceglie l'indirizzo di origine quando viene effettuata la connessione, sulla
-base dell'interfaccia usata per trasmettere i pacchetti, (che dipende dalle
+base dell'interfaccia usata per trasmettere i pacchetti, (che dipende dalle
 regole di instradamento usate per raggiungere il server).  Se un server non
 specifica il suo indirizzo locale il kernel userà come indirizzo di origine
 l'indirizzo di destinazione specificato dal SYN del client.
@@ -755,7 +753,7 @@ connessione con un server TCP, il prototipo della funzione 
   Stabilisce una connessione fra due socket.
   
   \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
-    errore, in caso di errore \var{errno} assumerà i valori:
+    errore, nel qual caso \var{errno} assumerà i valori:
   \begin{errlist}
   \item[\errcode{ECONNREFUSED}] non c'è nessuno in ascolto sull'indirizzo
     remoto.
@@ -1233,9 +1231,9 @@ socket di tipo stream).
 Infatti con i socket è comune che funzioni come \func{read} o \func{write}
 possano restituire in input o scrivere in output un numero di byte minore di
 quello richiesto. Come già accennato in \secref{sec:file_read} questo è un
-comportamento normale per l'I/O su file, ma con i normali file di dati il
-problema si avverte solo quando si incontra la fine del file. In generale non
-è così, e con i socket questo è particolarmente evidente.
+comportamento normale per le funzioni di I/O, ma con i normali file di dati il
+problema si avverte solo in lettura, quando si incontra la fine del file. In
+generale non è così, e con i socket questo è particolarmente evidente.
 
 
 \begin{figure}[htb]
@@ -1286,15 +1284,18 @@ l'errore viene ritornato al programma chiamante, interrompendo il ciclo.
 Nel caso della lettura, se il numero di byte letti è zero, significa che si è
 arrivati alla fine del file (per i socket questo significa in genere che
 l'altro capo è stato chiuso, e quindi non sarà più possibile leggere niente) e
-pertanto si ritorna senza aver concluso la lettura di tutti i byte richiesti.
+pertanto si ritorna senza aver concluso la lettura di tutti i byte
+richiesti. Entrambe le funzioni restituiscono 0 in caso di successo, ed un
+valore negativo in caso di errore, \texttt{FullRead} restituisce il numero di
+byte non letti in caso di end-of-file prematuro.
 
 
 \subsection{Il client \textit{daytime}}
 \label{sec:TCP_daytime_client}
 
 Il primo esempio di applicazione delle funzioni di base illustrate in
-precedenza è relativo alla creazione di un client elementare per il servizio
-\textit{daytime}, un servizio elementare, definito
+\secref{sec:TCP_functions} è relativo alla creazione di un client elementare
+per il servizio \textit{daytime}, un servizio elementare, definito
 nell'\href{http://www.ietf.org/rfc/rfc0867.txt}{RFC~867}, che restituisce
 l'ora locale della macchina a cui si effettua la richiesta, e che è assegnato
 alla porta 13.
@@ -1526,7 +1527,7 @@ ulteriori connessioni.
 
 Si noti come il figlio operi solo sul socket connesso, chiudendo
 immediatamente (\texttt{\small 32}) il socket \var{list\_fd}; mentre il padre
-continua ad operare solo sul socket in ascolto chiudendo (\texttt{\small 47})
+continua ad operare (\texttt{\small 47}) solo sul socket in ascolto chiudendo
 \var{sock\_fd} al ritorno dalla \func{fork}. Per quanto abbiamo detto in
 \secref{sec:TCP_func_close} nessuna delle due chiamate a \func{close} causa
 l'innesco della sequenza di chiusura perché il numero di riferimenti al file
@@ -1680,9 +1681,14 @@ Si usa poi (\texttt{\small 6}) la funzione \func{FullWrite}, vista in
 \secref{sec:sock_io_behav}, per scrivere i dati sul socket, gestendo
 automaticamente l'invio multiplo qualora una singola \func{write} non sia
 sufficiente.  I dati vengono riletti indietro (\texttt{\small 7}) con una
-\func{FullRead} sul buffer di ricezione e viene inserita (\texttt{\small 8})
-la terminazione della stringa e per poter usare (\texttt{\small 9}) la
-funzione \func{fputs} per scriverli su \file{stdout}.
+\func{read}\footnote{si è fatta l'assunzione implicita che i dati siano
+  contenuti tutti in un solo segmento, così che la chiamata a \texttt{read} li
+  restituisca sempre tutti; avendo scelto una dimensione ridotta per il buffer
+  questo sarà sempre vero, vedremo più avanti come superare il problema di
+  rileggere indietro tutti e soli i dati disponibili, senza bloccarsi.} sul
+buffer di ricezione e viene inserita (\texttt{\small 8}) la terminazione della
+stringa e per poter usare (\texttt{\small 9}) la funzione \func{fputs} per
+scriverli su \file{stdout}.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1793,13 +1799,13 @@ errore attraverso il sistema del \textit{syslog} trattato in
 \textit{wrapper} la funzione \code{PrintErr}, il cui codice è riportato in
 \figref{fig:TCP_PrintErr}. 
 
-In essa ci si limita a controllare se è stato impostato (valore attivo per
-default) l'uso come demone, nel qual caso (\texttt{\small 3}) si usa
-\func{syslog} per stampare il messaggio di errore fornito come argomento sui
-log di sistema. Se invece si è in modalità interattiva (attivabile con
-l'opzione \texttt{-i}) si usa semplicemente la funzione \func{perror} per
-stampare sullo standard error.
-
+In essa ci si limita a controllare (\texttt{\small 2}) se è stato impostato
+(valore attivo per default) l'uso come demone, nel qual caso (\texttt{\small
+  3}) si usa \func{syslog} (vedi \secref{sec:sess_daemon}) per stampare il
+messaggio di errore fornito come argomento sui log di sistema. Se invece si è
+in modalità interattiva (attivabile con l'opzione \texttt{-i}) si usa
+(\texttt{\small 5}) semplicemente la funzione \func{perror} per stampare sullo
+standard error.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1815,18 +1821,20 @@ stampare sullo standard error.
 
 La gestione del servizio \textit{echo} viene effettuata interamente nella
 funzione \code{ServEcho}, il cui codice è mostrato in
-\figref{fig:TCP_ServEcho}, la comunicazione viene gestita all'interno del
-ciclo (\texttt{\small 6--8}).  I dati inviati dal client vengono letti dal
-socket con una semplice \func{read} (che ritorna solo in presenza di dati in
-arrivo), la riscrittura viene invece gestita dalla funzione \func{FullWrite}
-(descritta in \figref{fig:sock_FullWrite_code}) che si incarica di tenere
-conto automaticamente della possibilità che non tutti i dati di cui è
-richiesta la scrittura vengano trasmessi con una singola \func{write}.
+\figref{fig:TCP_ServEcho}, e la comunicazione viene gestita all'interno di un
+ciclo (\texttt{\small 6--13}).  I dati inviati dal client vengono letti
+(\texttt{\small 6}) dal socket con una semplice \func{read}, di cui non si
+controlla lo stato di uscita, assumendo che ritorni solo in presenza di dati
+in arrivo. La riscrittura (\texttt{\small 7}) viene invece gestita dalla
+funzione \func{FullWrite} (descritta in \figref{fig:sock_FullWrite_code}) che
+si incarica di tenere conto automaticamente della possibilità che non tutti i
+dati di cui è richiesta la scrittura vengano trasmessi con una singola
+\func{write}.
 
 \begin{figure}[!htb] 
   \footnotesize \centering
   \begin{minipage}[c]{15.6cm}
-    \includecodesample{listati/ServEcho.c}
+    \includecodesample{listati/ServEcho_first.c}
   \end{minipage} 
   \normalsize
   \caption{Codice della prima versione della funzione \code{ServEcho} per la
@@ -1834,15 +1842,12 @@ richiesta la scrittura vengano trasmessi con una singola \func{write}.
   \label{fig:TCP_ServEcho}
 \end{figure}
 
-Nella funzione si è anche inserita la possibilità (\texttt{\small 7--14}) di
-inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d}
-che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui
-la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 11}) o
-direttamente sullo standard output (\texttt{\small 13}).
-
-Quando il client chiude la connessione il ricevimento del FIN fa ritornare la
-\func{read} con un numero di byte letti pari a zero, il che causa l'uscita dal
-ciclo e il ritorno della funzione, che a sua volta causa la terminazione del
+In caso di errore di scrittura (si ricordi che \func{FullWrite} restituisce un
+vamore nullo in caso di successo) si provvede (\texttt{\small 8--10}) a
+stampare il relativo messaggio con \func{PrintErr}.  Quando il client chiude
+la connessione il ricevimento del FIN fa ritornare la \func{read} con un
+numero di byte letti pari a zero, il che causa l'uscita dal ciclo e il ritorno
+(\texttt{\small 12}) della funzione, che a sua volta causa la terminazione del
 processo figlio.
 
 
@@ -1850,7 +1855,7 @@ processo figlio.
 \label{sec:TCP_echo_startup}
 
 Benché il codice dell'esempio precedente sia molto ridotto, esso ci permetterà
-di considerare in dettaglio tutte le problematiche che si possono incontrare
+di considerare in dettaglio le varie problematiche che si possono incontrare
 nello scrivere un'applicazione di rete. Infatti attraverso l'esame delle sue
 modalità di funzionamento normali, all'avvio e alla terminazione, e di quello
 che avviene nelle varie situazioni limite, da una parte potremo approfondire
@@ -1952,8 +1957,8 @@ quando affronteremo il comportamento in caso di conclusioni anomale:
 
 \begin{enumerate}
 \item inviando un carattere di EOF da terminale la \func{fgets} ritorna
-  restituendo un puntatore nullo che causa l'uscita dal ciclo di
-  \code{while}, così la \code{ClientEcho} ritorna.
+  restituendo un puntatore nullo che causa l'uscita dal ciclo di \code{while},
+  così la funzione \code{ClientEcho} ritorna.
 \item al ritorno di \code{ClientEcho} ritorna anche la funzione \code{main}, e
   come parte del processo terminazione tutti i file descriptor vengono chiusi
   (si ricordi quanto detto in \secref{sec:proc_term_conclusion}); questo causa
@@ -2200,6 +2205,14 @@ della chiusura del socket.
 
 
 
+Nella funzione si è anche inserita (\texttt{\small 16--24}) la possibilità di
+inviare dei messaggi di debug (abilitabile con l'uso dell'opzione \texttt{-d}
+che imposta opportunamente \var{debugging}), gestendo entrambi i casi in cui
+la stampa deve essere effettuata tramite \func{syslog} (\texttt{\small 20}) o
+direttamente sullo standard output (\texttt{\small 22}).
+
+
+
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"
index cff81bf885f30e78e7e5e7e12a9be2eb5571cba1..9a18289954704264d9e0f4cb37fc8a9ec0d103f7 100644 (file)
@@ -4,7 +4,7 @@ void ClientEcho(FILE * filein, int socket)
     int nread; 
     while (fgets(sendbuff, MAXLINE, filein) != NULL) {
         FullWrite(socket, sendbuff, strlen(sendbuff)); 
-        nread = FullRead(socket, recvbuff, strlen(sendbuff));        
+        nread = read(socket, recvbuff, strlen(sendbuff));        
         recvbuff[nread] = 0;
         fputs(recvbuff, stdout);
     }
index fcc265b6030a30b293c9aaa4e1ba2f2f83f40310..33185ca8a96d785190c4f3bf98ec8d30ff84ccc8 100644 (file)
@@ -19,5 +19,5 @@ ssize_t FullRead(int fd, void *buf, size_t count)
         nleft -= nread;             /* set left to read */
         buf +=nread;                /* set pointer */
     }
-    return (count - nleft);
+    return (nleft);
 }
index 505a1b88353d03f78149c82b3cb4e1a0cf0fdbd4..25f8649a9f79543c4447cb337a367d38097d600b 100644 (file)
@@ -17,5 +17,5 @@ ssize_t FullWrite(int fd, const void *buf, size_t count)
         nleft -= nwritten;          /* set left to write */
         buf +=nwritten;             /* set pointer */
     }
-    return (count);
+    return (nleft);
 }
index e6577d41d9c7ae6003269aff78b73fc5a0706872..6a9a2db5d50aadc3c5013f82f2ee9f22f8225a50 100644 (file)
@@ -1,6 +1,6 @@
 void PrintErr(char * error) {
-    if (demonize) {
-       syslog(LOG_ERR, error);
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
     } else {
        perror(error);
     }
diff --git a/listati/ServEcho_first.c b/listati/ServEcho_first.c
new file mode 100644 (file)
index 0000000..1cda55c
--- /dev/null
@@ -0,0 +1,13 @@
+void ServEcho(int sockfd) {
+    char buffer[MAXLINE];
+    int nread, nwrite;
+    char debug[MAXLINE+20];
+    /* main loop, reading 0 char means client close connection */
+    while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
+       nwrite = FullWrite(sockfd, buffer, nread);
+       if (nwrite) {
+           PrintErr("write error");
+       }
+    }
+    return;
+}
index 06ef46acc182cb5ee5306d64774af528cc334902..0d35c3ec43bea60c21f1bf3707fd05f192864f5a 100644 (file)
@@ -13,8 +13,8 @@
 
 In questo capitolo inizieremo a spiegare le caratteristiche salienti della
 principale interfaccia per la programmazione di rete, quella dei
-\textit{socket}, che, pur essendo nata in ambiente Unix è usata ormai da tutti
-i sistemi operativi.
+\textit{socket}, che, pur essendo nata in ambiente Unix, è usata ormai da
+tutti i sistemi operativi.
 
 Dopo una breve panoramica sulle caratteristiche di questa interfaccia vedremo
 come creare un socket e come collegarlo allo specifico protocollo di rete che
index dab56a3da75ca4b34ebe867f3a7e426055c5cb7f..6338c524623cc066773eeba0396c34a58a190b91 100644 (file)
@@ -24,7 +24,7 @@
  * Author: Simone Piccardi
  * Jun. 2001
  *
- * $Id: FullRead.c,v 1.3 2003/05/02 09:55:13 piccardi Exp $ 
+ * $Id: FullRead.c,v 1.4 2003/07/27 23:41:04 piccardi Exp $ 
  *
  ****************************************************************/
 #include <unistd.h>
@@ -49,6 +49,6 @@ ssize_t FullRead(int fd, void *buf, size_t count)
        nleft -= nread;             /* set left to read */
        buf +=nread;                /* set pointer */
     }
-    return (count - nleft);
+    return (nleft);
 }
 
index 5c27bed6fd73ef2cf5fae00d3db39449286d03d6..f90e91ad01129c3ff7e2beae49c07e0f024937e3 100644 (file)
@@ -24,7 +24,7 @@
  * Author: Simone Piccardi
  * Jun. 2001
  *
- * $Id: FullWrite.c,v 1.3 2003/05/02 09:55:13 piccardi Exp $ 
+ * $Id: FullWrite.c,v 1.4 2003/07/27 23:41:04 piccardi Exp $ 
  *
  ****************************************************************/
 #include <unistd.h>
@@ -47,6 +47,6 @@ ssize_t FullWrite(int fd, const void *buf, size_t count)
        nleft -= nwritten;          /* set left to write */
        buf +=nwritten;             /* set pointer */
     }
-    return (count);
+    return (nleft);
 }
 
index 84929865fcdf2e789db62e46fda332d615bdfdd9..275d570c1739d423f9a79fdcae0826f200add939 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Usage: echo -h give all info's
  *
- * $Id: TCP_echo.c,v 1.4 2003/07/27 15:20:45 piccardi Exp $
+ * $Id: TCP_echo.c,v 1.5 2003/07/27 23:41:04 piccardi Exp $
  *
  ****************************************************************/
 /* 
@@ -144,7 +144,7 @@ void ClientEcho(FILE * filein, int socket)
        if (nwrite < 0) {
            printf("Errore in scrittura %s", strerror(errno));
        }
-       nread = read(socket, recvbuff, strlen(sendbuff));
+       nread = FullRead(socket, recvbuff, strlen(sendbuff));
        if (nread < 0) {
            printf("Errore in lettura %s", strerror(errno));
        }
index 626d1964384a4237e0ff219b2b7365f3cd18184a..93083b37aa58a0c67effe3df5fc6d05668d792fb 100644 (file)
@@ -1,6 +1,6 @@
-/* TCP_echo1.c
+/* TCP_echo_first.c
  * 
- * Copyright (C) 2001 Simone Piccardi
+ * Copyright (C) 2001-2003 Simone Piccardi
  * 
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
  */
 /****************************************************************
  *
- * Program ElemEchoTCPClient.c
+ * Program TCP_echo_first.c (former ElemEchoTCPClient)
  * Simple TCP client for echo service (port 7)
  *
  * Author: Simone Piccardi
@@ -26,7 +26,7 @@
  *
  * Usage: echo -h give all info's
  *
- * $Id: TCP_echo_first.c,v 1.1 2003/06/19 12:08:11 piccardi Exp $
+ * $Id: TCP_echo_first.c,v 1.2 2003/07/27 23:41:04 piccardi Exp $
  *
  ****************************************************************/
 /* 
@@ -121,7 +121,7 @@ void ClientEcho(FILE * filein, int socket)
     int nread; 
     while (fgets(sendbuff, MAXLINE, filein) != NULL) {
        FullWrite(socket, sendbuff, strlen(sendbuff)); 
-       nread = FullRead(socket, recvbuff, strlen(sendbuff));
+       nread = read(socket, recvbuff, strlen(sendbuff));
        recvbuff[nread] = 0;
        fputs(recvbuff, stdout);
     }
index 049155744c919942c335a3a5f3b818ce0005990f..83d0c738f294743dd66478dfcb9b17d0e0bc7548 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Usage: echod -h give all info
  *
- * $Id: TCP_echod.c,v 1.8 2003/07/27 14:28:19 piccardi Exp $ 
+ * $Id: TCP_echod.c,v 1.9 2003/07/27 23:41:04 piccardi Exp $ 
  *
  ****************************************************************/
 /* 
@@ -41,7 +41,7 @@
 #include <syslog.h>      /* syslog system functions */
 #include <signal.h>      /* signal functions */
 #include <errno.h>       /* error code */
-#include <string.h>      /* error code */
+#include <string.h>      /* error strings */
 #include "Gapil.h"
 
 #define BACKLOG 10
@@ -209,7 +209,7 @@ void ServEcho(int sockfd) {
            }
        }
        nwrite = FullWrite(sockfd, buffer, nread);
-       if (nwrite < 0) {
+       if (nwrite) {
            snprintf(debug, MAXLINE+20, "Errore in scrittura: %s \n", 
                     strerror(errno));
            if (demonize) {          /* daemon mode */
@@ -234,8 +234,8 @@ void ServEcho(int sockfd) {
  * routine to print error on stout or syslog
  */
 void PrintErr(char * error) {
-    if (demonize) {          /* daemon mode */
-       syslog(LOG_ERR, error);
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
     } else {
        perror(error);
     }
index 55fd5c6981842e28f47d614c293d07c45170d7ae..b1356fe3f55213daae0bf5109fa2c1fa22c47370 100644 (file)
@@ -1,4 +1,4 @@
-/* TCP_echod.c
+/* TCP_echod_first.c
  * 
  * Copyright (C) 2001-2003 Simone Piccardi
  * 
@@ -26,7 +26,7 @@
  *
  * Usage: echod -h give all info
  *
- * $Id: TCP_echod_first.c,v 1.1 2003/05/06 14:05:12 piccardi Exp $ 
+ * $Id: TCP_echod_first.c,v 1.2 2003/07/27 23:41:04 piccardi Exp $ 
  *
  ****************************************************************/
 /* 
 #include <time.h>
 #include <syslog.h>      /* syslog system functions */
 #include <signal.h>      /* signal functions */
+#include <errno.h>       /* error code */
+#include <string.h>      /* error strings */
 #include "Gapil.h"
 
 #define BACKLOG 10
 #define MAXLINE 256
-int demonize  = 1;  /* daemon use option */
-int debugging = 0;  /* debug info printing option */
+int demonize  = 1;  /* daemon use option: default is daemon */
+int debugging = 0;  /* debug info printing option: default is no debug */
 /* Subroutines declaration */
 void usage(void);
 void ServEcho(int sockfd);
@@ -179,14 +181,8 @@ void ServEcho(int sockfd) {
     /* main loop, reading 0 char means client close connection */
     while ( (nread = read(sockfd, buffer, MAXLINE)) != 0) {
        nwrite = FullWrite(sockfd, buffer, nread);
-       if (debugging) {
-           buffer[nread] = 0;
-           snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
-           if (demonize) {          /* go daemon */
-               syslog(LOG_DEBUG, debug);
-           } else {
-               printf("%s", debug);
-           }
+       if (nwrite) {
+           PrintErr("write error");
        }
     }
     return;
@@ -195,8 +191,8 @@ void ServEcho(int sockfd) {
  * routine to print error on stout or syslog
  */
 void PrintErr(char * error) {
-    if (demonize) {          /* go daemon */
-       syslog(LOG_ERR, error);
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
     } else {
        perror(error);
     }