Altre correzioni alle funzioni, con riscrittura di ip_ntop per usare switch,
[gapil.git] / sockctrl.tex
index 62fd3d7037692a521a027423fa3d9f40f293cf9a..594e608642fe5c383f1e9e121dd54749fc3e0837 100644 (file)
@@ -1538,7 +1538,7 @@ nello stesso ordine in cui vengono inviati dal server DNS. In particolare
 nulla garantisce che vengano forniti prima i dati relativi ai servizi di un
 determinato protocollo o tipo di socket, se ne sono presenti di diversi.  Se
 allora utilizziamo il nostro programma potremo verificare il risultato:
-\begin{verbatim}
+\begin{Verbatim}
 [piccardi@gont sources]$ ./mygetaddr -c  gapil.truelite.it echo
 Canonical name sources2.truelite.it
 IPv4 address:
@@ -1549,7 +1549,7 @@ IPv4 address:
         Indirizzo 62.48.34.25
         Protocollo 17
         Porta 7
-\end{verbatim}
+\end{Verbatim}
 %$
 
 Una volta estratti i risultati dalla \textit{linked list} puntata da
@@ -1650,14 +1650,184 @@ indirizzi indicati dagli argomenti \param{host} e \param{serv} come stringhe
 terminate dal carattere NUL, a meno che queste non debbano essere troncate
 qualora la loro dimensione ecceda quelle specificate dagli argomenti
 \param{hostlen} e \param{servlen}. Sono comunque definite le due costanti
-\const{NI\_MAXHOST} e \const{NI\_MAXSERV}\footnote{le due costanti sono
-  definite in \file{netdb.h} ed hanno rispettivamente il valore 1024 e 12.}
-che possono essere utilizzate come limiti massimi.  In caso di errore viene
-restituito invece un codice che assume gli stessi valori illustrati in
+\const{NI\_MAXHOST} e \const{NI\_MAXSERV}\footnote{in Linux le due costanti
+  sono definite in \file{netdb.h} ed hanno rispettivamente il valore 1024 e
+  12.}  che possono essere utilizzate come limiti massimi.  In caso di errore
+viene restituito invece un codice che assume gli stessi valori illustrati in
 tab.~\ref{tab:addrinfo_error_code}.
 
-A questo punto possiamo fornire degli esempi di utilizzo diretto della nuova
-interfaccia, adottandola per rendere i nostri client 
+A questo punto possiamo fornire degli esempi di utilizzo della nuova
+interfaccia, adottandola per le precedenti implementazioni del client e del
+server per il servizio \textit{echo}; dato che l'uso delle funzioni appena
+illustrate (in particolare di \func{getaddrinfo}) è piuttosto complesso,
+essendo necessaria anche una impostazione diretta dei campi dell'argomento
+\param{hints}, provvederemo una interfaccia semplificata per i due casi visti
+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 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
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/sockconn.c}
+  \end{minipage}
+  \normalsize
+  \caption{Il codice della funzione \func{sockconn}.}
+  \label{fig:sockconn_code}
+\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 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 (un numero positivo)
+associato al socket 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} con i 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 è provvisto a stampare direttamente all'interno della
+funzione i rispettivi errori, si potrà riconoscere questo caso ottenendo -1
+per il valore di ritorno, ma un valore nullo di \var{errno}.
+
+Una volta definite le variabili necessarie (\texttt{\small 3--5}) la funzione
+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), ed 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 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}) ricominciando il ciclo
+(\texttt{\small 22}), se non ve ne sono si stampa l'errore ritornado
+immediatamente (\texttt{\small 24-27}). Se la creazione del socket ha avuto
+successo si procede (\texttt{\small 29}) con la connessione
+
+
+
+
+
+Se la risoluzione del nome ha successo si provvede (\texttt{\small 19--23}) ad
+aprire il socket, ed a connettersi ad esso (\texttt{\small 25--29}); in
+entrambi casi si gestisce il caso di errore, con una stampa ed il ritorno del
+valore -1. Infine 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}.
+
+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
+\textsl{opachi} rispetto all'uso della funzione \func{connect}.
+
+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})
+avremo una semplificazione per cui il corpo principale del nostro client
+diventerà quello illustrato in fig.~\ref{fig:TCP_echo_fifth}, in cui le
+chiamate a \func{socket}, \func{inet\_pton} e \func{connect} sono sostituite
+da una singola chiamata a \func{sockconn}. Inoltre il nuovo client (il cui
+codice completo è nel file \file{TCP\_echo\_fifth.c} dei sorgenti allegati)
+consente di utilizzare come argomento del programma un nome a dominio al posto
+dell'indirizzo numerico, e può utilizzare sia indirizzi IPv4 che IPv6.
+
+\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}
+
+La seconda funzione di ausilio è \func{sockbind}, il cui corpo principale è
+riportato in fig.~\ref{fig:sockbind_code} (al solito il sorgente completo è
+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. 
+
+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
+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}
+
+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. 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 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.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/TCP_echod_third.c}
+  \end{minipage}
+  \normalsize
+  \caption{Nuovo codice per l'apertura passiva del server \textit{echo}.}
+  \label{fig:TCP_echod_third}
+\end{figure}
+
 
 
 \section{Le opzioni dei socket}