X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=sockctrl.tex;h=4b07f89b92e601cd8103f02a2ab5b7a7ec3a6d49;hp=872f7b7f133babcf6be70ee733ddfe65a0d218a2;hb=f209f0494e4dd9065f3bf0cda54612297b3e079c;hpb=8654ce33b450ae7bb34c3907835000a0760c2931 diff --git a/sockctrl.tex b/sockctrl.tex index 872f7b7..4b07f89 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1666,12 +1666,12 @@ finora, quello in cui si specifica nel client un indirizzo remoto per la connessione al server, e quello in cui si specifica nel server un indirizzo locale su cui porsi in ascolto. -La prima funzione è allora \func{sockconn} che restituisce un socket connesso -all'indirizzo ed al servizio specificati come argomenti; la funzione prende -poi altri due argomenti aggiuntivi per indicare il protocollo da usare ed il -tipo di socket. Il corpo della funzione è riportato in -fig.~\ref{fig:sockconn_code}, ed il codice completo è nel file -\file{sockconn.c} nei sorgenti allegati alla guida. +La prima funzione della nostra intefaccia semplificata è \func{sockconn} che +permette di ottenere un socket, connesso all'indirizzo ed al servizio +specificati. Il corpo della funzione è riportato in +fig.~\ref{fig:sockconn_code}, il codice completo è nel file \file{SockUtil.c} +dei sorgenti allegati alla guida, che contiene varie funzioni di utilità per +l'uso dei socket. \begin{figure}[!htb] \footnotesize \centering @@ -1684,35 +1684,66 @@ fig.~\ref{fig:sockconn_code}, ed il codice completo \end{figure} La funzione prende quattro argomenti, i primi due sono le stringhe che -indicano il nome della macchina a cui collegarsi ed il relativo servizio; -seguono il protocollo da usare (in forma numerica) ed il tipo di socket (al -solito specificato con i valori illustrati in sez.~\ref{sec:sock_type}). La -funzione ritorna il filde descriptor associato al socket in caso di successo, -o -1 in caso di errore. Come si vede la funzione prevede anche ad alcune -stampe in maniera diretta (il che la rende non utilizzabile all'interno di un -demone). +indicano il nome della macchina a cui collegarsi ed il relativo servizio su +cui sarà effettuata la risoluzione; seguono il protocollo da usare (da +specificare con il valore numerico di \file{/etc/protocols}) ed il tipo di +socket (al solito specificato con i valori illustrati in +sez.~\ref{sec:sock_type}). La funzione ritorna il valore del file descriptor +associato al socket (un numero positivo) in caso di successo, o -1 in caso di +errore; per risolvere il problema di non poter passare indietro i valori di +ritorno di \func{getaddrinfo} contenenti i relativi codici di +errore\footnote{non si può avere nessuna certezza che detti valori siano + negativi, è questo è invece nessario per evitare ogni possibile ambiguità + nei confronti del valore di ritorno in caso di successo.} si sono stampati i +messaggi d'errore direttamente nella funzione. Una volta definite le variabili necessarie (\texttt{\small 3--5}) la funzione -prima (\texttt{\small 7}) azzera il contenuto della struttura \var{hint} e poi -provvede (\texttt{\small 8--10}) ad inizializzarne i valori necessari per la -chiamata (\texttt{\small 11}) a \func{getaddrinfo}. Di quest'ultima si -controlla (\texttt{\small 12}) il codice di ritorno, in modo da stampare -(\texttt{\small 13--15}) un avviso di errore ed uscire in caso di errore. Se -la risoluzioen del nome ha successo si provvede (\texttt{\small 18--22}) ad -aprire il socket, ed a connettersi ad esso (\texttt{\small 24--28}); in -entrambi casi si gestisce il caso di errore. Infine prima di ritornare -(\texttt{\small 30}) il file descriptor del socket si provvede (\texttt{\small - 29}) a liberare le strutture \struct{addrinfo} allocate da -\func{getaddrinfo}. - -Si noti come la funzione si limiti ad usare i valori contenuti nella prima -struttura \struct{addrinfo} ritornata da \func{getaddrinfo}, non eseguendo -ulteriori tentativi sulle successive in caso di errore. Un'altra -caratteristica della funzione è che è del tutto irrilevante se la struttura -ritornata usa indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei dati -relativi alle strutture degli indirizzi di \struct{addrinfo} che sono +prima (\texttt{\small 6}) azzera il contenuto della struttura \var{hint} e poi +provvede (\texttt{\small 7--9}) ad inizializzarne i valori necessari per la +chiamata (\texttt{\small 10}) a \func{getaddrinfo}. Di quest'ultima si +controlla (\texttt{\small 12-16}) il codice di ritorno, in modo da stampare un +avviso di errore, azzerare \var{errno} ed uscire in caso di errore. Dato che +ad una macchina possono corrispondere più indirizzi IP, e di tipo diverso (sia +IPv4 che IPv6), mantre il servizio può essere in ascolto soltanto su uno solo +di questi, si provvede a tentare la connessione per ciascun indirizzo +restituito all'interno di un ciclo (\texttt{\small 18-40}) di scansione della +lista restituita da \func{getaddrinfo}, ma prima (\texttt{\small 17}) si salva +il valore del puntatore per poterlo riutilizzare alla fine per disallocare la +lista. + +Il ciclo viene ripetuto (\texttt{\small 18}) fintanto che si hanno indirizzi +validi, ed inizia (\texttt{\small 19}) con l'apertura del socket; se questa +fallisce si controlla (\texttt{\small 20}) se sono disponibili altri +indirizzi, nel qual caso si passa al successivo (\texttt{\small 21}) e si +riprende (\texttt{\small 22}) il ciclo da capo; se non ve ne sono si stampa +l'errore ritornando immediatamente (\texttt{\small 24-27}). Quando la +creazione del socket ha avuto successo si procede (\texttt{\small 29}) +direttamente con la connessione, di nuovo in caso di fallimento viene ripetuto +(\texttt{\small 30--38}) il controllo se vi sono o no altri indirizzi da +provare nella stessa modalità fatta in precedenza, aggiungendovi però in +entrambi i casi (\texttt{\small 32} e (\texttt{\small 36}) la chiusura del +socket precedentemente aperto, che non è più utilizzabile. + +Se la connessione ha avuto successo invece si termina (\texttt{\small 39}) +direttamente il ciclo, e prima di ritornare (\texttt{\small 31}) il valore del +file descriptor del socket si provvede (\texttt{\small 30}) a liberare le +strutture \struct{addrinfo} allocate da \func{getaddrinfo} utilizzando il +valore del relativo puntatore precedentemente (\texttt{\small 17}) salvato. +Si noti come per la funzione sia del tutto irrilevante se la struttura +ritornata contiene indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei +dati relativi alle strutture degli indirizzi di \struct{addrinfo} che sono \textsl{opachi} rispetto all'uso della funzione \func{connect}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/TCP_echo_fifth.c} + \end{minipage} + \normalsize + \caption{Il nuovo codice per la connessione del client \textit{echo}.} + \label{fig:TCP_echo_fifth} +\end{figure} + Per usare questa funzione possiamo allora modificare ulteriormente il nostro programma client per il servizio \textit{echo}; in questo caso rispetto al codice usato finora per collegarsi (vedi fig.~\ref{fig:TCP_echo_client_1}) @@ -1727,11 +1758,11 @@ dell'indirizzo numerico, e pu \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \includecodesample{listati/TCP_echo_fifth.c} + \includecodesample{listati/sockbind.c} \end{minipage} \normalsize - \caption{Il nuovo codice per la connessione del client \textit{echo}.} - \label{fig:TCP_echo_fifth} + \caption{Il codice della funzione \func{sockbind}.} + \label{fig:sockbind_code} \end{figure} La seconda funzione di ausilio è \func{sockbind}, il cui corpo principale è @@ -1740,56 +1771,37 @@ nel file \file{sockbind.c} dei sorgenti allegati alla guida). Come si pu notare la funzione è del tutto analoga alla precedente \func{sockconn}, e prende gli stessi argomenti, però invece di eseguire una connessione con \func{connect} si limita a chiamare \func{bind} per collegare il socket ad una -porta. +porta. -Dato che la funzione è pensata per utilizzata da un server ci si può chiedere -a quale scopo mantenere l'argomento \param{host} quando l'indirizzo di questo -è usualmente noto. Si ricordi però quanto detto in +Dato che la funzione è pensata per essere utilizzata da un server ci si può +chiedere a quale scopo mantenere l'argomento \param{host} quando l'indirizzo +di questo è usualmente noto. Si ricordi però quanto detto in sez.~\ref{sec:TCP_func_bind}, relativamente al significato della scelta di un indirizzo specifico come argomento di \func{bind}, che consente di porre il server in ascolto su uno solo dei possibili diversi indirizzi presenti su di -una macchina. - -Se non si vuole che la funzione esegua \func{bind} su un indirizzo specifico, -ma utilizzi l'indirizzo generico, occorrerà avere cura di passare un valore -\const{NULL} come valore per l'argomento \var{host}, l'uso del valore -\const{AI\_PASSIVE} serve ad ottenere il valore generico nella rispettiva -struttura degli indirizzi. - -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \includecodesample{listati/sockbind.c} - \end{minipage} - \normalsize - \caption{Il codice della funzione \func{sockbind}.} - \label{fig:sockbind_code} -\end{figure} - +una macchina. Se non si vuole che la funzione esegua \func{bind} su un +indirizzo specifico, ma utilizzi l'indirizzo generico, occorrerà avere cura di +passare un valore \const{NULL} come valore per l'argomento \var{host}; l'uso +del valore \const{AI\_PASSIVE} serve ad ottenere il valore generico nella +rispettiva struttura degli indirizzi. Come già detto la funzione è analoga a \func{sockconn} ed inizia azzerando ed inizializzando (\texttt{\small 6-11}) opportunamente la struttura \var{hint} con i valori ricevuti come argomenti, soltanto che in questo caso si è usata (\texttt{\small 8}) una impostazione specifica dei flag di \var{hint} usando \const{AI\_PASSIVE} per indicare che il socket sarà usato per una apertura -passiva. Per il resto la chiamata a \func{getaddrinfo} (\texttt{\small 12-17}) -e quella a \func{socket} (\texttt{\small 19--23}) sono identiche, mentre si è -sostituita (\texttt{\small 25--29}) la chiamata a \func{connect} con una -chiamata a \func{bind}. La conclusione (\texttt{\small 30--31}) della funzione -è identica. Si noti come anche in questo caso si siano inserite le stampe -degli errori sullo standard output, nonostante la funzione possa essere -invocata da un demone. In realtà questo non è un problema in quanto se la -funzione non ha successo il programma deve uscire immediatamente prima di -essere posto in background, e può quindi scrivere gli errori direttamente -sullo standard output. - -Con l'uso di questa funzione si può modificare anche il codice del nostro -server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale -di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma -riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui -porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \func{sockbind} -che si cura anche della eventuale risoluzione di un indirizzo specifico sul -quale si voglia far ascoltare il server. +passiva. Per il resto la chiamata (\texttt{\small 12-18}) a \func{getaddrinfo} +e ed il ciclo principale (\texttt{\small 20--42}) sono identici, solo che si è +sostituita (\texttt{\small 31}) la chiamata a \func{connect} con una chiamata +a \func{bind}. Anche la conclusione (\texttt{\small 43--44}) della funzione è +identica. + +Si noti come anche in questo caso si siano inserite le stampe degli errori +sullo standard error, nonostante la funzione possa essere invocata da un +demone. Nel nostro caso questo non è un problema in quanto se la funzione non +ha successo il programma deve uscire immediatamente prima di essere posto in +background, e può quindi scrivere gli errori direttamente sullo standard +error. \begin{figure}[!htb] \footnotesize \centering @@ -1801,22 +1813,155 @@ quale si voglia far ascoltare il server. \label{fig:TCP_echod_third} \end{figure} +Con l'uso di questa funzione si può modificare anche il codice del nostro +server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale +di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma +riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui +porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \func{sockbind} +che si cura anche della eventuale risoluzione di un indirizzo specifico sul +quale si voglia far ascoltare il server. + \section{Le opzioni dei socket} -\label{sec:TCP_sock_options} +\label{sec:sock_options} + +Benché dal punto di vista del loro uso come canali di trasmissione di dati i +socket siano trattati allo stesso modo dei file, ed acceduti tramite i file +descriptor, la normale interfaccia usata per la gestione dei file non è +sufficiente a poterne controllare tutte le caratteristiche, che variano tra +l'altro a seconda del loro tipo (e della relativa forma di comunicazione +sottostante). In questa sezione vedremo allora quali sono le funzioni dedicate +alla gestione delle caratteristiche specifiche dei vari tipi di socket, le +cosiddette \textit{socket options}. + + +\subsection{Le funzioni \func{setsockopt} e \func{getsockopt}} +\label{sec:sock_setsockopt} + +Le varie caratteristiche dei socket possono essere gestite attraverso l'uso di +due funzioni generiche che permettono rispettivamente di impostarle e di +recuperarne il valore corrente. La prima di queste due funzioni, quella usata +per impostare le \textit{socket options}, è \funcd{setsockopt}, ed il suo +prototipo è: +\begin{functions} + \headdecl{sys/socket.h} + \headdecl{sys/types.h} + + \funcdecl{int setsockopt(int sock, int level, int optname, const void + *optval, socklen\_t optlen)} + + + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, nel qual caso \var{errno} assumerà i valori: + \begin{errlist} + \item[\errcode{EBADF}] il file descriptor \param{sock} non è valido. + \item[\errcode{EFAULT}] l'indirizzo \param{optval} non è valido. + \item[\errcode{EINVAL}] il valore di \param{optlen} non è valido. + \item[\errcode{ENOPROTOOPT}] l'opzione scelta non esiste per il livello + indicato. + \item[\errcode{ENOTSOCK}] il file descriptor \param{sock} non corrisponde ad + un socket. + \end{errlist} +} +\end{functions} + +Il primo argomento della funzione, \param{sock}, indica il socket su cui si +intende operare; il secondo argomento, \param{level} indica invece il livello +a cui si intende impostare l'opzione. Come abbiamo visto in +sez.~\ref{sec:net_protocols} infatti i protocolli di rete sono strutturati su +più livelli; pertanto anche le proprietà e le opzioni disponibili dipendono +dai protocolli usati dal socket sul quale si va ad agire, e saranno anche esse +differenziate a seconda del protocollo cui fanno riferimento. + + + + +Il valore di \param{level} seleziona allora il livello sul quale si va ad +intervenire e permette di usare le opzioni definite su quel livello. Esiste +poi il valore \const{SOL\_SOCKET} che indica un livello generico e cioè le +opzioni disponibili per qualunque tipo di socket. Per impostare le opzioni +relative alle funzionalità disponibili per socket che usano particolari +protocolli può utilizzare il valore numerico che identifica questi ultimi in +\file{/etc/protocols}, ma più comunemente si suano le apposite costanti +\texttt{SOL\_*} riportate in tab.~\ref{tab:sock_option_levels} dove si sono +riassunti i possibili valori per l'argomento \param{level}.\footnote{la + notazione in questo caso è, purtroppo, abbastanza confusa: infatti in Linux + il valore si può impostare sia usando le costanti \texttt{SOL\_*}, che delle + analoghe \texttt{IPPROTO\_*} (citate anche da Stevens in \cite{UNP1}) che di + nuovo sono equivalenti ai numeri di protocollo di \file{/etc/protocols}; con + una eccesione specifica, che è quella del protocollo ICMP, per la quale non + esista una costante, dato poi che il suo valore, 1, è anche quello che viene + assegnato a \const{SOL\_SOCKET}.} + +\begin{table}[!htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|l|} + \hline + \textbf{Livello} & \textbf{Significato} \\ + \hline + \hline + \const{SOL\_SOCKET}& opzioni generiche dei socket.\\ + \const{SOL\_IP} & opzioni specifiche per i socket che usano IPv4.\\ + \const{SOL\_TCP} & opzioni per i socket che usano TCP.\\ + \const{SOL\_IPV6} & opzioni specifiche per i socket che usano IPv6.\\ + \const{SOL\_ICMPV6}& opzioni specifiche per i socket che usano ICMPv6.\\ + \hline + \end{tabular} + \caption{Possibili valori dell'argomento \param{level} delle + funzioni \func{setsockopt} e \func{getsockopt}.} + \label{tab:sock_option_levels} +\end{table} -Finora abbiamo trattato i socket nel loro comportamento più comune, è però -possibile attivare alcune modalità diverse di funzionamento degli stessi -Dato che la maggior parte delle opzioni dei socket sono relative ai socket - TCP, ed hanno poi significato analogo quando usate con altri socket, abbiamo -preferito trattare l'argomento in generale in questa sezione piuttosto che nel -capitolo dedicato alla trattazione generica dei socket. + +\subsection{Le opzioni generiche} +\label{sec:sock_generic_options} + +Anche se ciascun tipo di socket presenta una serie di caratteristiche +particolari, gestite attraverso delle opzioni specifiche, ma esiste un insieme +generico di opzioni che possono applicarsi a qualunque tipo di socket. + \section{Altre funzioni di controllo} -\label{sec:TCP_sock_ctrl} +\label{sec:sock_ctrl_func} + +Benché la maggior parte delle caratteristiche dei socket sia gestita +attraverso le due funzioni \func{setsockopt} e \func{getsockopt}, alcune +funzionalità possono essere impostate attraverso quelle che sono le funzioni +classiche per il controllo delle proprietà dei file, cioè \func{fcntl} e +\func{ioctl}. + + +\subsection{L'uso di \func{fcntl} per i socket} +\label{sec:sock_fcntl} + +Abbiamo già trattato l'uso di \func{fcntl} in sez.~\ref{sec:file_fcntl}, dove +però ne abbiamo descritto le funzionalità nell'ambito della sua applicazione a +file descriptor associati a file normali; tratteremo qui invece il suo uso +specifico quando la si impiega su file descriptor associati a dei socket. + + +\subsection{L'uso di \func{ioctl} per i socket} +\label{sec:sock_ioctl} + +Come per \func{fcntl} abbiamo trattato l'uso di \func{ioctl} in +sez.~\ref{sec:file_ioctl}, dove ne abbiamo descritto le funzionalità +nell'ambito dell'applicazione su file normali; tratteremo qui il suo uso +specifico quando la si impiega su file descriptor associati a dei socket. + + +\subsection{L'uso di \func{sysctl} per le proprietà della rete} +\label{sec:sock_sysctl} +Come ultimo argomento di questa sezione tratteremo l'uso della funzione +\func{sysctl} (che è stata introdotta nelle sue funzionalità generiche in +sez.~\ref{sec:sys_sysctl}) per quanto riguarda le sue capacità di effettuare +impostazioni relative a proprietà generali dei socket (di tutti quelli di un +certo tipo o di tutti quelli che usano un certo protocollo) rispetto alle +funzioni viste finora che consentono di controllare quelle di un singolo +socket.