From: Simone Piccardi Date: Sun, 13 Mar 2016 16:57:07 +0000 (+0000) Subject: Finita revisione capitolo socket base X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=43d2568d8a142054e3c8cf564da0e0cf4f839ec8;p=gapil.git Finita revisione capitolo socket base --- diff --git a/netlayer.tex b/netlayer.tex index 388ee59..c4d943a 100644 --- a/netlayer.tex +++ b/netlayer.tex @@ -919,7 +919,9 @@ tab.~\ref{tab:IP_ipv6_linklocal}, questi indirizzi iniziano sempre con un valore nell'intervallo \texttt{FE80}--\texttt{FEBF} e vengono in genere usati per la configurazione automatica dell'indirizzo al bootstrap e per la ricerca dei vicini (vedi \ref{sec:IP_ipv6_autoconf}); un pacchetto che abbia tale -indirizzo come sorgente o destinazione non deve venire ritrasmesso dai router. +indirizzo come sorgente o destinazione non deve venire ritrasmesso dai router, +sono gli indirizzi che identificano la macchina sulla rete locale, per questo +sono chiamati in questo modo, in quanto sono usati solo su di essa. Un indirizzo \textit{site-local} invece è usato per l'indirizzamento all'interno di un sito che non necessita di un prefisso globale; la struttura @@ -1486,15 +1488,15 @@ il protocollo infatti fornisce la possibilità ad un nodo di scoprire automaticamente il suo indirizzo acquisendo i parametri necessari per potersi connettere a internet. -L'auto-configurazione sfrutta gli indirizzi link-local; qualora sul nodo sia +L'auto-configurazione sfrutta gli indirizzi \textit{link-local}; qualora sul nodo sia presente una scheda di rete che supporta lo standard IEEE802 (ethernet) questo garantisce la presenza di un indirizzo fisico a 48 bit unico; pertanto il nodo può assumere automaticamente senza pericoli di collisione l'indirizzo -link-local \texttt{FE80::xxxx:xxxx:xxxx} dove \texttt{xxxx:xxxx:xxxx} è +\textit{link-local} \texttt{FE80::xxxx:xxxx:xxxx} dove \texttt{xxxx:xxxx:xxxx} è l'indirizzo hardware della scheda di rete. Nel caso in cui non sia presente una scheda che supporta lo standard IEEE802 -allora il nodo assumerà ugualmente un indirizzo link-local della forma +allora il nodo assumerà ugualmente un indirizzo \textit{link-local} della forma precedente, ma il valore di \texttt{xxxx:xxxx:xxxx} sarà generato casualmente; in questo caso la probabilità di collisione è di 1 su 300 milioni. In ogni caso per prevenire questo rischio il nodo invierà un @@ -1506,13 +1508,13 @@ richiedendo assistenza). Una volta ottenuto un indirizzo locale valido diventa possibile per il nodo comunicare con la rete locale; sono pertanto previste due modalità di auto-configurazione, descritte nelle seguenti sezioni. In ogni caso -l'indirizzo link-local resta valido. +l'indirizzo \textit{link-local} resta valido. \subsection{Auto-configurazione stateless} \label{sec:stateless} Questa è la forma più semplice di auto-configurazione, possibile quando -l'indirizzo globale può essere ricavato dall'indirizzo link-local cambiando +l'indirizzo globale può essere ricavato dall'indirizzo \textit{link-local} cambiando semplicemente il prefisso a quello assegnato dal provider per ottenere un indirizzo globale. @@ -1523,13 +1525,13 @@ dall'indirizzo \textit{multicast} \texttt{FF02::1} (vedi sez.~\ref{sec:IP_ipv6_multicast}); a questo punto devono inviare un messaggio ICMP \textit{Router solicitation} a tutti i router locali usando l'indirizzo \textit{multicast} \texttt{FF02::2} usando come sorgente il proprio indirizzo -link-local. +\textit{link-local}. Il router risponderà con un messaggio ICMP \textit{Router Advertisement} che fornisce il prefisso e la validità nel tempo del medesimo, questo tipo di messaggio può essere trasmesso anche a intervalli regolari. Il messaggio contiene anche l'informazione che autorizza un nodo a autocostruire -l'indirizzo, nel qual caso, se il prefisso unito all'indirizzo link-local non +l'indirizzo, nel qual caso, se il prefisso unito all'indirizzo \textit{link-local} non supera i 128 bit, la stazione ottiene automaticamente il suo indirizzo globale. @@ -1548,7 +1550,7 @@ Per questi motivi è previsto anche un protocollo stateful basato su un server che offra una versione IPv6 del DHCP; un apposito gruppo di \textit{multicast} \texttt{FF02::1:0} è stato riservato per questi server; in questo caso il nodo interrogherà il server su questo indirizzo di \textit{multicast} con -l'indirizzo link-local e riceverà un indirizzo unicast globale. +l'indirizzo \textit{link-local} e riceverà un indirizzo unicast globale. \section{Il protocollo ICMP} diff --git a/socket.tex b/socket.tex index a8c697b..e4b3161 100644 --- a/socket.tex +++ b/socket.tex @@ -469,6 +469,16 @@ aggiuntivo \code{uint8\_t sin\_len} (come riportato da R. Stevens in non è richiesto dallo standard POSIX.1g, in Linux pertanto non esiste. Il campo \type{sa\_family\_t} era storicamente un \ctyp{unsigned short}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.80\textwidth} + \includestruct{listati/sockaddr.h} + \end{minipage} + \caption{La struttura generica degli indirizzi dei socket + \structd{sockaddr}.} + \label{fig:sock_sa_gen_struct} +\end{figure} + Dal punto di vista del programmatore l'unico uso di questa struttura è quello di fare da riferimento per il casting, per il kernel le cose sono un po' diverse, in quanto esso usa il puntatore per recuperare il campo @@ -480,12 +490,31 @@ sarebbe più immediato per l'utente (che non dovrebbe più eseguire il casting), Se si usa una struttura \struct{sockaddr} per allocare delle variabili generiche da usare in seguito per degli indirizzi si pone il problema che niente assicura che i dati necessari per le varie famiglie di indirizzi -possano rientrare nella dimensione del campo \var{sa\_data}, anzi, come -vedremo in sez.~\ref{sec:sock_sa_ipv6}, nel caso di indirizzi IPv6 questa -non è proprio sufficiente. Per questo l'interfaccia di programmazione dei -socket prevede la defizione di una speciale struttura -\struct{sockaddr\_storage} per la quale è assicurato che la dimensione sia -sufficiente per qualunque +possano rientrare nella dimensione del campo \var{sa\_data} indicata in +fig.~\ref{fig:sock_sa_gen_struct}, anzi, come vedremo in +sez.~\ref{sec:sock_sa_ipv6}, nel caso di indirizzi IPv6 questa non è proprio +sufficiente. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/sockaddr_storage.h} + \end{minipage} + \caption{La struttura generica degli indirizzi dei socket + \structd{sockaddr\_storage}.} + \label{fig:sock_sa_storage_struct} +\end{figure} + +Per questo l'interfaccia di programmazione dei socket prevede la defizione di +una speciale struttura \struct{sockaddr\_storage} illustrata in +fig.~\ref{fig:sock_sa_storage_struct}, in cui di nuovo si usa il primo campo +(\var{ss\_family}) per indicare il tipo di indirizzo, ed in cui i campi +successivi sono utilizzati per allineare i dati al tipo di architettura +hardware utilizzata, e per allocare uno spazio sufficiente ampio per contenere +qualunque tipo di indirizzo supportato. Allocando questa struttura si ha la +certezza di non eccedere le dimensioni qualunque sia il tipo di indirizzi che +si useranno, pertanto risulta utile tutte le volte che si devono gestire in +maniera generica tipi di indirizzi diversi (ad esempio IPv4 ed IPv6). \subsection{La struttura degli indirizzi IPv4} @@ -510,10 +539,11 @@ fig.~\ref{fig:sock_sa_ipv4_struct}, conforme allo standard POSIX.1g. L'indirizzo di un socket Internet (secondo IPv4) comprende l'indirizzo Internet di un'interfaccia più un \textsl{numero di porta} (affronteremo in dettaglio il significato di questi numeri in sez.~\ref{sec:TCP_port_num}). Il -protocollo IP non prevede numeri di porta, che sono utilizzati solo dai -protocolli di livello superiore come TCP e UDP. Questa struttura però viene -usata anche per i socket RAW che accedono direttamente al livello di IP, nel -qual caso il numero della porta viene impostato al numero di protocollo. +protocollo IP di per sé non prevede numeri di porta, questi sono utilizzati +solo dai protocolli di livello superiore come TCP e UDP, ma devono essere +indicati qui. Inoltre questa struttura viene usata anche per i socket RAW che +accedono direttamente al livello di IP, in questo caso il numero della porta +deve essere impostato al numero di protocollo. Il membro \var{sin\_family} deve essere sempre impostato a \constd{AF\_INET}, altrimenti si avrà un errore di \errcode{EINVAL}; il membro \var{sin\_port} @@ -568,13 +598,26 @@ specifici dell'header dei pacchetti IPv6 (vedi sez.~\ref{sec:IP_ipv6head}) ed il loro uso è sperimentale. Il campo \var{sin6\_addr} contiene l'indirizzo a 128 bit usato da IPv6, -espresso da un vettore di 16 byte. Infine il campo \var{sin6\_scope\_id} è un -campo introdotto in Linux con il kernel 2.4, per gestire alcune operazioni -riguardanti il \textit{multicasting}. Si noti infine che -\struct{sockaddr\_in6} ha una dimensione maggiore della struttura -\struct{sockaddr} generica di fig.~\ref{fig:sock_sa_gen_struct}, quindi -occorre stare attenti a non avere fatto assunzioni riguardo alla possibilità -di contenere i dati nelle dimensioni di quest'ultima. +espresso da un vettore di 16 byte; anche in questo caso esistono alcuni valori +predediniti, ma essendo il campo un vettore di byte non è possibile assegnarli +con il calore di una costante. Esistono però le variabili predefinite +\var{in6addr\_any} (che indica l'indirizzo generico) e \var{in6addr\_loopback} +(che indica l'indirizzo di loopback) il cui valore può essere copiato in +questo campo. A queste due variabili si aggiungono le macro +\macrod{IN6ADDR\_ANY\_INIT} e \macrod{IN6ADDR\_LOOPBACK\_INIT} per effettuare +delle assegnazioni statiche. + +Infine il campo \var{sin6\_scope\_id} è un campo introdotto in Linux con il +kernel 2.4, per gestire alcune operazioni riguardanti il +\textit{multicasting}, è supportato solo per gli indirizzi di tipo +\textit{link-local} (vedi sez.~\ref{sec:IP_ipv6_unicast}) e deve contenere +l'\textit{interface index} (vedi sez.~\ref{sec:sock_ioctl_netdevice}) della +scheda di rete. Si noti infine che \struct{sockaddr\_in6} ha una dimensione +maggiore della struttura \struct{sockaddr} generica di +fig.~\ref{fig:sock_sa_gen_struct}, quindi occorre stare attenti a non avere +fatto assunzioni riguardo alla possibilità di contenere i dati nelle +dimensioni di quest'ultima (per questo se necessario è opportuno usare +\struct{sockaddr\_storage}). \subsection{La struttura degli indirizzi locali} @@ -601,15 +644,25 @@ fig.~\ref{fig:sock_sa_local_struct}. \label{fig:sock_sa_local_struct} \end{figure} -In questo caso il campo \var{sun\_family} deve essere \constd{AF\_UNIX}, mentre -il campo \var{sun\_path} deve specificare un indirizzo. Questo ha due forme; -può essere un file (di tipo socket) nel filesystem o una stringa univoca -(mantenuta in uno spazio di nomi astratto). Nel primo caso l'indirizzo viene -specificato come una stringa (terminata da uno zero) corrispondente al -\textit{pathname} del file; nel secondo invece \var{sun\_path} inizia con uno -zero e vengono usati come nome i restanti byte come stringa, senza -terminazione. - +In questo caso il campo \var{sun\_family} deve essere \constd{AF\_UNIX}, +mentre il campo \var{sun\_path} deve specificare un indirizzo. Questo ha due +forme; può essere ``\textit{named}'' ed in tal caso deve corrispondere ad un +file (di tipo socket) presente nel filesystem o essere ``\textit{abstract}'' +nel qual caso viene identificato da una stringa univoca in uno spazio di nomi +astratto. + +Nel primo caso l'indirizzo viene specificato in \var{sun\_path} come una +stringa (terminata da uno zero) corrispondente al \textit{pathname} del file; +nel secondo caso (che è specifico di Linux e non portabile) \var{sun\_path} +deve iniziare con uno zero ed il nome verrà costituito dai restanti byte che +verranno interpretati come stringa senza terminazione (un byte nullo non ha in +questo caso nessun significato). + +In realtà esiste una terza forma, \textit{unnamed}, che non è possibile +indicare in fase di scrittura, ma che è quella che viene usata quando si legge +l'indirizzo di un socket anonimo creato con \texttt{socketpair}; in tal caso +la struttura restituita è di dimensione \code{sizeof(sa\_family\_t)}, quindi +\var{sun\_path} non esiste e non deve essere referenziato. \subsection{La struttura degli indirizzi AppleTalk} \label{sec:sock_sa_appletalk} @@ -648,14 +701,16 @@ Il campo \var{sat\_family} deve essere sempre \constd{AF\_APPLETALK}, mentre il campo \var{sat\_port} specifica la porta che identifica i vari servizi. Valori inferiori a 129 sono usati per le \textsl{porte riservate}, e possono essere usati solo da processi con i privilegi di amministratore o con -la \textit{capability} \const{CAP\_NET\_BIND\_SERVICE}. L'indirizzo remoto è -specificato nella struttura \var{sat\_addr}, e deve essere in \textit{network - order} (vedi sez.~\ref{sec:endianness}); esso è composto da un parte di rete -data dal campo \var{s\_net}, che può assumere il valore \constd{AT\_ANYNET}, -che indica una rete generica e vale anche per indicare la rete su cui si è, il -singolo nodo è indicato da \var{s\_node}, e può prendere il valore generico -\constd{AT\_ANYNODE} che indica anche il nodo corrente, ed il valore -\constd{ATADDR\_BCAST} che indica tutti i nodi della rete. +la \textit{capability} \const{CAP\_NET\_BIND\_SERVICE}. + +L'indirizzo remoto è specificato nella struttura \var{sat\_addr}, e deve +essere in \textit{network order} (vedi sez.~\ref{sec:endianness}); esso è +composto da un parte di rete data dal campo \var{s\_net}, che può assumere il +valore \constd{AT\_ANYNET}, che indica una rete generica e vale anche per +indicare la rete su cui si è, il singolo nodo è indicato da \var{s\_node}, e +può prendere il valore generico \constd{AT\_ANYNODE} che indica anche il nodo +corrente, ed il valore \constd{ATADDR\_BCAST} che indica tutti i nodi della +rete. \subsection{La struttura degli indirizzi dei \textit{packet socket}} @@ -683,12 +738,14 @@ comunque il pacchetto, riempiendo gli opportuni campi della struttura \struct{sockaddr\_ll} ad esso associata. Si usano invece socket di tipo \const{SOCK\_DGRAM} quando si vuole operare a -livello di rete. In questo caso in fase di ricezione l'intestazione del -protocollo di collegamento viene rimossa prima di passare il resto del -pacchetto all'utente, mentre in fase di trasmissione viene creata una -opportuna intestazione per il protocollo a livello di collegamento -utilizzato, usando le informazioni necessarie che devono essere specificate -sempre con una struttura \struct{sockaddr\_ll}. +livello di rete. + +In questo caso in fase di ricezione l'intestazione del protocollo di +collegamento viene rimossa prima di passare il resto del pacchetto all'utente, +mentre in fase di trasmissione viene creata una opportuna intestazione per il +protocollo a livello di collegamento utilizzato, usando le informazioni +necessarie che devono essere specificate sempre con una struttura +\struct{sockaddr\_ll}. Nella creazione di un \textit{packet socket} il valore dell'argomento \param{protocol} di \func{socket} serve a specificare, in \textit{network @@ -705,7 +762,8 @@ con la \textit{capability} \const{CAP\_NET\_RAW}. Una volta aperto un \textit{packet socket}, tutti i pacchetti del protocollo specificato passeranno attraverso di esso, qualunque sia l'interfaccia da cui provengono; se si vuole limitare il passaggio ad una interfaccia specifica -occorre usare la funzione \func{bind} per agganciare il socket a quest'ultima. +occorre usare la funzione \func{bind} (vedi sez.~\ref{sec:TCP_func_bind}) per +agganciare il socket a quest'ultima. \begin{figure}[!htb] \footnotesize \centering @@ -726,19 +784,20 @@ scrivere tutto direttamente nel pacchetto, quindi la struttura non serve più a specificare gli indirizzi. Essa mantiene questo ruolo solo per i socket di tipo \const{SOCK\_DGRAM}, per i quali permette di specificare i dati necessari al protocollo di collegamento, mentre viene sempre utilizzata in lettura (per -entrambi i tipi di socket), per la ricezione dei i dati relativi a ciascun +entrambi i tipi di socket), per la ricezione dei dati relativi a ciascun pacchetto. Al solito il campo \var{sll\_family} deve essere sempre impostato al valore \constd{AF\_PACKET}. Il campo \var{sll\_protocol} indica il protocollo scelto, e deve essere indicato in \textit{network order}, facendo uso delle costanti simboliche definite in \file{linux/if\_ether.h}. Il campo \var{sll\_ifindex} è -l'indice dell'interfaccia, che, in caso di presenza di più interfacce dello -stesso tipo (se ad esempio si hanno più schede Ethernet), permette di -selezionare quella con cui si vuole operare (un valore nullo indica qualunque -interfaccia). Questi sono i due soli campi che devono essere specificati -quando si vuole selezionare una interfaccia specifica, usando questa struttura -con la funzione \func{bind}. +l'indice dell'interfaccia (l'\textit{inxterface index} (vedi +sez.~\ref{sec:sock_ioctl_netdevice}) che in caso di presenza di più +interfacce dello stesso tipo (se ad esempio si hanno più schede Ethernet), +permette di selezionare quella con cui si vuole operare (un valore nullo +indica qualunque interfaccia). Questi sono i due soli campi che devono essere +specificati quando si vuole selezionare una interfaccia specifica, usando +questa struttura con la funzione \func{bind}. I campi \var{sll\_halen} e \var{sll\_addr} indicano rispettivamente l'indirizzo associato all'interfaccia sul protocollo di collegamento e la @@ -808,7 +867,7 @@ funzioni sono \funcd{htonl}, \funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i rispettivi prototipi sono: \begin{funcproto}{ -\fhead{netinet/in.h} +\fhead{arpa/inet.h} \fdecl{unsigned long int htonl(unsigned long int hostlong)} \fdesc{Converte l'intero a 32 bit \param{hostlong} dal formato della macchina a quello della rete.} @@ -816,11 +875,11 @@ rispettivi prototipi sono: \fdesc{Converte l'intero a 16 bit \param{hostshort} dal formato della macchina a quello della rete.} \fdecl{unsigned long int ntohl(unsigned long int netlong)} -\fdesc{Converte l'intero a 32 bit \param{netlong} dal formato della rete a quello - della macchina.} +\fdesc{Converte l'intero a 32 bit \param{netlong} dal formato della rete a + quello della macchina.} \fdecl{unsigned sort int ntohs(unsigned short int netshort)} -\fdesc{Converte l'intero a 16 bit \param{netshort} dal formato della rete a quello - della macchina.} +\fdesc{Converte l'intero a 16 bit \param{netshort} dal formato della rete a + quello della macchina.} } {Tutte le funzioni restituiscono il valore convertito, e non prevedono @@ -841,63 +900,112 @@ sempre utilizzate, anche quando potrebbero non essere necessarie, in modo da assicurare la portabilità del codice su tutte le architetture. -\subsection{Le funzioni \func{inet\_aton}, \func{inet\_addr} e - \func{inet\_ntoa}} +\subsection{Le funzioni di conversione per gli indirizzi IPv4} \label{sec:sock_func_ipv4} -Un secondo insieme di funzioni di manipolazione serve per passare dal formato -binario usato nelle strutture degli indirizzi alla rappresentazione simbolica -dei numeri IP che si usa normalmente. +Un secondo insieme di funzioni di manipolazione è quello che serve per passare +dalla rappresentazione simbolica degli indirizzi IP al formato binario +previsto dalla struttura degli indirizzi di +fig.~\ref{fig:sock_sa_ipv4_struct}, e viceversa. La notazione più comune è la +cosiddetta notazione \itindex{dotted-decimal} \textit{dotted-decimal}, che +prevede che gli indirizzi IPv4 siano indicati con l'espressione del valore +numerico decimale di ciascuno dei 4 byte che li costituiscono separati da un +punto (ad esempio \texttt{192.168.0.1}). + +In realtà le funzioni che illustreremo supportano una notazione che più +propriamente dovrebbe esser chiamata \textit{numbers-and-dot} in quanto il +valore può essere indicato con numeri espressi sia in decimale, che in ottale +(se indicati apponendo uno zero) che in esadecimale (se indicati apponendo +\texttt{0x}). Inoltre per la parte meno significativa dell'espressione, quella +che riguarda l'indirizzo locale, si può usare, eliminando altrettanti punti, +valori a 16 o a 24 bit, e togliendo tutti i punti, si può usare anche +direttamente un valore numerico a 32 bit.\footnote{la funzionalità si trova + anche in gran parte dei programmi che usano indirizzi di rete, e deriva + direttamente da queste funzioni.} + +Tradizionalmente la conversione di un indirizzo \textit{dotted-decimal} al +valore numerico veniva eseguita dalla funzione \funcd{inet\_addr} (prevista +fin dalle origini in BSD e inclusa in POSIX.1-2001) il cui prototipo è: + +\begin{funcproto}{ +\fhead{arpa/inet.h} +\fdecl{in\_addr\_t inet\_addr(const char *strptr)} +\fdesc{Converte la stringa dell'indirizzo \textit{dotted decimal} in nel + numero IP in network order.} +} -Le prime tre funzioni di manipolazione riguardano la conversione degli -indirizzi IPv4 da una stringa in cui il numero di IP è espresso secondo la -cosiddetta notazione \textit{dotted-decimal}, (cioè nella forma -\texttt{192.168.0.1}) al formato binario (direttamente in \textit{network - order}) e viceversa; in questo caso si usa la lettera \texttt{a} come -mnemonico per indicare la stringa. Dette funzioni sono \funcd{inet\_addr}, -\funcd{inet\_aton} e \funcd{inet\_ntoa}, ed i rispettivi prototipi sono: -\begin{functions} - \headdecl{arpa/inet.h} - - \funcdecl{in\_addr\_t inet\_addr(const char *strptr)} Converte la stringa - dell'indirizzo \textit{dotted decimal} in nel numero IP in network order. +{La funzione ritorna il valore dell'indirizzo in caso di successo e + \const{INADDR\_NONE} per un errore e non genera codici di errore.} +\end{funcproto} - \funcdecl{int inet\_aton(const char *src, struct in\_addr *dest)} Converte - la stringa dell'indirizzo \textit{dotted decimal} in un indirizzo IP. +La prima funzione, \func{inet\_addr}, restituisce l'indirizzo a 32 bit in +\textit{network order} (del tipo \type{in\_addr\_t}) a partire dalla stringa +passata nell'argomento \param{strptr}. In caso di errore (quando la stringa +non esprime un indirizzo valido) restituisce invece il valore +\const{INADDR\_NONE}, che tipicamente sono trentadue bit a uno. Questo però +comporta che la stringa \texttt{255.255.255.255}, che pure è un indirizzo +valido, non può essere usata con questa funzione dato che genererebe comunque +un errore; per questo motivo essa è generalmente deprecata in favore di +\func{inet\_aton}. + +Per effettuare la conversione inversa la funzione usata tradizionalmente è +\funcd{inet\_ntoa}, anch'essa presente fin da BSD 4.3, in cui si riprende la +notazione già vista in sez.~\ref{sec:sock_func_ord} che usa la lettera +\texttt{n} come mnemonico per indicare la rete ed \texttt{a} (per ASCII) come +mnemonico per indicare la stringa corrispodente all'indirizzo; il suo +prototipo è: - \funcdecl{char *inet\_ntoa(struct in\_addr addrptr)} - Converte un indirizzo IP in una stringa \textit{dotted decimal}. +\begin{funcproto}{ +\fhead{arpa/inet.h} +\fdecl{char *inet\_ntoa(struct in\_addr addrptr)} +\fdesc{Converte un indirizzo IP in una stringa \textit{dotted decimal}.} +} - \bodydesc{Tutte queste le funzioni non generano codice di errore.} -\end{functions} +{La funzione l'indirizzo della stringa con il valore dell'indirizzo convertito + e non prevede errori.} +\end{funcproto} -La prima funzione, \func{inet\_addr}, restituisce l'indirizzo a 32 bit in -network order (del tipo \type{in\_addr\_t}) a partire dalla stringa passata -nell'argomento \param{strptr}. In caso di errore (quando la stringa non esprime -un indirizzo valido) restituisce invece il valore \const{INADDR\_NONE} che -tipicamente sono trentadue bit a uno. Questo però comporta che la stringa -\texttt{255.255.255.255}, che pure è un indirizzo valido, non può essere usata -con questa funzione; per questo motivo essa è generalmente deprecata in favore -di \func{inet\_aton}. - -La funzione \func{inet\_aton} converte la stringa puntata da \param{src} -nell'indirizzo binario che viene memorizzato nell'opportuna struttura -\struct{in\_addr} (si veda fig.~\ref{fig:sock_sa_ipv4_struct}) situata -all'indirizzo dato dall'argomento \param{dest} (è espressa in questa forma in -modo da poterla usare direttamente con il puntatore usato per passare la -struttura degli indirizzi). La funzione restituisce un valore diverso da zero -se l'indirizzo è valido e la conversione ha successo e 0 in caso contrario. -Se usata con \param{dest} inizializzato a \val{NULL} effettua la validazione -dell'indirizzo. - -L'ultima funzione, \func{inet\_ntoa}, converte il valore a 32 bit -dell'indirizzo (espresso in \textit{network order}) restituendo il puntatore -alla stringa che contiene l'espressione in formato dotted decimal. Si deve -tenere presente che la stringa risiede in memoria statica, per cui questa -funzione non è rientrante. - - -\subsection{Le funzioni \func{inet\_pton} e \func{inet\_ntop}} +La funzione converte il valore a 32 bit dell'indirizzo, espresso in +\textit{network order}, e preso direttamente con un puntatore al relativo +campo della struttura degli indirizzi, restituendo il puntatore alla stringa +che contiene l'espressione in formato \textit{dotted-decimal}. Si deve tenere +presente che la stringa risiede in un segmento di memoria statica, per cui +viene riscritta ad ogni chiamata e la funzione non è rientrante. + +Per rimediare ai problemi di \funcd{inet\_addr} è stata sostituita da +\funcd{inet\_aton}, che però non è stata standardizzata e non è presente in +POSIX.1-2001, anche se è definita sulla gran parte dei sistemi Unix; il suo +prototipo è: + +\begin{funcproto}{ +\fhead{arpa/inet.h} +\fdecl{int inet\_aton(const char *src, struct in\_addr *dest)} +\fdesc{Converte la stringa dell'indirizzo \textit{dotted decimal} in un + indirizzo IP.} +} + +{La funzione ritorna un valore non nullo in caso di successo e $0$ per un + errore e non genera codici di errore.} +\end{funcproto} + +La funzione converte la stringa puntata da \param{src} nell'indirizzo binario +che viene memorizzato nell'opportuna struttura \struct{in\_addr} (si veda +fig.~\ref{fig:sock_sa_ipv4_struct}) situata all'indirizzo dato +dall'argomento \param{dest} (è espressa in questa forma in modo da poterla +usare direttamente con il puntatore usato per passare la struttura degli +indirizzi). La funzione restituisce un valore diverso da zero se l'indirizzo è +valido e la conversione ha successo e 0 in caso contrario. Se usata +con \param{dest} inizializzato a \val{NULL} può essere usata per effettuare la +validazione dell'indirizzo espresso da \param{src}. + +Oltre a queste tre funzioni esistono le ulteriori \funcm{inet\_lnaof}, +\funcm{inet\_netof} e \funcm{inet\_makeaddr} che assumono la ormai obsoleta e +deprecata suddivisione in classi degli indirizzi IP per fornire la parte di +rete e quella di indirizzo locale. Ad oggi il loro uso non ha più alcun senso +per ciò non le tratteremo. + + +\subsection{Le funzioni di conversione per indirizzi IP generici} \label{sec:sock_conv_func_gen} Le tre funzioni precedenti sono limitate solo ad indirizzi IPv4, per questo @@ -911,47 +1019,61 @@ Entrambe le funzioni accettano l'argomento \param{af} che indica il tipo di indirizzo, e che può essere soltanto \const{AF\_INET} o \const{AF\_INET6}. La prima funzione, \funcd{inet\_pton}, serve a convertire una stringa in un indirizzo; il suo prototipo è: -\begin{prototype}{sys/socket.h} -{int inet\_pton(int af, const char *src, void *addr\_ptr)} - Converte l'indirizzo espresso tramite una stringa nel valore numerico. - - \bodydesc{La funzione restituisce un valore negativo se \param{af} specifica - una famiglia di indirizzi non valida, con \var{errno} che assume il valore - \errcode{EAFNOSUPPORT}, un valore nullo se \param{src} non rappresenta un - indirizzo valido, ed un valore positivo in caso di successo.} -\end{prototype} +\begin{funcproto}{ +\fhead{sys/socket.h} +\fdecl{int inet\_pton(int af, const char *src, void *addr\_ptr)} +\fdesc{Converte l'indirizzo espresso tramite una stringa nel valore numerico.} +} + +{La funzione ritorna $1$ in caso di successo, $0$ se \param{src} non contiene + una rappresentazione valida per la famiglia di indirizzi indicati + da \param{af} e $-1$ se \param{af} specifica una famiglia di indirizzi non + valida, e solo in quest'ultimo caso \var{errno} assumerà il valore + \errcode{EAFNOSUPPORT}. +} +\end{funcproto} La funzione converte la stringa indicata tramite \param{src} nel valore numerico dell'indirizzo IP del tipo specificato da \param{af} che viene -memorizzato all'indirizzo puntato da \param{addr\_ptr}, la funzione -restituisce un valore positivo in caso di successo, nullo se la stringa non -rappresenta un indirizzo valido, e negativo se \param{af} specifica una -famiglia di indirizzi non valida. +memorizzato all'indirizzo puntato da \param{addr\_ptr}. La funzione supporta +per IPv4 la sola notazione \textit{dotted-decimal}, e non quella più completa +\textit{number-and-dot} che abbiamo visto per \func{inet\_aton}. Per IPv6 la +notazione prevede la suddivisione dei 128 bit dell'indirizzo in 16 parti di 16 +bit espresse con valori esadecimali separati dal carattere ``\texttt{:}'' ed +una serie di valori nulli possono essere sostituiti (una sola volta, sempre a +partire dalla sinistra) con la notazione ``\texttt{::}'', un esempio di +indirizzo in questa forma potrebbe essere \texttt{2001:db8::8:ba98:2078:e3e3}, +per una descrizione più completa si veda sez.~\ref{sec:IP_ipv6_notation}. La seconda funzione di conversione è \funcd{inet\_ntop} che converte un indirizzo in una stringa; il suo prototipo è: -\begin{prototype}{sys/socket.h} - {char *inet\_ntop(int af, const void *addr\_ptr, char *dest, size\_t len)} - Converte l'indirizzo dalla relativa struttura in una stringa simbolica. - - \bodydesc{La funzione restituisce un puntatore non nullo alla stringa - convertita in caso di successo e \val{NULL} in caso di fallimento, nel - qual caso \var{errno} assume i valori: - \begin{errlist} + +\begin{funcproto}{ +\fhead{sys/socket.h} +\fdecl{char *inet\_ntop(int af, const void *addr\_ptr, char *dest, size\_t len)} +\fdesc{Converte l'indirizzo dalla relativa struttura in una stringa simbolica.} +} + +{La funzione ritorna un puntatore non nullo alla stringa convertita in caso di + successo e \val{NULL} per un errore, nel qual caso \var{errno} assumerà uno + dei valori: + \begin{errlist} \item[\errcode{ENOSPC}] le dimensioni della stringa con la conversione dell'indirizzo eccedono la lunghezza specificata da \param{len}. \item[\errcode{ENOAFSUPPORT}] la famiglia di indirizzi \param{af} non è una valida. - \end{errlist}} -\end{prototype} + \end{errlist} +} +\end{funcproto} + La funzione converte la struttura dell'indirizzo puntata da \param{addr\_ptr} in una stringa che viene copiata nel buffer puntato dall'indirizzo \param{dest}; questo deve essere preallocato dall'utente e la lunghezza deve essere almeno \constd{INET\_ADDRSTRLEN} in caso di indirizzi IPv4 e \constd{INET6\_ADDRSTRLEN} per indirizzi IPv6; la lunghezza del buffer deve -comunque venire specificata attraverso il parametro \param{len}. +comunque essere specificata con il parametro \param{len}. Gli indirizzi vengono convertiti da/alle rispettive strutture di indirizzo (una struttura \struct{in\_addr} per IPv4, e una struttura \struct{in6\_addr} @@ -959,11 +1081,6 @@ per IPv6), che devono essere precedentemente allocate e passate attraverso il puntatore \param{addr\_ptr}; l'argomento \param{dest} di \func{inet\_ntop} non può essere nullo e deve essere allocato precedentemente. -Il formato usato per gli indirizzi in formato di presentazione è la notazione -\textit{dotted decimal} per IPv4 e quello descritto in -sez.~\ref{sec:IP_ipv6_notation} per IPv6. - - diff --git a/tcpsock.tex b/tcpsock.tex index ff4aa49..b408819 100644 --- a/tcpsock.tex +++ b/tcpsock.tex @@ -16,7 +16,7 @@ In questo capitolo tratteremo le basi dei socket TCP, iniziando con una descrizione delle principali caratteristiche del funzionamento di una connessione TCP; vedremo poi le varie funzioni che servono alla creazione di una connessione fra client e server, fornendo alcuni esempi elementari, e -finiremo prendendo in esame l'uso dell'I/O multiplexing. +finiremo prendendo in esame l'uso dell'\textit{I/O multiplexing}. \section{Il funzionamento di una connessione TCP}