massimo valore della somma del numero di entrate possibili per ciascuna di
dette code. Stevens riporta che BSD ha sempre applicato un fattore di 1.5 al
valore, e provvede una tabella con i risultati ottenuti con vari kernel,
-compreso linux 2.0, che mostrano le differenze fra diverse implementazioni.
+compreso linux 2.0, che mostrano le differenze fra diverse implementazioni.
Ma in linux il significato di questo valore è cambiato a partire dal kernel
2.2 per prevenire l'attacco chiamato \texttt{syn flood}. Questo si basa
\texttt{/proc/sys/net/ipv4/tcp\_max\_syn\_backlog}. Quando si attiva la
protezione dei syncookies però (con l'opzione da compilare nel kernel e da
attivare usando \texttt{/proc/sys/net/ipv4/tcp\_syncookies}) questo valore
-viene ignorato e non esiste più un valore massimo.
+viene ignorato e non esiste più un valore massimo. In ogni caso in linux il
+valore di \texttt{backlog} viene troncato ad un massimo di \texttt{SOMAXCONN}
+se è superiore a detta constante (che di default vale 128).
La scelta storica per il valore di questo parametro è di 5, e alcuni vecchi
kernel non supportavano neanche valori superiori, ma la situazione corrente è
richiederebbe la ricompilazione del server) ma usare piuttosto una variabile
di ambiente (vedi \secref{sec:xxx_env_var}). Lo Stevens tratta accuratamente
questo argomento, con esempi presi da casi reali su web server, ed in
-particolare evidenzia come non sia più vero che la ragione della coda è quella
-di gestire il caso in cui il server è occupato fra chiamate successive alla
-\texttt{accept} (per cui la coda più occupata sarebbe quella delle connessioni
-compeltate), ma è invece necessaria a gestire la presenza di un gran numero di
-SYN in attesa di completare il three-way handshake.
+particolare evidenzia come non sia più vero che il compito principale della
+coda sia quello di gestire il caso in cui il server è occupato fra chiamate
+successive alla \texttt{accept} (per cui la coda più occupata sarebbe quella
+delle connessioni compeltate), ma piuttosto quello di gestire la presenza di
+un gran numero di SYN in attesa di completare il three-way handshake.
Come accennato nel caso del TCP se un SYN arriva con tutte le code piene, il
pacchetto sarà ignorato. Questo viene fatto perché la condizione delle code
errori rispetto ad altre implementazioni dei socket BSD, infatti la funzione
\texttt{accept} passa gli errori di rete pendenti sul nuovo socket come codici
di errore per \texttt{accept}. Inoltre la funzione non fa ereditare ai nuovi
-socket flag come \texttt{O_NONBLOCK}, che devono essere rispecificati volta
+socket flag come \texttt{O\_NONBLOCK}, che devono essere rispecificati volta
volta, questo è un comportamento diverso rispetto a quanto accade con BSD e
deve essere tenuto in conto per scrivere programmi portabili.
\section{Un server concorrente su TCP}
\label{sec:TCPel_cunc_serv}
+Il server \texttt{daytime} dell'esempio in \secref{sec:net_cli_sample} è un
+tipico esempio di server iterativo, in cui viene servita una richiesta alla
+volta; in generale però, specie se il servizio è più complesso e comporta uno
+scambio di dati più sostanzioso di quello in questione, non è opportuno
+bloccare un server nel servizio di un client per volta; per questo si ricorre
+alle capacità di multitasking del sistema.
+
+Il modo più immediato per creare un server concorrente è allora quello di
+usare la funzione \texttt{fork} per far creare al server per ogni richiesta da
+parte di un client un processo figlio che si incarichi della gestione della
+comunicazione.
+
+Per illustrare questo meccanismo abbiamo allora riscritto il server
+\texttt{daytime} in forma concorrente, inserendo anche una opzione per la
+stampa degli indirizzi delle connessioni ricevute.
+
+In \nfig\ è mostrato un estratto del codice, in cui si sono tralasciate il
+trattamento delle opzioni e le parti rimaste invariate rispetto al precedente
+esempio. Al solito il sorgente completo del server
+\texttt{ElemDaytimeTCPCuncServ.c} è allegato nella directory dei sorgenti.
+
+\begin{figure}[!htb]
+ \footnotesize
+ \begin{lstlisting}{}
+#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>
+
+int main(int argc, char *argv[])
+{
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add, client;
+ char buffer[MAXLINE];
+ socklen_t len;
+ time_t timeval;
+ pid_t pid;
+ int logging=0;
+ ...
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
+ <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd);
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ if (logging) {
+ inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+ printf("Request from host %s, port %d\n", buffer,
+ ntohs(client.sin_port));
+ }
+ close(conn_fd);
+ exit(0);
+ } else { /* parent */
+ close(conn_fd);
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
+ \end{lstlisting}
+ \caption{Esempio di codice di un server concorrente elementare per il
+ servizio daytime.}
+ \label{fig:net_cli_code}
+\end{figure}
+
+Come si può vedere (\texttt{\small 21--25}) alla funzione \texttt{accept}
--- /dev/null
+/****************************************************************
+ *
+ * Program ElemDaytimeTCPCuncServ.c
+ * Elementary TCP cuncurrent server for daytime service (port 13)
+ *
+ * Author: Simone Piccardi
+ * May. 2001
+ *
+ * Usage: daytimed
+ *
+ * $Id: ElemDaytimeTCPCuncServ.c,v 1.1 2001/05/19 20:47:03 piccardi Exp $
+ *
+ ****************************************************************/
+/*
+ * 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>
+
+#define MAXLINE 80
+#define BACKLOG 10
+/* Program begin */
+void usage(void);
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add, client;
+ char buffer[MAXLINE];
+ socklen_t len;
+ time_t timeval;
+ pid_t pid;
+ int logging=0;
+ /*
+ * Input section: decode parameters passed in the calling
+ * Use getopt function
+ */
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "hv")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h':
+ printf("Wrong -h option use\n");
+ usage();
+ return(0);
+ break;
+ case '?': /* unrecognized options */
+ printf("Unrecognized options -%c\n",optopt);
+ usage();
+ return(0);
+ break;
+ case 'v':
+ logging = 1;
+ break;
+ default: /* should not reached */
+ usage();
+ return(0);
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ /* create socket */
+ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ exit(-1);
+ }
+ /* initialize address */
+ memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime port is 13 */
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
+ /* bind socket */
+ if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("bind error");
+ exit(-1);
+ }
+ /* listen on socket */
+ if (listen(list_fd, BACKLOG) < 0 ) {
+ perror("listen error");
+ exit(-1);
+ }
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
+ <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd);
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ if (logging) {
+ inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+ printf("Request from host %s, port %d\n", buffer,
+ ntohs(client.sin_port));
+ }
+ close(conn_fd);
+ exit(0);
+ } else { /* parent */
+ close(conn_fd);
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Simple daytime server\n");
+ printf("Usage:\n");
+ printf(" daytimed [-hv] \n");
+ printf(" -h print this help\n");
+ printf(" -v print request source on stdout\n");
+ exit(1);
+}
+