From 6d9ca1293f0ecac0c4148a3faaf5f52451c22383 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sun, 29 May 2005 20:52:28 +0000 Subject: [PATCH] Un po' di materiale sulle opzioni dei socket Ipv4 --- netlayer.tex | 31 ++++++--- sockctrl.tex | 185 +++++++++++++++++++++++++++++++++------------------ 2 files changed, 140 insertions(+), 76 deletions(-) diff --git a/netlayer.tex b/netlayer.tex index 5212a5a..75815b1 100644 --- a/netlayer.tex +++ b/netlayer.tex @@ -23,9 +23,10 @@ possa essere necessario per capirne meglio il funzionamento dal punto di vista della programmazione. Data la loro prevelenza il capitolo sarà sostanzialmente incentrato sui due -protocolli principali esistenti su questo livello: l'\textit{Internet - Protocol} IP (che più propriamente si dovrebbe chiamare IPv4) ed la sua -nuova versione denominata IPv6. +protocolli principali esistenti su questo livello: il protocollo IP, sigla che +sta per \textit{Internet Protocol}, (ma che più propriamente si dovrebbe +chiamare IPv4) ed la nuova versione di questo stesso protocollo, denominata +IPv6. \section{Il protocollo IP} @@ -42,7 +43,7 @@ pi \subsection{Introduzione} \label{sec:IP_intro} -Il compito di IP è pertanto quello di trasmettere i pacchetti da un computer +Il compito principale di IP è quello di trasmettere i pacchetti da un computer all'altro della rete; le caratteristiche essenziali con cui questo viene realizzato in IPv4 sono due: @@ -69,10 +70,10 @@ centrale (la IANA, \textit{Internet Assigned Number Authority}) che assegna i numeri di rete alle organizzazioni che ne fanno richiesta; è poi compito di quest'ultime assegnare i numeri dei singoli host. -Per venire incontro alle diverse esigenze gli indirizzi di rete sono stati -originariamente organizzati in \textit{classi}, (rappresentate in -tab.~\ref{tab:IP_ipv4class}), per consentire dispiegamenti di reti di -dimensioni diverse. +Per venire incontro alle diverse esigenze gli indirizzi di rete erano stati +originariamente organizzati all'interno delle cosiddette \textit{classi}, +(rappresentate in tab.~\ref{tab:IP_ipv4class}), per consentire dispiegamenti +di reti di dimensioni diverse. \begin{table}[htb] @@ -147,9 +148,10 @@ dimensioni diverse. \label{tab:IP_ipv4class} \end{table} -Le classi usate per il dispiegamento delle reti sono le prime tre; la classe D -è destinata al (non molto usato) \textit{multicast} mentre la classe E è -riservata per usi sperimentali e non viene impiegata. +Le classi usate per il dispiegamento delle reti su quella che comunemente +viene chiamata \textit{Internet} sono le prime tre; la classe D è destinata al +(non molto usato) \textit{multicast} mentre la classe E è riservata per usi +sperimentali e non viene impiegata. Come si può notare però la suddivisione riportata in tab.~\ref{tab:IP_ipv4class} è largamente inefficiente in quanto se ad un @@ -201,6 +203,13 @@ indirizzi di rete da inserire nelle tabelle di instradamento dei router. + +\subsection{Le opzioni di IP} +\label{sec:IP_options} + + + + \section{Il protocollo IPv6} \label{sec:ipv6_protocol} diff --git a/sockctrl.tex b/sockctrl.tex index b0cc66c..87dca61 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2272,15 +2272,15 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: \end{basedescript} -\subsection{Le uso delle principali opzioni dei socket} +\subsection{L'uso delle principali opzioni dei socket} \label{sec:sock_options_main} La descrizione sintetica del significato delle opzioni generiche dei socket, -riportata nell'elenco in sez.~\ref{sec:sock_generic_options}, non è -sufficientemente dettagliata per permetterci di approfondire tutti le -funzionalità che alcune di esse possono controllare, alcune delle quali hanno -un rilevanza notevole nella programmazione dei socket. Per questo motivo -tratteremo nei dettagli le principali opzioni in questa sezione. +riportata nell'elenco in sez.~\ref{sec:sock_generic_options}, è +necessariamente sintentica, alcune di queste però possono essere utilizzate +per controllare delle funzionalità che hanno una notevole rilevanza nella +programmazione dei socket. Per questo motivo faremo in questa sezione un +approfondimento sul significato delle opzioni generiche più importanti. \index{\texttt{SO\_KEEPALIVE} (costante)|(} @@ -2312,13 +2312,14 @@ In caso di problemi invece si possono avere i due casi gi sez.~\ref{sec:TCP_conn_crash} per il caso di terminazione prococe del server: il primo è quello in cui la macchina remota è caduta ed è stata riavviata, per cui dopo il riavvio la connessione non viene più riconosciuta,\footnote{si - ricordi che un normale riavvio non ha questo effetto, in quanto si passa per - la chiusura del processo, che chiude anche il socket inviando un segmento - FIN all'altro capo della connessione.} in questo caso all'invio del -messaggio di \textit{keep-alive} si otterrà come risposta un segmento RST che -indica che l'altro capo non riconosce più l'esistenza della connessione. In -tal caso il socket viene chiuso dopo aver impostato un errore -\errcode{ECONNRESET}. + ricordi che un normale riavvio non ha questo effetto, in quanto in tal caso + si passa per la chiusura del processo, e questo, come illustrato in + sez.~\ref{sec:file_close}, comporta la chiusura del socket col'invio di un + segmento FIN all'altro capo della connessione, che verrà regolarmente + chiusa.} in questo caso all'invio del messaggio di \textit{keep-alive} si +otterrà come risposta un segmento RST che indica che l'altro capo non +riconosce più l'esistenza della connessione. In tal caso il socket viene +chiuso dopo aver impostato un errore \errcode{ECONNRESET}. Se invece non viene ricevuta nessuna risposta (indice che la macchina non è più raggiungibile) l'emissione dei messaggi viene ripetuta ad intervalli di 75 @@ -2334,24 +2335,15 @@ 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{la terminazione di un processo di nuovo comporta la - chiusura di tutti i file che aveva aperti e la relativa emissione degli - opportuni segmenti FIN nel caso dei socket.} anche quando non si sta facendo -traffico su di essa. In genere viene usata sui server per evitare di -mantenere impegnate le risorse dedicate a trattare delle connessioni in realtà -già terminate (quelle che vengono anche chiamate connessioni -\textsl{semi-aperte}) in cui il server è in attesa di dati in ingresso che non -arriveranno mai perché il client sull'altro capo non è più attivo. - -Abilitandola le connessioni effettivamente terminate vengono chiuse e ad -esempio una \func{select} potrà rilevare la conclusione delle stesse e -ricevere il relativo errore. Si tenga però presente che non si ha la certezza -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} (anche se questa non -è una una condizione molto probabile). +In generale questa opzione serve per individuare una caduta della connessione +anche quando non si sta facendo traffico su di essa. Viene usata +principalmente sui server per evitare di mantenere impegnate le risorse che +verrbbero dedicate a trattare delle connessioni che in realtà sono già +terminate (quelle che vengono anche chiamate connessioni +\textsl{semi-aperte}); in tutti quei casi cioè in cui il server si trova in +attesa di dati in ingresso su una connessione che non arriveranno mai perché o +il client sull'altro capo non è più attivo o non è più in grado di comunicare +con il server via rete. \begin{figure}[!htb] \footnotesize \centering @@ -2365,6 +2357,17 @@ vari tentativi di ritrasmissione del \textit{keep-alive} (anche se questa non \label{fig:echod_keepalive_code} \end{figure} +Abilitandola dopo un certo tempo le connessioni effettivamente terminate +verrano comunque chiuse per cui, utilizzando ad esempio una \func{select}, se +be potrà rilevare la conclusione e ricevere il relativo errore. Si tenga +presente però che non può avere la certezza assoluta che un errore di +\errcode{ETIMEDOUT} ottenuto dopo aver abilitato questa opzione corrisponda +necessariamente ad una reale conclusione della connessione, il problema +potrebbe anche 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} (anche se questa non è una una condizione molto +probabile). + 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 @@ -2378,9 +2381,10 @@ Come si pu 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 +tutte le volte 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. +che esegue l'impostazione di \const{SO\_KEEPALIVE} sul socket connesso, +attivando il relativo comportamento. \index{\texttt{SO\_KEEPALIVE} (costante)|)} @@ -2393,32 +2397,34 @@ 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ò +stesso indirizzo e la stessa porta, che verrebbero a contendersi i pacchetti +aventi quella destinazione. + +Esistono però situazioni ed esigenze particolari in cui non si vuole che +questo comportamento di salvaguardia accada, ed allora si può fare ricorso a +questa opzione. La questione è comunque abbastanza complessa in quanto, come +sottolinea Stevens in \cite{UNP1}, si distinguono ben quattro casi diversi in +cui è prevista la possibilità di un utilizzo di questa opzione, il che la +rende una delle più difficili da capire. + +Il primo caso, che è anche il più comune, 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 figli 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 ricordi quanto detto in sez.~\ref{sec:TCP_time_wait}) che la +ricordare (si riveda 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 @@ -2431,10 +2437,11 @@ 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. +illustrate in fig.~\ref{fig:sockbindopt_code}, dove si sono riportate le +sezioni di codice modificate rispetto alla versione precedente. 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 @@ -2447,12 +2454,12 @@ all'interno del file \texttt{SockUtils.c} dei sorgenti allegati alla guida. \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 +In realtà tutto quello che si è fatto è stato introdurre nella nuova funzione +(\texttt{\small 1}) un nuovo argomento intero, \param{reuse}, 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 +\func{setsockopt}. Si è poi aggiunta una sezione (\texttt{\small 13-17}) che esegue l'impostazione dell'opzione fra la chiamata a \func{socket} e quella a -\func{bind}. +\func{bind}. A questo punto basterà modificare il server per utilizzare la nuova @@ -2545,13 +2552,14 @@ opzione sia specificata per tutti i socket per i quali si vuole eseguire il esiste, ma il comportamento di \const{SO\_REUSEADDR} è analogo, sarà cioè possibile effettuare un \textit{completely duplicate binding} ed ottenere il successo di \func{bind} su un socket legato allo stesso indirizzo e porta solo -se il primo programma che ha eseguito \func{bind} su di essi ha impostato +se il programma che ha eseguito per primo \func{bind} su di essi ha impostato questa opzione.\footnote{Questa restrizione permette di evitare il cosiddetto \textit{port stealing}, in cui un programma, usando \const{SO\_REUSEADDR}, può collegarsi ad una porta già in uso e ricevere i pacchetti destinati ad un altro programma; con questa caratteristica ciò è possibile soltanto se il primo programma a consentirlo, avendo usato fin dall'inizio - \const{SO\_REUSEADDR}.} + \const{SO\_REUSEADDR}.} + \index{\texttt{SO\_REUSEADDR} (costante)|)} @@ -2632,7 +2640,7 @@ Infine l'ultima possibilit esegue l'impostazione con questi valori sia \func{close} che \func{shutdown} si bloccano, nel frattempo viene eseguita la normale procedura di conclusione della connessione (quella di sez.~\ref{sec:TCP_conn_term}) ma entrambe le -funzioni ritornano fintanto che non si sia concluso il procedimento di +funzioni non ritornano fintanto che non si sia concluso il procedimento di chiusura della connessione, o non sia passato un numero di secondi\footnote{questa è l'unità di misura indicata da POSIX ed adottata da Linux, altri kernel possono usare unità di misura diverse, oppure usare il @@ -2716,11 +2724,51 @@ opzioni in tab.~\ref{tab:sock_opt_iplevel}. \label{tab:sock_opt_iplevel} \end{table} - Le descrizioni di tab.~\ref{tab:sock_opt_iplevel} sono estremamente succinte, una maggiore quantità di dettagli su queste opzioni è fornito nel seguente elenco: \begin{basedescript}{\desclabelwidth{2.5cm}\desclabelstyle{\nextlinelabel}} + + +\item[\const{IP\_OPTIONS}] l'opzione permette di impostare o leggere le + opzioni del protocollo IP (si veda sez.~\ref{sec:IP_options}). L'opzione + prende come valore dell'argomento \param{optval} un puntatore ad un buffer + dove sono mantenute le opzioni, mentre \param{optlen} indica la dimensione + di quest'ultimo. Quando la si usa con \func{setsockopt} + +\item[\const{IP\_PKTINFO}] + +\item[\const{IP\_RECVTOS}] + +\item[\const{IP\_RECVTTL}] + +\item[\const{IP\_RECVOPTS}] + +\item[\const{IP\_RETOPTS}] + + +\item[\const{IP\_TOS}] + + +\item[\const{IP\_TTL}] + + +\item[\const{IP\_HDRINCL}] + + +\item[\const{IP\_RECVERR}] + +\item[\const{IP\_MTU\_DISCOVER}] + +\item[\const{IP\_MTU}] + +\item[\const{IP\_ROUTER\_ALERT}] + +\item[\const{IP\_MULTICAST\_TTL}] + + + + \item[\const{IP\_MULTICAST\_LOOP}] L'opzione consente di decidere se i dati che si inviano su un socket usato con il multicast vengano ricevuti anche sulla stessa macchina da cui li si stanno inviando. Prende per @@ -2732,6 +2780,13 @@ elenco: disponibili l'uso di questa opzione permette di disabilitare questo tipo di traffico. +\item[\const{IP\_ADD\_MEMBERSHIP}] + +\item[\const{IP\_DROP\_MEMBERSHIP}] + +\item[\const{IP\_MULTICAST\_IF}] + + \end{basedescript} -- 2.30.2