Risistemate le trattazioni delle opzioni SO_KEEPALIVE e SO_REUSEADDR, con
authorSimone Piccardi <piccardi@gnulinux.it>
Mon, 25 Apr 2005 20:42:09 +0000 (20:42 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Mon, 25 Apr 2005 20:42:09 +0000 (20:42 +0000)
l'inserimento di nuove opzioni nei server di esempio per usarle. Revisione
degli indici e correzioni di alcuni errori relativi a funzioni non definnite
o scritta con errori di battitura. Inseriti una serie di riferimenti.

18 files changed:
fileadv.tex
listati/TCP_echod_fifth.c [new file with mode: 0644]
listati/TCP_echod_fourth.c [new file with mode: 0644]
listati/sockbindopt.c [new file with mode: 0644]
session.tex
signal.tex
sockctrl.tex
sources/Gapil.h
sources/Makefile
sources/SockUtil.c
sources/TCP_echo.c
sources/TCP_echod.c
sources/TCP_echod_fifth.c [new file with mode: 0644]
sources/TCP_echod_fourth.c [new file with mode: 0644]
sources/UDP_echo.c
sources/wwwd.c
system.tex
tcpsock.tex

index 2f55a322ac0c34087b7b09545541eb81142f32fb..f4acfefe5a878b41947a462bcd6bac97d2a27785 100644 (file)
@@ -736,7 +736,7 @@ esaurimento.
 
 Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
 disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
-compiuta dalla funzione \func{aio\_fsync}, che ha lo stesso effetto della
+compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
 analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
 è:
 \begin{prototype}{aio.h}
@@ -946,7 +946,7 @@ prototipi sono:
   \end{errlist}
   ed inoltre \errval{EISDIR}, \errval{ENOMEM}, \errval{EFAULT} (se non sono
   stato allocati correttamente i buffer specificati nei campi
-  \func{iov\_base}), più tutti gli ulteriori errori che potrebbero avere le
+  \var{iov\_base}), più tutti gli ulteriori errori che potrebbero avere le
   usuali funzioni di lettura e scrittura eseguite su \param{fd}.}
 \end{functions}
 
diff --git a/listati/TCP_echod_fifth.c b/listati/TCP_echod_fifth.c
new file mode 100644 (file)
index 0000000..0977366
--- /dev/null
@@ -0,0 +1,18 @@
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    int keepalive = 0; 
+    int reuse = 0;
+    ... 
+    /* create and bind socket */
+    if ( (list_fd = sockbindopt(argv[optind], "echo", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
+       return 1;
+    }   
+    ...
+    /* normal exit, never reached */
+    exit(0);
+}
diff --git a/listati/TCP_echod_fourth.c b/listati/TCP_echod_fourth.c
new file mode 100644 (file)
index 0000000..5eb9d30
--- /dev/null
@@ -0,0 +1,20 @@
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    int waiting = 0;
+    int keepalive = 0;
+    ...
+    ...        
+
+       if (pid == 0) {      /* child */
+           close(list_fd);          /* close listening socket */   
+           if (keepalive) {         /* enable keepalive ? */
+               setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, 
+                          &keepalive, sizeof(keepalive));
+           }
+           ServEcho(conn_fd);       /* handle echo */
+           ...
+}
diff --git a/listati/sockbindopt.c b/listati/sockbindopt.c
new file mode 100644 (file)
index 0000000..19a77c6
--- /dev/null
@@ -0,0 +1,21 @@
+int sockbindopt(char *host, char *serv, int prot, int type, int reuse) 
+{
+    struct addrinfo hint, *addr, *save;
+    int res;
+    int sock;
+    char buf[INET6_ADDRSTRLEN];
+    ...
+    while (addr != NULL) {                 /* loop on possible addresses */
+       /* get a socket */
+       sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
+       ...
+       /* connect the socket */
+       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
+                      &reuse, sizeof(reuse))) {
+           printf("error on socket options\n");
+           return -1;
+       }
+       ...
+
+    return sock;
+}
index ae8322ece30f1d68dbabfcd79af209315267939a..ec42332bc4b29199672fc340d7c1ecfed0c16142 100644 (file)
@@ -549,7 +549,7 @@ o se la password non corrisponde\footnote{il confronto non viene effettuato
   volta criptato, ed è il risultato che viene confrontato con il valore che
   viene mantenuto nel database degli utenti.} la richiesta viene ripetuta un
 certo numero di volte dopo di che \cmd{login} esce ed \cmd{init} provvede a
-rilanciare un'altra istanza di \func{getty}.
+rilanciare un'altra istanza di \cmd{getty}.
 
 Se invece la password corrisponde \cmd{login} esegue \func{chdir} per settare
 la \textit{home directory} dell'utente, cambia i diritti di accesso al
index df3727cb06101d026517a13a095f5488570eee6b..2972c9f0764e57b50dad0162bb386caf91908a4a 100644 (file)
@@ -1240,7 +1240,7 @@ il processo non viene terminato direttamente dal gestore sia la stessa
 \func{abort} a farlo al ritorno dello stesso. Inoltre, sempre seguendo lo
 standard POSIX, prima della terminazione tutti i file aperti e gli stream
 saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le
-eventuali funzioni registrate con \func{at\_exit} e \func{on\_exit}.
+eventuali funzioni registrate con \func{atexit} e \func{on\_exit}.
 
 
 \subsection{Le funzioni di pausa e attesa}
