From 19a767ff841eb36a696db253f1c3cc26c1b2f3a2 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 6 Dec 2017 22:41:24 +0000 Subject: [PATCH] Ancora sulle opzioni dei socket --- fileadv.tex | 5 ++ prochand.tex | 2 + sockctrl.tex | 222 +++++++++++++++++++++++++++------------------------ 3 files changed, 125 insertions(+), 104 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index a3e8710..5cdcf42 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -3860,6 +3860,7 @@ per il campo \var{aio\_sigevent} di \struct{aiocb}. % http://webfiveoh.com/content/guides/2012/aug/mon-13th/linux-asynchronous-io-and-libaio.html, % https://code.google.com/p/kernel/wiki/AIOUserGuide, % http://bert-hubert.blogspot.de/2012/05/on-linux-asynchronous-file-io.html +% https://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt \section{Altre modalità di I/O avanzato} @@ -4686,6 +4687,10 @@ caching dei dati. \end{table} % TODO aggiunta MADV_FREE dal kernel 4.5 (vedi http://lwn.net/Articles/590991/) +% TODO aggiunta MADV_WIPEONFORK dal kernel 4.14 that causes the affected memory +% region to appear to be full of zeros in the child process after a fork. It +% differs from the existing MADV_DONTFORK in that the address range will +% remain valid in the child (dalla notizia in https://lwn.net/Articles/733256/). \footnotetext{a partire dal kernel 2.6.32 è stato introdotto un meccanismo che identifica pagine di memoria identiche e le accorpa in una unica pagina diff --git a/prochand.tex b/prochand.tex index 907a823..495851d 100644 --- a/prochand.tex +++ b/prochand.tex @@ -4313,6 +4313,8 @@ elenco, che illustra quelle attualmente disponibili:\footnote{si fa %TODO trattare membarrier, introdotta con il kernel 4.3 % vedi http://lwn.net/Articles/369567/ http://lwn.net/Articles/369640/ % http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5b25b13ab08f616efd566347d809b4ece54570d1 +% vedi anche l'ulteriore opzione "expedited" introdotta con il kernel 4.14 +% (https://lwn.net/Articles/728795/) \section{Problematiche di programmazione multitasking} \label{sec:proc_multi_prog} diff --git a/sockctrl.tex b/sockctrl.tex index c074a44..a0512bf 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2207,6 +2207,8 @@ riportato un elenco di queste opzioni in tab.~\ref{tab:sock_opt_socklevel}. \hline \const{SO\_ACCEPTCONN}&$\bullet$& & &\texttt{int}& Indica se il socket è in ascolto.\\ + \const{SO\_ATTACH\_FILTER}& &$\bullet$& &\texttt{sock\_fprog}& + Aggancia un filtro BPF al socket.\\ \const{SO\_BINDTODEVICE}&$\bullet$&$\bullet$& &\texttt{char *}& Lega il socket ad un dispositivo.\\ \const{SO\_BROADCAST}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& @@ -2217,6 +2219,8 @@ riportato un elenco di queste opzioni in tab.~\ref{tab:sock_opt_socklevel}. Attiva il ``\textit{busy poll}'' sul socket.\\ \const{SO\_DEBUG} &$\bullet$&$\bullet$&$\bullet$&\texttt{int}& Abilita il debugging sul socket.\\ + \const{SO\_DETACH\_FILTER}& &$\bullet$&$\bullet$&\texttt{int}& + Rimuove il filtro BPF agganciato al socket.\\ \const{SO\_DOMAIN} &$\bullet$& & &\texttt{int}& Legge il tipo di socket.\\ \const{SO\_DONTROUTE}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& @@ -2227,6 +2231,8 @@ riportato un elenco di queste opzioni in tab.~\ref{tab:sock_opt_socklevel}. Controlla l'attività della connessione.\\ \const{SO\_LINGER} &$\bullet$&$\bullet$& &\texttt{linger}& Indugia nella chiusura con dati da spedire.\\ + \const{SO\_LOCK\_FILTER}& &$\bullet$&$\bullet$&\texttt{int}& + Blocca il filtro BPF agganciato al socket.\\ \const{SO\_MARK} &$\bullet$&$\bullet$& &\texttt{int}& Imposta un ``\textit{firewall mark}'' sul socket.\\ \const{SO\_OOBINLINE}&$\bullet$&$\bullet$&$\bullet$&\texttt{int}& @@ -2276,7 +2282,10 @@ riportato un elenco di queste opzioni in tab.~\ref{tab:sock_opt_socklevel}. % TODO aggiungere e documentare SO_ATTACH_BPF, introdotta con il kernel 3.19, % vedi http://lwn.net/Articles/625224/ % TODO aggiungere e documentare SO_INCOMING_CPU, introdotta con il kernel 3.19, - +% TODO documentare SO_PEERGROUPS introdotta con il kernel 4.13, citata +% in https://lwn.net/Articles/727385/ +% TODO documentare SO_ZEROCOPY, vedi https://lwn.net/Articles/726917/ (e il +% resto pure) introdotta con il kernel 4.14 La tabella elenca le costanti che identificano le singole opzioni da usare come valore per \param{optname}; le due colonne seguenti indicano per quali @@ -2299,15 +2308,23 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: \item[\constd{SO\_ACCEPTCONN}] questa opzione permette di rilevare se il socket su cui opera è stato posto in modalità di ricezione di eventuali connessioni con una chiamata a \func{listen}. L'opzione può essere usata soltanto con - \func{getsockopt} e utilizza per \param{optval} un intero in cui viene - restituito 1 se il socket è in ascolto e 0 altrimenti. + \func{getsockopt} ed utilizza per \param{optval} un intero in cui viene + restituito 1 se il socket è in ascolto e 0 altrimenti. \item[\constd{SO\_ATTACH\_FILTER}] questa opzione permette di agganciare ad un - socket un filtro di pacchetti che consente di selezionare quali pacchetti, - fra tutti quelli ricevuti, verranno letti. Viene usato principalmente con i - socket di tipo \const{PF\_PACKET} con la libreria \texttt{libpcap} per - implementare programmi di cattura dei pacchetti, torneremo su questo in - sez.~\ref{sec:packet_socket}. + socket un filtro di selezione dei pacchetti con la stessa sintassi del BPF + (\textit{Berkley Packet Filter}) di BSD, che consente di selezionare, fra + tutti quelli ricevuti, verranno letti. Può essere usata solo con + \func{setsockopt} ed utilizza per \param{optval} un puntatore ad una + struttura \struct{sock\_fprog} (definita in + \headfile{linux/filter.h}). Questa opzione viene usata principalmente con i + socket di tipo \const{PF\_PACKET} (torneremo su questo in + sez.~\ref{sec:packet_socket}) dalla libreria \texttt{libpcap} per + implementare programmi di cattura dei pacchetti, e per questo tipo di + applicazione è opportuno usare sempre quest'ultima.\footnote{la trattazione + del BPF va al di là dell'argomento di questa sezione per la documentazione + si consulti il file \texttt{networking/filter.txt} nella documentazione + del kernel.} \item[\constd{SO\_BINDTODEVICE}] questa opzione permette di \textsl{legare} il socket ad una particolare interfaccia, in modo che esso possa ricevere ed @@ -2381,11 +2398,13 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: programma, \cmd{trpt}.} \item[\constd{SO\_DETACH\_FILTER}] consente di distaccare un filtro - precedentemente aggiunto ad un socket. - -% TODO documentare SO_ATTACH_FILTER e SO_DETACH_FILTER -% riferimenti http://www.rcpt.to/lsfcc/lsf.html -% Documentation/networking/filter.txt + precedentemente aggiunto ad un socket con l'opzione + \const{SO\_ATTACH\_FILTER}, in genere non viene usata direttamente in quanto + i filtri BPF vengono automaticamente rimossi alla chiusura del socket, il + suo utilizzo è pertanto limitato ai rari casi in cui si vuole rimuovere un + precedente filtro per inserirne uno diverso. Come \const{SO\_ATTACH\_FILTER} + può essere usato solo \func{setsockopt} e prende per \param{optval} un + intero usato come valore logico. \item[\constd{SO\_DOMAIN}] questa opzione, presente dal kernel 2.6.32, legge il ``\textsl{dominio}'' (la famiglia di indirizzi) del socket. @@ -2425,6 +2444,15 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: fig.~\ref{fig:sock_linger_struct}. Maggiori dettagli sul suo funzionamento sono forniti in sez.~\ref{sec:sock_options_main}. +\item[\constd{SO\_LOCK\_FILTER}] consente di bloccare un filtro + precedentemente aggiunto ad un socket con l'opzione + \const{SO\_ATTACH\_FILTER}, in modo che non possa essere né rimosso né + modificato, questo consente di impostare un filtro su un socket, bloccarlo e + poi cedere i privilegi con la sicurezza che il filtro permarrà fino alla + chiusura del socket. Come \const{SO\_ATTACH\_FILTER} può essere usato solo + \func{setsockopt} e prende per \param{optval} un intero usato come valore + logico. + \item[\constd{SO\_MARK}] questa opzione, presente dal kernel 2.6.25, imposta un valore di marcatura sui pacchetti del socket. Questa è una funzionalità specifica di Linux, ottenibile anche con l'uso del target \texttt{MARK} @@ -2575,31 +2603,11 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: socket. Maggiori dettagli sul suo funzionamento sono forniti in sez.~\ref{sec:sock_options_main}. - \item[\const{SO\_REUSEPORT}] questa opzione, presente a partire dal kernel 3.9, permette di far usare a più socket di tipo \const{AF\_INET} o - \const{AF\_INET6} lo stesso indirizzo locale. L'opzione deve essere attivata - sul socket prima di chiamare \func{bind} e richiede che tutti i processi che - si mettono in ascolto sullo stesso indirizzo abbiano lo stesso \ids{UID} - effettivo, per evitare che un altro utente possa ottenere il relativo - traffico (eseguendo quello che viene definito in \textit{port hijacking}); - l'opzione utilizza per \param{optval} un intero usato come valore logico. - - L'opzione si usa sia per socket TCP che UDP, nel primo caso consente un uso - distribuito si \func{accept} in una applicazione \textit{multithreaded} - passando un diverso \textit{listening socket} ad ogni thread (cosa che - migliora le prestazioni rispetto all'approccio tradizionale di usare un - thread per usare \func{accept} e distribuire le connessioni o avere più - thread che competono per usare \func{accept} sul socket. Nel caso di UDP - l'opzione consente di distribuire meglio i pacchetti su più processi o - thread rispetto all'approccio tradizionale di far competere gli stessi per - l'accesso in ricezione al socket. - - -% TODO documentare SO_REUSEPORT introdotta con il kernel 3.9, vedi -% http://git.kernel.org/linus/c617f398edd4db2b8567a28e899a88f8f574798d -% TODO: in cosa differisce da REUSEADDR? - + \const{AF\_INET6} lo stesso indirizzo locale, e costituisce una estensione + della precedente \const{SO\_REUSEADDR}. Maggiori dettagli sul suo + funzionamento sono forniti in sez.~\ref{sec:sock_options_main}. \item[\constd{SO\_RXQ\_OVFL}] questa opzione, presente dal kernel 2.6.33, permette di abilitare o disabilitare sul socket la ricezione di un messaggio @@ -2662,30 +2670,6 @@ tab.~\ref{tab:sock_opt_socklevel} sul significato delle varie opzioni: \param{optval} un intero in cui verrà restituito il valore numerico che lo identifica (ad esempio \const{SOCK\_STREAM}). -\item[\constd{SO\_DETACH\_FILTER}] consente di distaccare un filtro - precedentemente aggiunto ad un socket. - -% TODO documentare SO_ATTACH_FILTER e SO_DETACH_FILTER -% riferimenti http://www.rcpt.to/lsfcc/lsf.html -% Documentation/networking/filter.txt - -% TODO documentare SO_MARK, introdotta nel 2.6.25, richiede CAP_NET_ADMIN -%A userspace program may wish to set the mark for each packets its send -%without using the netfilter MARK target. Changing the mark can be used -%for mark based routing without netfilter or for packet filtering. - - -% TODO documentare SO_TIMESTAMP e le altre opzioni di timestamping dei -% pacchetti, introdotte nel 2.6.30, vedi nei sorgenti del kernel: -% Documentation/networking/timestamping.txt - - -% TOFO documentare SO_REUSEPORT introdotta con il kernel 3.9, vedi -% http://git.kernel.org/linus/c617f398edd4db2b8567a28e899a88f8f574798d - -% TODO documentare SO_PEERGROUPS introdotta con il kernel 4.13, citata -% in https://lwn.net/Articles/727385/ - \end{basedescript} @@ -2808,9 +2792,9 @@ attivando il relativo comportamento. \constbeg{SO\_REUSEADDR} -\subsubsection{L'opzione \const{SO\_REUSEADDR}} +\subsubsection{Le opzioni \const{SO\_REUSEADDR} e \const{SO\_REUSEADDR}} -La seconda opzione da approfondire è \const{SO\_REUSEADDR}, che consente di +La seconda opzione da approfondire è \constd{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 @@ -2832,13 +2816,13 @@ 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}). + domande più frequenti relative 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 @@ -2863,7 +2847,6 @@ finire fra quelli di una nuova. \label{fig:sockbindopt_code} \end{figure} - Come esempio di uso di questa connessione abbiamo predisposto una nuova versione della funzione \texttt{sockbind} (vedi fig.~\ref{fig:sockbind_code}) che consenta l'impostazione di questa opzione. La nuova funzione è @@ -2920,10 +2903,12 @@ 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 -una precedente chiamata più specifica. Infine si tenga presente che con il -protocollo TCP non è in genere possibile far partire server che eseguano -\func{bind} sullo stesso indirizzo e la stessa porta, cioè ottenere quello che -viene chiamato un \textit{completely duplicate binding}. +una precedente chiamata più specifica. Si tenga presente infatti che con il +protocollo TCP non è in genere possibile far partire più server che eseguano +\func{bind} sullo stesso indirizzo e la stessa porta se su di esso c'è già un +socket in ascolto, cioè ottenere quello che viene chiamato un +\itindex{completely~duplicate~binding} \textit{completely duplicate binding} +(per questo è stata introdotta \const{SO\_REUSEPORT}). Il terzo impiego è simile al precedente e prevede l'uso di \func{bind} all'interno dello stesso programma per associare indirizzi locali diversi a @@ -2940,12 +2925,12 @@ invocare \func{getsockname} una volta che si è completata la connessione. Infine il quarto caso è quello in cui si vuole effettivamente ottenere un \textit{completely duplicate binding}, quando cioè si vuole eseguire \func{bind} su un indirizzo ed una porta che sono già \textsl{legati} ad un -altro socket. Questo ovviamente non ha senso per il normale traffico di rete, -in cui i pacchetti vengono scambiati direttamente fra due applicazioni; ma -quando un sistema supporta il traffico in \textit{multicast}, allora ha senso -che su una macchina i pacchetti provenienti dal traffico in \textit{multicast} -possano essere ricevuti da più applicazioni o da diverse istanze della stessa -applicazione. +altro socket. Come detto normalmente questo non è possibile con TCP, e non ha +senso per il traffico di rete in cui i pacchetti vengono scambiati +direttamente fra due applicazioni; ma quando un sistema supporta il traffico +in \textit{multicast}, allora ha senso che su una macchina i pacchetti +provenienti dal traffico in \textit{multicast} possano essere ricevuti da più +applicazioni o da diverse istanze della stessa applicazione. L'esempio classico di traffico in \textit{multicast} è quello di uno streaming di dati (audio, video, ecc.), l'uso del \textit{multicast} consente in tal @@ -2956,36 +2941,65 @@ possano lanciare un programma che permetta loro di ricevere gli stessi dati. In questo caso utilizzando \const{SO\_REUSEADDR} si consente ad una applicazione eseguire \func{bind} sulla stessa porta ed indirizzo usata da -un'altra, così che anche essa possa ricevere gli stessi pacchetti (chiaramente -la cosa non ha alcun senso per i socket TCP, ed infatti in questo tipo di -applicazione è normale l'uso del protocollo UDP). La regola è che quando si -hanno più applicazioni che hanno eseguito \func{bind} sulla stessa porta, di -tutti pacchetti destinati ad un indirizzo di \textit{broadcast} o di -\textit{multicast} viene inviata una copia a ciascuna applicazione. Non è +un'altra, così che anche essa possa ricevere gli stessi pacchetti; come detto +la cosa non è possibile con i socket TCP, ma lo è per quelli UDP che è il +protocollo normalmente in uso da parte di queste applicazioni. La regola è che +quando si hanno più applicazioni che hanno eseguito \func{bind} sulla stessa +porta, di tutti pacchetti destinati ad un indirizzo di \textit{broadcast} o di +\textit{multicast} viene inviata una copia a ciascuna applicazione. Non è definito invece cosa accade qualora il pacchetto sia destinato ad un indirizzo normale (\textit{unicast}). % TODO documentare SO_REUSEPORT, vedi https://lwn.net/Articles/542260/ -Essendo questo un caso particolare in alcuni sistemi (come BSD) è stata -introdotta una opzione ulteriore, \const{SO\_REUSEPORT} che richiede che detta -opzione sia specificata per tutti i socket per i quali si vuole eseguire il -\textit{completely duplicate binding}. Nel caso di Linux questa opzione non -esisteva fino al kernel 3.9, 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 programma che ha eseguito per primo -\func{bind} su di essi ha impostato questa opzione. - -Questa restrizione permette di evitare parzialmente 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}. Con l'introduzione di \const{SO\_REUSEPORT} una -ulteriore protezione deriva dalla richiesta che tutti i processi che usano -questa opzione per un socket abbiano lo stesso \ids{UID} effettivo. +\constbeg{SO\_REUSEPORT} + +Esistono però dei casi, in particolare per l'uso di programmi +\textit{multithreaded}, in cui può essere necessario un \textit{completely + duplicate binding} + +L'opzione deve essere attivata sul socket prima di chiamare \func{bind} e +richiede che tutti i processi che si mettono in ascolto sullo stesso indirizzo +abbiano lo stesso \ids{UID} effettivo, per evitare che un altro utente possa +ottenere il relativo traffico (eseguendo quello che viene definito in +\textit{port hijacking}); l'opzione utilizza per \param{optval} un intero +usato come valore logico. + + L'opzione si usa sia per socket TCP che UDP, nel primo caso consente un uso + distribuito si \func{accept} in una applicazione \textit{multithreaded} + passando un diverso \textit{listening socket} ad ogni thread (cosa che + migliora le prestazioni rispetto all'approccio tradizionale di usare un + thread per usare \func{accept} e distribuire le connessioni o avere più + thread che competono per usare \func{accept} sul socket. Nel caso di UDP + l'opzione consente di distribuire meglio i pacchetti su più processi o + thread rispetto all'approccio tradizionale di far competere gli stessi per + l'accesso in ricezione al socket. + % TODO documentare SO_REUSEPORT introdotta con il kernel 3.9, vedi + % http://git.kernel.org/linus/c617f398edd4db2b8567a28e899a88f8f574798d TODO: + % in cosa differisce da REUSEADDR? + + + Essendo questo un caso particolare in alcuni sistemi (come BSD) è stata + introdotta una opzione ulteriore, \const{SO\_REUSEPORT} che richiede che + detta opzione sia specificata per tutti i socket per i quali si vuole + eseguire il \textit{completely duplicate binding}. Nel caso di Linux questa + opzione non esisteva fino al kernel 3.9, 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 programma che + ha eseguito per primo \func{bind} su di essi ha impostato questa opzione. + + Questa restrizione permette di evitare parzialmente 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}. Con l'introduzione di \const{SO\_REUSEPORT} una + ulteriore protezione deriva dalla richiesta che tutti i processi che usano + questa opzione per un socket abbiano lo stesso \ids{UID} effettivo. + +\constend{SO\_REUSEPORT} \constend{SO\_REUSEADDR} -- 2.30.2