index 7e8a5b611baff469dd1c6aaf389b0ed783d03603..8ff56e32ecec98faf11790b2dbe742f0cdde9c98 100644 (file)
@@ -2294,26 +2294,28 @@ permetterci di approfondire il significato di alcune di esse, che assumono
 grande importanza nella programmazione dei socket. Per questo motivo
 tratteremo ulteriormente l'uso di alcune di esse in questa sezione.
 
-\index{\texttt{SO\_KEEPALIVE} (costante)|(}
-La prima opzione da approfondire è \const{SO\_KEEPALIVE}, che come accennato
-permette di controllare automaticamente lo stato di una connessione.  Una
-connessione infatti può restare attiva anche se non viene effettuato alcun
-traffico su di essa, ma in certi casi però può essere utile controllarne lo
-stato per accorgersi di eventuali problemi. 
-
-Per questo, se si imposta questa opzione, è cura del kernel inviare degli
-appositi messaggi sulla rete (detti appunto \textit{keep-alive}) per
-verificare se la connessione è attiva.  L'opzione funziona soltanto con socket
-che supportino le connessioni (non ha senso per socket UDP ad esempio), ed
-utilizza per \param{optval} un intero usato come valore logico.
-
-L'opzione si applica principalmente ai socket TCP.  Con le impostazioni di
-default (che sono riprese da BSD) Linux emette un messaggio di
-\textit{keep-alive} verso l'altro capo della connessione se questa è rimasta
-senza traffico per più di due ore. Se è tutto a posto il messaggio viene
-ricevuto e verrà emesso un segmento ACK di risposta, alla cui ricezione
-ripartirà un'altro ciclo di attesa per altre due ore di inattività; tutto ciò
-viene effettuato dal kernel e le applicazioni non riceveranno nessun dato.
+
+\index{\texttt{SO\_KEEPALIVE} (costante)|(} 
+\subsubsection{L'opzione \const{SO\_KEEPALIVE}}
+
+La prima opzione da approfondire è \const{SO\_KEEPALIVE} che permette di
+tenere sotto controllo lo stato di una connessione. Una connessione infatti
+resta attiva anche quando non viene effettuato alcun traffico su di essa, per
+cui un crollo della stessa potrebbe passare inosservato.
+
+Se si imposta questa opzione, è cura del kernel inviare degli appositi
+messaggi sulla rete (detti appunto \textit{keep-alive}) per verificare se la
+connessione è attiva.  L'opzione funziona soltanto con socket che supportino
+le connessioni (non ha senso per socket UDP ad esempio) e si applica
+principalmente ai socket TCP.
+
+Con le impostazioni di default (che sono riprese da BSD) Linux emette un
+messaggio di \textit{keep-alive} verso l'altro capo della connessione se
+questa è rimasta senza traffico per più di due ore. Se è tutto a posto il
+messaggio viene ricevuto e verrà emesso un segmento ACK di risposta, alla cui
+ricezione ripartirà un'altro ciclo di attesa per altre due ore di inattività;
+il tutto avviene all'interno del kernel e le applicazioni non riceveranno
+nessun dato.
 
 In caso di problemi invece si possono avere i due casi già illustrati in
 sez.~\ref{sec:TCP_conn_crash} per il caso di terminazione prococe del server:
@@ -2333,9 +2335,11 @@ secondi ad un massimo di 9 volte\footnote{entrambi questi valori possono
   di kernel ed i valori saranno applicati a \textsl{tutti} i socket.} (per un
 totale di 11 minuti e 15 secondi) dopo di che, se non si è ricevuta nessuna
 risposta, il socket viene chiuso dopo aver impostato un errore di
-\errcode{ETIMEDOUT}. Se invece si riceve in risposta ad uno di questi messaggi
-un pacchetto ICMP di destinazione irraggiungibile, verrà restituito l'errore
-corrispondente.
+\errcode{ETIMEDOUT}. Qualora la connessione si sia ristabilita e si riceva un
+successivo messaggio di risposta il ciclo riparte come se niente fosse
+avvenuto.  Infine se invece si riceve come risposta un pacchetto ICMP di
+destinazione irraggiungibile (vedi sez.~\ref{sec:icmp_protocol_xxx}), verrà
+restituito l'errore corrispondente.
 
 In generale questa opzione serve per individuare una caduta della
 connessione,\footnote{il crash di un processo di nuovo comporta la chiusura di
@@ -2349,28 +2353,74 @@ assoluta che un errore di \errcode{ETIMEDOUT} corrisponda ad una reale
 conclusione della connessione, il problema potrebbe essere dovuto ad un
 problema di routing che perduri per un tempo maggiore di quello impiegato nei
 vari tentativi di ritrasmissione del \textit{keep-alive}.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/TCP_echod_fourth.c}
+  \end{minipage}
+  \normalsize
+  \caption{La sezione della nuova versione del server del servizio
+    \textit{echo} che prevede l'attivazione del \textit{keepalive} sui
+    socket.} 
+  \label{fig:echod_keepalive_code}
+\end{figure}
+
+Come esempio dell'utilizzo di questa opzione introduciamo all'interno del
+nostro server per il servizio \textit{echo} la nuova opzione \texttt{-k} che
+permette di attivare il \textit{keep-alive} sui socket; tralasciando la parte
+relativa alla gestione di detta opzione (che si limita ad assegnare ad 1 la
+variabile \var{keepalive}) tutte le modifiche al server sono riportate in
+fig.~\ref{fig:echod_keepalive_code}. Al solito il codice completo è contenuto
+nel file \texttt{TCP\_echod\_fourth.c} dei sorgenti allegati alla guida.
+
+Come si può notare la variabile \var{keepalive} è preimpostata (\texttt{\small
+  8}) ad un valore nullo; essa viene utilizzata sia come variabile logica per
+la condizione (\texttt{\small 14}) che controlla l'attivazione del
+\textit{keep-alive} che come valore dell'argomento \param{optval} della
+chiamata a \func{setsockopt} (\texttt{\small 16}).  A seconda del suo valore
+tutte le volta che un processo figlio viene eseguito in risposta ad una
+connessione verrà pertanto eseguita o meno la sezione (\texttt{\small 14--17})
+che esegue l'impostazione di \const{SO\_KEEPALIVE} sul socket connesso.
+
 \index{\texttt{SO\_KEEPALIVE} (costante)|)}
 
 
 \index{\texttt{SO\_REUSEADDR} (costante)|(}
-La seconda opzione da approfondire è \const{SO\_REUSEADDR}.  Come Stevens
-sottolinea in \cite{UNP1} si distinguono quattro casi per l'utilizzo di questa
-opzione; il primo è quello in cui un server è terminato ma esistono ancora dei
-processi figli che mantengono attiva almeno una connessione remota che
-utilizza l'indirizzo locale. Quando si riavvia il server questo viene bloccato
-sulla chiamata a \func{bind} dato che la porta è ancora utilizzata in una
-connessione esistente.\footnote{questa è una delle domande più frequenti sui
-  newsgroup dedicati allo sviluppo, in quanto è piuttosto comune in questa
-  situazione quando si sta sviluppando un server che si ferma e si riavvia in
-  continuazione.}  Inoltre se si usa il protocollo TCP questo può avvenire
-anche dopo che l'ultimo processo figlio è terminato, dato che la connessione
-può restare attiva anche dopo la chiusura del socket mantenendosi nello stato
-\texttt{TIME\_WAIT}.
+\subsubsection{L'opzione \const{SO\_REUSEADDR}}
+
+La seconda opzione da approfondire è \const{SO\_REUSEADDR}, che consente di
+eseguire \func{bind} su un socket anche quando la porta specificata è già in
+uso da parte di un altro socket. Si ricordi infatti che, come accennato in
+sez.~\ref{sec:TCP_func_bind}, normalmente la funzione \func{bind} fallisce con
+un errore di \errcode{EADDRINUSE} se la porta scelta è già utilizzata da un
+altro socket, proprio per evitare che possano essere lanciati due server sullo
+stesso indirizzo che verrebbero a contendersi i relativi pacchetti.  
+
+Esistono però dei casi speciali in cui non si vuole che questo accada, ed
+allora si può fare ricorso a questa opzione. La questione è comunque
+abbastanza complessa (il che rende questa una delle opzioni piu difficili da
+capire) in quanto, come sottolinea Stevens in \cite{UNP1}, si distinguono ben
+quattro casi diversi in cui è prevista la possibilità di un suo utilizzo.
+
+Il primo ed il più comune caso in cui si fa ricorso a \const{SO\_REUSEADDR} è
+quello in cui un server è terminato ma esistono ancora dei processi figli che
+mantengono attiva almeno una connessione remota che utilizza l'indirizzo
+locale mantenendo occupata la porta. Quando si riesegue il server allora
+questo riceve un errore sulla chiamata a \func{bind} dato che la porta è
+ancora utilizzata in una connessione esistente.\footnote{questa è una delle
+  domande più frequenti sui newsgroup dedicati allo sviluppo, in quanto è
+  piuttosto comune trovarsi in questa situazione quando si sta sviluppando un
+  server che si ferma e si riavvia in continuazione dopo aver fatto
+  modifiche.}  Inoltre se si usa il protocollo TCP questo può avvenire anche
+dopo tutti i processi figlio sono terminati, dato che una connessione può
+restare attiva anche dopo la chiusura del socket, mantenendosi nello stato
+\texttt{TIME\_WAIT} (vedi sez.~\ref{sec:TCP_time_wait}).
 
 Usando \const{SO\_REUSEADDR} fra la chiamata a \func{socket} e quella a
 \func{bind} si consente a quest'ultima di avere comunque successo anche se la
 connessione è attiva (o nello stato \texttt{TIME\_WAIT}). È bene però
-ricordare (si riveda quanto detto in sez.~\ref{sec:TCP_time_wait}) che la
+ricordare (si ricordi quanto detto in sez.~\ref{sec:TCP_time_wait}) che la
 presenza dello stato \texttt{TIME\_WAIT} ha una ragione, ed infatti se si usa
 questa opzione esiste sempre una probabilità, anche se estremamente
 remota,\footnote{perché ciò avvenga infatti non solo devono coincidere gli
@@ -2379,14 +2429,71 @@ remota,\footnote{perch
 eventuali pacchetti rimasti intrappolati in una precedente connessione possano
 finire fra quelli di una nuova.
 
-Il secondo caso in cui viene usata questa opzione è quando si ha una macchina
-cui sono assegnati diversi numeri IP (o come suol dirsi \textit{multi-homed})
-e si vuole porre in ascolto sulla stessa porta un programma diverso (o una
-istanza diversa dello stesso programma) per indirizzi IP diversi. Si ricordi
-infatti che è sempre possibile indicare a \func{bind} di collegarsi solo su di
-un indirizzo specifico; in tal caso se un altro programma cerca di
-riutilizzare la stessa porta (anche specificando un indirizzo diverso) otterrà
-un errore a meno di non aver preventivamente impostato \const{SO\_REUSEADDR}.
+Come esempio di uso di questa connessione abbiamo predisposto una nuova
+versione della funzione \func{sockbind} (vedi fig.~\ref{fig:sockbind_code})
+che consenta l'impostazione di questa opzione. La nuova funzione è
+\func{sockbindopt}, e le principali differenze rispetto alla precedente sono
+illustrate in fig.~\ref{fig:sockbindopt_code} dove si sono riportate le
+sezioni di codice modificate rispetto ad essa. Il codice completo della
+funzione si trova, insieme alle altre funzioni di servizio dei socket,
+all'interno del file \texttt{SockUtils.c} dei sorgenti allegati alla guida.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/sockbindopt.c}
+  \end{minipage}
+  \normalsize
+  \caption{Le sezioni della funzione \func{sockbindopt} modificate rispetto al
+    codice della precedente \func{sockbind}.} 
+  \label{fig:sockbindopt_code}
+\end{figure}
+
+In realtà tutto quello che si è fatto è stato introdurre (\texttt{\small 1})
+un nuovo argomento intero \param{reuse} nella nuova funzione che conterrà il
+valore logico da usare nella successiva chiamata (\texttt{\small 14}) a
+\func{setsockopt}. Si è poi aggiunta la sezione (\texttt{\small 13-17}) che
+esegue l'impostazione dell'opzione fra la chiamata a \func{socket} e quella a
+\func{bind}. 
+
+
+A questo punto basterà modificare il  server per utilizzare la nuova
+funzione; in fig.~\ref{fig:TCP_echod_fifth} abbiamo riportato le sezioni
+modificate rispetto alla precedente versione di
+fig.~\ref{fig:TCP_echod_third}. Al solito il codice completo è coi sorgenti
+allegati alla guida, nel file \texttt{TCP\_echod\_fifth.c}.
+
+Anche in questo caso si è introdotta (\texttt{\small 8}) una nuova variabile
+\var{reuse} che consente di controllare l'uso dell'opzione e che poi sarà
+usata (\texttt{\small 14}) come ultimo argomento di \func{setsockopt}. Il
+valore di default di questa variabile è nullo, ma usando l'opzione \texttt{-r}
+nell'invocazione del server (al solito la gestione delle opzioni non è
+riportata in fig.~\ref{fig:TCP_echod_fifth}) se ne potrà impostare ad 1 il
+valore, per cui in tal caso la successiva chiamata (\texttt{\small 13-17}) a
+\func{setsockopt} attiverà l'opzione \const{SO\_REUSEADDR}.
+
+
+\begin{figure}[!htb] 
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/TCP_echod_fifth.c}
+  \end{minipage}
+  \normalsize
+  \caption{Il nuovo codice per l'apertura passiva del server \textit{echo} che
+    usa la nuova funzione \func{sockbindopt}.}
+  \label{fig:TCP_echod_fifth}
+\end{figure}
+
+Il secondo caso in cui viene usata \const{SO\_REUSEADDR} è quando si ha una
+macchina cui sono assegnati diversi numeri IP (o come suol dirsi
+\textit{multi-homed}) e si vuole porre in ascolto sulla stessa porta un
+programma diverso (o una istanza diversa dello stesso programma) per indirizzi
+IP diversi. Si ricordi infatti che è sempre possibile indicare a \func{bind}
+di collegarsi solo su di un indirizzo specifico; in tal caso se un altro
+programma cerca di riutilizzare la stessa porta (anche specificando un
+indirizzo diverso) otterrà un errore, a meno di non aver preventivamente
+impostato \const{SO\_REUSEADDR}.
+
 Usando questa opzione diventa anche possibile eseguire \func{bind}
 sull'indirizzo generico, e questo permetterà il collegamento per tutti gli
 indirizzi (di quelli presenti) per i quali la porta non risulti occupata da
@@ -2403,9 +2510,9 @@ il sistema non supporta l'opzione \const{IP\_RECVDSTADDR};\footnote{nel caso
   di Linux questa opzione è stata supportata per in certo periodo nello
   sviluppo del kernel 2.1.x, ma è in seguito stata soppiantata dall'uso di
   \const{IP\_PKTINFO} (vedi sez.~\ref{sec:sock_ipv4_options}).} in tale modo
-si può sapere a quale socket corrisponde un certo indirizzo.  Non ha senso per
-socket TCP dato che su di essi si può sempre invocare \func{getsockname} una
-volta che si è completata la connessione.
+si può sapere a quale socket corrisponde un certo indirizzo.  Non ha senso
+fare questa operazionie per socket TCP dato che su di essi si può sempre
+invocare \func{getsockname} una volta che si è completata la connessione.
 
 Infine il quarto caso è quello in si vuole effettivamente ottenere un
 \textit{completely duplicate binding}, quando cioè si vuole eseguire
@@ -2451,13 +2558,15 @@ questa opzione.\footnote{Questa restrizione permette di evitare il cosiddetto
 \index{\texttt{SO\_REUSEADDR} (costante)|)}
 
 
-\index{\texttt{SO\_LINGER} (costante)|(} La terza opzione da approfondire è
-\const{SO\_LINGER}; essa, come il nome suggerisce, consente di
-\textsl{indugiare} nella chiusura di un socket. Il comportamento standard sia
-di \func{close} che \func{shutdown} è quello di terminare immediatamente dopo
-la chiamata, mentre il procedimento di chiusura della connessione e l'invio
-sulla rete di tutti i dati ancora presenti nei buffer viene gestito in
-sottofondo dal kernel.
+\index{\texttt{SO\_LINGER} (costante)|(} 
+\subsubsection{L'opzione \const{SO\_LINGER}}
+
+La terza opzione da approfondire è \const{SO\_LINGER}; essa, come il nome
+suggerisce, consente di ``\textsl{indugiare}'' nella chiusura di un socket. Il
+comportamento standard sia di \func{close} che \func{shutdown} è quello di
+terminare immediatamente dopo la chiamata, mentre il procedimento di chiusura
+della connessione e l'invio sulla rete di tutti i dati ancora presenti nei
+buffer viene gestito in sottofondo dal kernel.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -2487,6 +2596,8 @@ da zero sia \func{close} che \func{shutdown} si bloccano e non ritornano
 fintanto che non si sia concluso il procedimento di chiusura della
 connessione, o non siano passati il numero di secondi specificati da
 \var{l\_linger}.
+
+
 \index{\texttt{SO\_LINGER} (costante)|)}
 
 
index e82e825fa22ce7b815ac8c99facefa24eade3149..68fbc24f076f85dace16b5048ea32222ace1643b 100644 (file)
@@ -132,7 +132,7 @@ int RemoveShm(char * shm_name);
  */
 int sockconn(char *host, char *serv, int prot, int type);
 int sockbind(char *host, char *serv, int prot, int type);
-int sockbind2(char *host, char *serv, int prot, int type);
+int sockbindopt(char *host, char *serv, int prot, int type, int reuse);
 
 /*
  * General purpose functions. See corresponding .c
index f612cf2f49eb97bed9dc76761e81487d1aeec37e..edd6119b22a0e0af5d130b4b7d042c33ab29fc29 100644 (file)
@@ -70,7 +70,7 @@ forktest: ForkTest.c
 errcode: ErrCode.c 
        $(CC) $(CFLAGJ) $^ -o $@
 
-echo: UDP_echo.c
+uecho: UDP_echo.c
        $(CC) $(CFLAGJ) $(CFLAGS) $^ -o $@
 
 techo: TCP_echo.c
index 28b22defae96326ad406f723a85bea0484316bb2..8b3fef219143d48543cb0e2dd49b79651efb8840 100644 (file)
@@ -205,12 +205,11 @@ int sockbind(char *host, char *serv, int prot, int type)
  * $Id$ 
  *
  ****************************************************************/
-int sockbind2(char *host, char *serv, int prot, int type) 
+int sockbindopt(char *host, char *serv, int prot, int type, int reuse) 
 {
     struct addrinfo hint, *addr, *save;
     int res;
     int sock;
-    int opt=1;
     char buf[INET6_ADDRSTRLEN];
     /* initialize hint structure */
     memset(&hint, 0, sizeof(struct addrinfo)); 
@@ -240,7 +239,8 @@ int sockbind2(char *host, char *serv, int prot, int type)
            }
        }
        /* connect the socket */
-       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
+       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, 
+                      &reuse, sizeof(reuse))) {
            printf("error on socket options\n");
            return -1;
        }
index f60c518233c4d2e399d9fcc7357c74319a5b571b..6b806ac944032fd763cfe948e959b8e1582c8f18 100644 (file)
@@ -39,6 +39,7 @@
 #include <stdio.h>      /* include standard I/O library */
 #include <errno.h>      /* include error codes */
 #include <string.h>     /* include erroro strings definitions */
+#include <stdlib.h>
 
 #include "Gapil.h"
 #include "macros.h"
index cca49332ade78b32be343a7d57dea39f64cc4f67..ff866efa581860497f57a32a194c5eea5798a11c 100644 (file)
@@ -62,6 +62,8 @@ int main(int argc, char *argv[])
  */
     int list_fd, conn_fd;
     int waiting = 0;
+    int keepalive = 0; 
+    int reuse = 0;
     int compat = 0;
     pid_t pid;
     struct sockaddr_in cli_add;
@@ -73,7 +75,7 @@ int main(int argc, char *argv[])
      */
     int i;
     opterr = 0;         /* don't want writing to stderr */
-    while ( (i = getopt(argc, argv, "hdicw:")) != -1) {
+    while ( (i = getopt(argc, argv, "hkrdicw:")) != -1) {
        switch (i) {
        /* 
         * Handling options 
@@ -86,6 +88,12 @@ int main(int argc, char *argv[])
        case 'i':
            demonize = 0;
            break;
+       case 'k':
+           keepalive = 1;
+           break;
+       case 'r':
+           reuse = 1;
+           break;
        case 'c':
            compat = 1;
            break;
@@ -116,7 +124,8 @@ int main(int argc, char *argv[])
        SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
     }
     /* create and bind socket */
-    if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+    if ( (list_fd = sockbindopt(argv[optind], "echo", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
        return 1;
     }   
     /* release privileges and go daemon */
@@ -167,6 +176,10 @@ int main(int argc, char *argv[])
        }
        if (pid == 0) {      /* child */
            close(list_fd);          /* close listening socket */   
+           if (keepalive) {         /* enable keepalive ? */
+               setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, 
+                          &keepalive, sizeof(keepalive));
+           }
            ServEcho(conn_fd);       /* handle echo */
            if (debugging) {
                snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
@@ -193,6 +206,8 @@ void usage(void) {
     printf("  echod [-h] \n");
     printf("  -h          print this help\n");
     printf("  -d          write debug info\n");
+    printf("  -k          enable SO_KEEPALIVE\n");
+    printf("  -r          enable SO_REUSEADDR\n");
     printf("  -i          use interactively\n");
     printf("  -c          disable BSD semantics\n");
     printf("  -w N        wait N sec. before calling accept\n");
diff --git a/sources/TCP_echod_fifth.c b/sources/TCP_echod_fifth.c
new file mode 100644 (file)
index 0000000..ff866ef
--- /dev/null
@@ -0,0 +1,256 @@
+/* TCP_echod.c
+ * 
+ * Copyright (C) 2001-2004 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
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program echod 
+ * Elementary TCP server for echo service (port 7)
+ *
+ * Author: Simone Piccardi
+ * Jun. 2001
+ *
+ * Usage: echod -h give all info
+ *
+ * $Id$ 
+ *
+ ****************************************************************/
+/* 
+ * Include needed headers
+ */
+#include <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>      /* include standard I/O library */
+#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 <stdlib.h>
+
+#include "Gapil.h"
+
+#define BACKLOG 10
+#define MAXLINE 256
+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);
+void PrintErr(char * error);
+/* Program beginning */
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    int waiting = 0;
+    int keepalive = 0; 
+    int reuse = 0;
+    int compat = 0;
+    pid_t pid;
+    struct sockaddr_in cli_add;
+    socklen_t len;
+    char debug[MAXLINE], ipaddr[20];
+    /*
+     * Input section: decode parameters passed in the calling 
+     * Use getopt function
+     */
+    int i;
+    opterr = 0;         /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hkrdicw:")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(0);
+           break;
+       case 'i':
+           demonize = 0;
+           break;
+       case 'k':
+           keepalive = 1;
+           break;
+       case 'r':
+           reuse = 1;
+           break;
+       case 'c':
+           compat = 1;
+           break;
+       case 'd':
+           debugging = 1;
+           break;
+       case 'w':
+           waiting = strtol(optarg, NULL, 10);
+           break;
+       case '?':   /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+       default:    /* should not reached */
+           usage();
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    /* Main code begin here */
+    if (compat) {                             /* install signal handler */
+       Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
+    } else {
+       SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
+    }
+    /* create and bind socket */
+    if ( (list_fd = sockbindopt(argv[optind], "echo", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
+       return 1;
+    }   
+    /* release privileges and go daemon */
+    if (setgid(65534) !=0) { /* first give away group privileges */
+       perror("cannot give away group privileges");
+       exit(1);
+    }
+    if (setuid(65534) !=0) { /* and only after user ... */
+       perror("cannot give away user privileges");
+       exit(1);
+    }
+    if (demonize) {          /* go daemon */
+        openlog(argv[0], 0, LOG_DAEMON); /* open logging */
+       if (daemon(0, 0) != 0) {
+           perror("cannot start as daemon");
+           exit(1);
+       }
+    }
+    /* main body */
+    if (listen(list_fd, BACKLOG) < 0 ) {
+       PrintErr("listen error");
+       exit(1);
+    }
+    if (waiting) sleep(waiting);
+    /* handle echo to client */
+    while (1) {
+       /* accept connection */
+       len = sizeof(cli_add);
+       while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
+               < 0) && (errno == EINTR)); 
+       if (conn_fd < 0) {
+           PrintErr("accept error");
+           exit(1);
+       }
+       if (debugging) {
+           inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
+           snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
+           if (demonize) {
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+       /* fork to handle connection */
+       if ( (pid = fork()) < 0 ){
+           PrintErr("fork error");
+           exit(1);
+       }
+       if (pid == 0) {      /* child */
+           close(list_fd);          /* close listening socket */   
+           if (keepalive) {         /* enable keepalive ? */
+               setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, 
+                          &keepalive, sizeof(keepalive));
+           }
+           ServEcho(conn_fd);       /* handle echo */
+           if (debugging) {
+               snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
+               if (demonize) {
+                   syslog(LOG_DEBUG, debug);
+               } else {
+                   printf("%s", debug);
+               }
+           }
+           exit(0);
+       } else {             /* parent */
+           close(conn_fd);          /* close connected socket */
+       }
+    }
+    /* normal exit, never reached */
+    exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+    printf("Elementary echo server\n");
+    printf("Usage:\n");
+    printf("  echod [-h] \n");
+    printf("  -h          print this help\n");
+    printf("  -d          write debug info\n");
+    printf("  -k          enable SO_KEEPALIVE\n");
+    printf("  -r          enable SO_REUSEADDR\n");
+    printf("  -i          use interactively\n");
+    printf("  -c          disable BSD semantics\n");
+    printf("  -w N        wait N sec. before calling accept\n");
+    exit(1);
+}
+/*
+ * routine to handle echo for connection
+ */
+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) {
+       if (nread < 0) {
+           PrintErr("Errore in lettura");
+           return;
+       }
+       nwrite = FullWrite(sockfd, buffer, nread);
+       if (nwrite) {
+           PrintErr("Errore in scrittura");
+           return;
+       }
+       if (debugging) {
+           buffer[nread] = 0;
+           snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
+           if (demonize) {          /* daemon mode */
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+    }
+    return;
+}
+/*
+ * routine to print error on stout or syslog
+ */
+void PrintErr(char * error) {
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
+    } else {
+       perror(error);
+    }
+    return;
+}
diff --git a/sources/TCP_echod_fourth.c b/sources/TCP_echod_fourth.c
new file mode 100644 (file)
index 0000000..48d564c
--- /dev/null
@@ -0,0 +1,250 @@
+/* TCP_echod.c
+ * 
+ * Copyright (C) 2001-2004 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
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program echod 
+ * Elementary TCP server for echo service (port 7)
+ *
+ * Author: Simone Piccardi
+ * Jun. 2001
+ *
+ * Usage: echod -h give all info
+ *
+ * $Id$ 
+ *
+ ****************************************************************/
+/* 
+ * Include needed headers
+ */
+#include <sys/types.h>   /* predefined types */
+#include <unistd.h>      /* include unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utiliites */
+#include <sys/socket.h>  /* socket library */
+#include <stdio.h>      /* include standard I/O library */
+#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 <stdlib.h>
+
+#include "Gapil.h"
+
+#define BACKLOG 10
+#define MAXLINE 256
+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);
+void PrintErr(char * error);
+/* Program beginning */
+int main(int argc, char *argv[])
+{
+/* 
+ * Variables definition  
+ */
+    int list_fd, conn_fd;
+    int waiting = 0;
+    int keepalive = 0;
+    int compat = 0;
+    pid_t pid;
+    struct sockaddr_in cli_add;
+    socklen_t len;
+    char debug[MAXLINE], ipaddr[20];
+    /*
+     * Input section: decode parameters passed in the calling 
+     * Use getopt function
+     */
+    int i;
+    opterr = 0;         /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hkdicw:")) != -1) {
+       switch (i) {
+       /* 
+        * Handling options 
+        */ 
+       case 'h':  
+           printf("Wrong -h option use\n");
+           usage();
+           return(0);
+           break;
+       case 'i':
+           demonize = 0;
+           break;
+       case 'k':
+           keepalive = 1;
+           break;
+       case 'c':
+           compat = 1;
+           break;
+       case 'd':
+           debugging = 1;
+           break;
+       case 'w':
+           waiting = strtol(optarg, NULL, 10);
+           break;
+       case '?':   /* unrecognized options */
+           printf("Unrecognized options -%c\n",optopt);
+           usage();
+       default:    /* should not reached */
+           usage();
+       }
+    }
+    /* ***********************************************************
+     * 
+     *          Options processing completed
+     *
+     *               Main code beginning
+     * 
+     * ***********************************************************/
+    /* Main code begin here */
+    if (compat) {                             /* install signal handler */
+       Signal(SIGCHLD, HandSigCHLD);         /* non restarting handler */
+    } else {
+       SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
+    }
+    /* create and bind socket */
+    if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) {
+       return 1;
+    }   
+    /* release privileges and go daemon */
+    if (setgid(65534) !=0) { /* first give away group privileges */
+       perror("cannot give away group privileges");
+       exit(1);
+    }
+    if (setuid(65534) !=0) { /* and only after user ... */
+       perror("cannot give away user privileges");
+       exit(1);
+    }
+    if (demonize) {          /* go daemon */
+        openlog(argv[0], 0, LOG_DAEMON); /* open logging */
+       if (daemon(0, 0) != 0) {
+           perror("cannot start as daemon");
+           exit(1);
+       }
+    }
+    /* main body */
+    if (listen(list_fd, BACKLOG) < 0 ) {
+       PrintErr("listen error");
+       exit(1);
+    }
+    if (waiting) sleep(waiting);
+    /* handle echo to client */
+    while (1) {
+       /* accept connection */
+       len = sizeof(cli_add);
+       while (((conn_fd = accept(list_fd, (struct sockaddr *)&cli_add, &len)) 
+               < 0) && (errno == EINTR)); 
+       if (conn_fd < 0) {
+           PrintErr("accept error");
+           exit(1);
+       }
+       if (debugging) {
+           inet_ntop(AF_INET, &cli_add.sin_addr, ipaddr, sizeof(ipaddr));
+           snprintf(debug, MAXLINE, "Accepted connection form %s\n", ipaddr);
+           if (demonize) {
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+       /* fork to handle connection */
+       if ( (pid = fork()) < 0 ){
+           PrintErr("fork error");
+           exit(1);
+       }
+       if (pid == 0) {      /* child */
+           close(list_fd);          /* close listening socket */   
+           if (keepalive) {         /* enable keepalive ? */
+               setsockopt(conn_fd, SOL_SOCKET, SO_KEEPALIVE, 
+                          &keepalive, sizeof(keepalive));
+           }
+           ServEcho(conn_fd);       /* handle echo */
+           if (debugging) {
+               snprintf(debug, MAXLINE, "Closed connection %s\n", ipaddr);
+               if (demonize) {
+                   syslog(LOG_DEBUG, debug);
+               } else {
+                   printf("%s", debug);
+               }
+           }
+           exit(0);
+       } else {             /* parent */
+           close(conn_fd);          /* close connected socket */
+       }
+    }
+    /* normal exit, never reached */
+    exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+    printf("Elementary echo server\n");
+    printf("Usage:\n");
+    printf("  echod [-h] \n");
+    printf("  -h          print this help\n");
+    printf("  -d          write debug info\n");
+    printf("  -k          enable keepalive on connection\n");
+    printf("  -i          use interactively\n");
+    printf("  -c          disable BSD semantics\n");
+    printf("  -w N        wait N sec. before calling accept\n");
+    exit(1);
+}
+/*
+ * routine to handle echo for connection
+ */
+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) {
+       if (nread < 0) {
+           PrintErr("Errore in lettura");
+           return;
+       }
+       nwrite = FullWrite(sockfd, buffer, nread);
+       if (nwrite) {
+           PrintErr("Errore in scrittura");
+           return;
+       }
+       if (debugging) {
+           buffer[nread] = 0;
+           snprintf(debug, MAXLINE+20, "Letti %d byte, %s", nread, buffer);
+           if (demonize) {          /* daemon mode */
+               syslog(LOG_DEBUG, debug);
+           } else {
+               printf("%s", debug);
+           }
+       }
+    }
+    return;
+}
+/*
+ * routine to print error on stout or syslog
+ */
+void PrintErr(char * error) {
+    if (demonize) {                       /* daemon mode */
+       syslog(LOG_ERR, "%s: %m", error); /* log string and error message */
+    } else {
+       perror(error);
+    }
+    return;
+}
index cc9e3ae786a378d0a1b2cbb2c57fb804c2f51b2b..238effb3bdc49ad257410e56dcca0604962b5559 100644 (file)
@@ -39,6 +39,7 @@
 #include <stdio.h>      /* include standard I/O library */
 #include <errno.h>      /* include error codes */
 #include <string.h>     /* include erroro strings definitions */
+#include <stdlib.h>
 
 #include "macros.h"
 
index cb7752680ec47e59237c3e54b8c6fde06895f2fe..16838882a4fd8820eaf1317157f4adc04a6f9761 100644 (file)
@@ -74,6 +74,7 @@ int main(int argc, char *argv[])
     int list_fd, conn_fd;
     int compat = 0;
     int reroot = 0;
+    int reuse = 1;
     char * rootdir;
     pid_t pid;
     struct sockaddr_in cli_add;
@@ -85,7 +86,7 @@ int main(int argc, char *argv[])
      */
     int i;
     opterr = 0;         /* don't want writing to stderr */
-    while ( (i = getopt(argc, argv, "hdicr:")) != -1) {
+    while ( (i = getopt(argc, argv, "hwdicr:")) != -1) {
        switch (i) {
        /* 
         * Handling options 
@@ -104,6 +105,9 @@ int main(int argc, char *argv[])
        case 'd':
            debugging = 1;
            break;
+       case 'w':
+           reuse = 0;
+           break;
        case 'r':
            reroot = 1;
            rootdir = optarg;
@@ -129,7 +133,8 @@ int main(int argc, char *argv[])
        SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
     }
     /* create and bind socket */
-    if ( (list_fd = sockbind2(argv[optind], "www", 6, SOCK_STREAM)) < 0) {
+    if ( (list_fd = sockbindopt(argv[optind], "www", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
        return 1;
     }   
     /* chroot if requested */
index 1d662114da8965c48a47efa052e2cac0a0e1371c..200aa9469d79eccb6bf5924747eb95a84388bec4 100644 (file)
@@ -2065,23 +2065,23 @@ l'ora locale o il tempo universale, a quelle per trasformare il valore di un
 tempo in una stringa contenente data ed ora, i loro prototipi sono:
 \begin{functions}
   \headdecl{time.h}
-  \funcdecl{char *asctime(const struct tm *tm)} 
+  \funcdecl{char *\funcd{asctime}(const struct tm *tm)} 
   Produce una stringa con data e ora partendo da un valore espresso in
   \textit{broken-down time}.
 
-  \funcdecl{char *ctime(const time\_t *timep)} 
+  \funcdecl{char *\funcd{ctime}(const time\_t *timep)} 
   Produce una stringa con data e ora partendo da un valore espresso in
   in formato \type{time\_t}.
   
-  \funcdecl{struct tm *gmtime(const time\_t *timep)} 
+  \funcdecl{struct tm *\funcd{gmtime}(const time\_t *timep)} 
   Converte il \textit{calendar time} dato in formato \type{time\_t} in un
   \textit{broken-down time} espresso in UTC.
 
-  \funcdecl{struct tm *localtime(const time\_t *timep)} 
+  \funcdecl{struct tm *\funcd{localtime}(const time\_t *timep)} 
   Converte il \textit{calendar time} dato in formato \type{time\_t} in un
   \textit{broken-down time} espresso nell'ora locale.
 
-  \funcdecl{time\_t mktime(struct tm *tm)}   
+  \funcdecl{time\_t \funcd{mktime}(struct tm *tm)}   
   Converte il \textit{broken-down time} in formato \type{time\_t}.
   
   \bodydesc{Tutte le funzioni restituiscono un puntatore al risultato in caso
index 03fb502bbaa8817ace2e0bee04347867a6f97de3..78a6ce446664057d26eecd33fc6de8ea8f8fc65f 100644 (file)
@@ -1600,7 +1600,7 @@ Inoltre nel caso sia stato abilitato il \textit{logging} delle connessioni, si
 provvede anche (\texttt{\small 40--43}) a stampare sullo standard output
 l'indirizzo e la porta da cui il client ha effettuato la connessione, usando i
 valori contenuti nelle strutture restituite da \func{accept}, eseguendo le
-opportune conversioni con \func{inet\_ntop} e \func{atohs}.
+opportune conversioni con \func{inet\_ntop} e \func{ntohs}.
 
 Ancora una volta l'esempio è estremamente semplificato, si noti come di nuovo
 non si sia gestita né la terminazione del processo né il suo uso come demone,
@@ -2292,9 +2292,10 @@ attraverso la sequenza vista in sez.~\ref{sec:TCP_conn_term}, per cui la
 \func{accept} ritornerà senza errori, e si avrà semplicemente un end-of-file
 al primo accesso al socket. Nel caso di Linux inoltre, anche qualora si
 modifichi il client per fargli gestire l'invio di un segmento di RST alla
-chiusura dal socket (come suggerito da Stevens in \cite{UNP1}), non si ha
-nessun errore al ritorno di \funcd{accept}, quanto un errore di
-\errcode{ECONNRESET} al primo tentativo di accesso al socket.
+chiusura dal socket (usando l'opzione \const{SO\_LINGER}, vedi
+sez.~\ref{sec:sock_options_main}), non si ha nessun errore al ritorno di
+\func{accept}, quanto un errore di \errcode{ECONNRESET} al primo tentativo di
+accesso al socket.