From b8a79028184003289dc1c92fdcfab416b130ce20 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 30 Sep 2006 15:56:57 +0000 Subject: [PATCH] Documentato l'uso di {{{SIOCGIFCONF}}} con tanto di programma di esempio {{{iflist.c}}} che stampa l'elenco delle interfacce e relativi indirizzi. --- errors.tex | 27 ++++++++++---- intro.tex | 16 ++++----- listati/iflist.c | 34 ++++++++++++++++++ sockctrl.tex | 91 +++++++++++++++++++++++++++++++++++++++++------- sources/iflist.c | 9 +++-- 5 files changed, 147 insertions(+), 30 deletions(-) create mode 100644 listati/iflist.c diff --git a/errors.tex b/errors.tex index 3028dc6..4141761 100644 --- a/errors.tex +++ b/errors.tex @@ -353,7 +353,7 @@ specificati nelle sezioni precedenti. %\item \errcode{ED} \textit{}. %\item \errcode{EGREGIOUS} \textit{}. %\item \errcode{EIEIO} \textit{}. -%\item \errcode{EGRATUITOUS} \textit{}. +%\item \errcode{EGRATUITOUS} \textit{} roba di Hurd, pare. \item \errcode{EBADMSG} \textit{Not a data message}. Definito da Posix come @@ -388,18 +388,31 @@ messaggio. coda di messaggi del \textit{SysV IPC} non è presente nessun messaggio del tipo desiderato. -\item \errcode{ENOSR} \textit{Out of streams resources}. +\item \errcode{ENOSR} \textit{Out of streams resources}. Errore relativo agli + \textit{STREAMS}, che indica l'assenza di risorse sufficienti a completare + l'operazione richiesta. Quella degli \textit{STREAMS}\footnote{che non vanno + confusi con gli \textit{stream} di cap.~\ref{cha:files_std_interface}.} è + interfaccia di programmazione originaria di System V, che non è implementata + da Linux, per cui questo errore non viene utilizzato. -\item \errcode{ENOSTR} \textit{Device not a stream}. +\item \errcode{ENOSTR} \textit{Device not a stream}. Altro errore relativo + agli \textit{STREAMS}, anch'esso non utilizzato da Linux. \item \errcode{EOVERFLOW} \textit{Value too large for defined data type}. Si è chiesta la lettura di un dato dal \textit{SysV IPC} con \const{IPC\_STAT} ma il valore eccede la dimensione usata nel buffer di lettura. -\item \errcode{EPROTO} \textit{Protocol error}. C'è stato un errore nel - protocollo di rete usato dal socket. - -\item \errcode{ETIME} \textit{Timer expired}. +\item \errcode{EPROTO} \textit{Protocol error}. Indica che c'è stato un errore + nel protocollo di rete usato dal socket; viene usato come errore generico + dall'interfaccia degli \textit{STREAMS} quando non si è in grado di + specificare un altro codice di errore che esprima più accuratamente la + situazione. + +\item \errcode{ETIME} \textit{Timer expired}. Indica che è avvenuto un timeout + nell'accesso ad una risorsa (ad esempio un semaforo). Compare nei sorgenti + del kernel (in particolare per le funzioni relativa al bus USB) come + indicazione di una mancata risposta di un dispositivo, con una descrizione + alternativa di \textit{Device did not respond}. \end{description} diff --git a/intro.tex b/intro.tex index 9291d6d..6b95412 100644 --- a/intro.tex +++ b/intro.tex @@ -517,7 +517,7 @@ asincrono (sez.~\ref{sec:file_asyncronous_io}). -\subsection{Lo standard X/Open -- XPG3} +\subsection{Lo standard X/Open} \label{sec:intro_xopen} Il consorzio X/Open nacque nel 1984 come consorzio di venditori di sistemi @@ -550,13 +550,13 @@ versione di Spec 1170 divent Specification}, SUSv1, più comunemente nota come \textit{Unix 95}. -\subsection{Gli standard Unix -- Open Group} +\subsection{Gli standard Unix} \label{sec:intro_opengroup} Nel 1996 la fusione del consorzio X/Open con la Open Software Foundation (nata da un gruppo di aziende concorrenti rispetto ai fondatori di X/Open) portò -alla costituzione dell'Open Group, un consorzio internazionale che raccoglie -produttori, utenti industriali, entità accademiche e governative. +alla costituzione dell'\textit{Open Group}, un consorzio internazionale che +raccoglie produttori, utenti industriali, entità accademiche e governative. Attualmente il consorzio è detentore del marchio depositato Unix, e prosegue il lavoro di standardizzazione delle varie implementazioni, rilasciando @@ -707,10 +707,10 @@ Le macro disponibili per i vari standard sono le seguenti: \end{basedescript} In particolare è da sottolineare che le \acr{glibc} supportano alcune -estensioni specifiche GNU, che non sono comprese in nessuno degli -standard citati. Per poterle utilizzare esse devono essere attivate -esplicitamente definendo la macro \macro{\_GNU\_SOURCE} prima di -includere i vari header file. +estensioni specifiche GNU, che non sono comprese in nessuno degli standard +citati. Per poterle utilizzare esse devono essere attivate esplicitamente +definendo la macro \macro{\_GNU\_SOURCE} prima di includere i vari header +file. %% \subsection{Gli standard di GNU/Linux} diff --git a/listati/iflist.c b/listati/iflist.c new file mode 100644 index 0000000..256b1cb --- /dev/null +++ b/listati/iflist.c @@ -0,0 +1,34 @@ +int i, num, ret, sock; +struct ifconf iflist; +char buffer[4096]; +struct sockaddr_in * address; +... +/* create a socket for the operation */ +sock = socket(PF_INET, SOCK_STREAM, 0); +if (sock < 0) { + perror("Socket creation error"); + return 1; +} +/* init values for the ifcon structure and do SIOCGIFCONF */ +iflist.ifc_len = sizeof(buffer); +iflist.ifc_buf = buffer; +ret = ioctl(sock, SIOCGIFCONF, &iflist); +if (ret < 0) { + perror("ioctl failed"); + return 1; +} +/* check that we have all data */ +if (iflist.ifc_len == sizeof(buffer)) { + printf("Probable overflow, too many interfaces, cannot read\n"); + return 1; +} else { + num = iflist.ifc_len/sizeof(struct ifreq); + printf("Found %i interfaces \n", num); +} +/* loop on interface to write data */ +for (i=0; i < num; i++) { + address = (struct sockaddr_in *) &iflist.ifc_req[i].ifr_addr; + printf("Interface %s, address %s\n", iflist.ifc_req[i].ifr_name, + inet_ntoa(address->sin_addr)); +} +return 0; diff --git a/sockctrl.tex b/sockctrl.tex index 69894b3..a1490ad 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -2775,7 +2775,9 @@ seguente elenco: una struttura \struct{pktinfo} (vedi fig.~\ref{fig:sock_pktinfo_struct}) che mantiene una serie di informazioni riguardo i pacchetti in arrivo. In particolare è possibile conoscere l'interfaccia su cui è stato ricevuto un - pacchetto (nel campo \var{ipi\_ifindex}), l'indirizzo locale da esso + pacchetto (nel campo \var{ipi\_ifindex}),\footnote{in questo campo viene + restituito il valore numerico dell'indice dell'interfaccia, + sec.~\ref{sec:sock_ioctl_netdevice}.} l'indirizzo locale da esso utilizzato (nel campo \var{ipi\_spec\_dst}) e l'indirizzo remoto dello stesso (nel campo \var{ipi\_addr}). @@ -3297,7 +3299,7 @@ quantit \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \includestruct{listati/is_closing.c} + \includecodesnip{listati/is_closing.c} \end{minipage} \caption{Codice della funzione \texttt{is\_closing.c}, che controlla lo stato di un socket TCP per verificare se si sta chiudendo.} @@ -3595,9 +3597,10 @@ sono le seguenti: effettivamente la identifica nelle operazioni a basso livello, il nome dell'interfaccia è soltanto una etichetta associata a detto \textsl{indice}, che permette di rendere più comprensibile l'indicazione dell'interfaccia - all'interno dei comandi; si può ottenere un elenco delle interfacce che - contiene anche il valore del relativo indice usando il comando \cmd{ip - link}. + all'interno dei comandi. Una modalità per ottenere questo valore è usare il + comando \cmd{ip link}, che fornisce un elenco delle interfacce presenti + ordinato in base a tale valore (riportato come primo campo). + \item[\const{SIOCGIFINDEX}] restituisce nel campo \var{ifr\_ifindex} il valore numerico dell'indice dell'interfaccia specificata con \var{ifr\_name}, è in @@ -3665,8 +3668,8 @@ sono le seguenti: \item[\const{SIOCGIFMETRIC}] permette di leggere il valore della metrica del dispositivo associato all'interfaccia specificata nel campo - \var{ifr\_metric}, attualmente non ancora implementato, restituisce sempre 0 - come valore. + \var{ifr\_metric}. Attualmente non è implementato, e l'operazione + restituisce sempre un valore nullo. \item[\const{SIOCSIFMETRIC}] permette di impostare il valore della metrica del dispositivo al valore specificato nel campo \var{ifr\_metric}, attualmente @@ -3750,11 +3753,12 @@ sono le seguenti: \end{basedescript} -Una ulteriore operazione che consente di ricavare le caratteristiche delle -interfacce di rete, che però è disponibile soltanto per socket della famiglia -\const{AF\_INET} (vale ad dire per socket IPv4), è \const{SIOCGIFCONF}. In -questo caso l'utente dovrà passare come argomento una struttura -\struct{ifconf}, definita in fig.~\ref{fig:netdevice_ifconf_struct}. +Una ulteriore operazione, che consente di ricavare le caratteristiche delle +interfacce di rete, è \const{SIOCGIFCONF}; però per ragioni di compatibilità +questa operazione è disponibile soltanto per i socket della famiglia +\const{AF\_INET} (vale ad dire per socket IPv4). In questo caso l'utente dovrà +passare come argomento una struttura \struct{ifconf}, definita in +fig.~\ref{fig:netdevice_ifconf_struct}. \begin{figure}[!htb] \footnotesize \centering @@ -3765,6 +3769,69 @@ questo caso l'utente dovr \label{fig:netdevice_ifconf_struct} \end{figure} +Per eseguire questa operazione occorrerà allocare preventivamente un buffer di +contentente un vettore di strutture \struct{ifreq}. La dimensione (in byte) di +questo buffer deve essere specificata nel campo \var{ifc\_len} di +\struct{ifconf}, mentre il suo indirizzo andrà specificato nel campo +\var{ifc\_req}. Qualora il buffer sia stato allocato come una stringa, il suo +indirizzo potrà essere fornito usando il campo \var{ifc\_buf}.\footnote{si + noti che l'indirizzo del buffer è definito in \struct{ifconf} con una + \ctyp{union}, questo consente di utilizzare una delle due forme a piacere.} + +La funzione restituisce nel buffer indicato una serie di strutture +\struct{ifreq} contenenti nel campo \var{ifr\_name} il nome dell'interfaccia e +nel campo \var{ifr\_addr} il relativo indirizzo IP. Se lo spazio allocato nel +buffer è sufficiente il kernel scriverà una struttura \struct{ifreq} per +ciascuna interfaccia attiva, restituendo nel campo \var{ifc\_len} il totale +dei byte effettivamente scritti. Il valore di ritorno è 0 se l'operazione ha +avuto successo e negativo in caso contrario. + +Si tenga presente che il kernel non scriverà mai sul buffer di uscita dati +eccedenti numero di byte specificato col valore di \var{ifc\_len} impostato +alla chiamata della funzione, troncando il risultato se questi non dovessero +essere sufficienti. Questa condizione non viene segnalata come errore per cui +occorre controllare il valore di \var{ifc\_len} all'uscita della funzione, e +verificare che esso sia inferiore a quello di ingresso. In caso contrario si è +probabilmente\footnote{probabilmente perché si potrebbe essere nella + condizione in cui sono stati usati esattamente quel numero di byte.} avuta +una situazione di troncamento dei dati. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/iflist.c} + \end{minipage} + \caption{Il corpo principale del programma \texttt{iflist.c}.} + \label{fig:netdevice_iflist} +\end{figure} + +Come esempio dell'uso di queste funzioni si è riportato in +fig.~\ref{fig:netdevice_iflist} il corpo principale del programma +\texttt{iflist} in cui si utilizza l'operazione \const{SIOCGIFCONF} per +ottenere una lista delle interfacce attive e dei relativi indirizzi. Al solito +il codice completo è fornito nei sorgenti allegati alla guida. + +Il programma inizia (\texttt{\small 7--11}) con la creazione del socket +necessario ad eseguire l'operazone, dopo di che si inizializzano +opportunamente (\texttt{\small 13--14}) i valori della struttura +\struct{ifconf} indicando la dimensione del buffer ed il suo +indirizzo;\footnote{si noti come in questo caso si sia specificato l'indirizzo + usando il campo \var{ifc\_buf}, mentre nel seguito del programma si accederà + ai valori contenuti nel buffer usando \var{ifc\_req}.} si esegue poi +l'operazione invocando \func{ioctl}, controllando come sempre la corretta +esecuzione, ed uscendo in caso di errore (\texttt{\small 15--19}). + +Si esegue poi un controllo sulla quantità di dati restituiti segnalando un +eventuale overflow del buffer (\texttt{\small 21--23}); se invece è tutto a +posto (\texttt{\small 24--27}) si calcola e si stampa a video il numero di +interfacce attive trovate. L'ultima parte del programma (\texttt{\small + 28--33}) è il ciclo sul contenuto delle varie strutture \struct{ifreq} +restituite in cui si estrae (\texttt{\small 30}) l'indirizzo ad esse +assegnato\footnote{si è definito \var{access} come puntatore ad una struttura + di tipo \struct{sockaddr\_in} per poter eseguire un \textit{casting} + dell'indirizzo del valore restituito nei vari campi \var{ifr\_addr}, così + poi da poterlo poi usare come argomento di \func{inet\_ntoa}.} e lo si +stampa (\texttt{\small 31--32}) insieme al nome dell'interfaccia. diff --git a/sources/iflist.c b/sources/iflist.c index 6020b52..371714f 100644 --- a/sources/iflist.c +++ b/sources/iflist.c @@ -85,19 +85,21 @@ int main(int argc, char *argv[]) printf("Wrong number of arguments %d\n", argc - optind); usage(); } - iflist.ifc_len = sizeof(buffer); - iflist.ifc_buf = buffer; - + /* create a socket for the operation */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { perror("Socket creation error"); return 1; } + /* init values for the ifcon structure and do SIOCGIFCONF */ + iflist.ifc_len = sizeof(buffer); + iflist.ifc_buf = buffer; ret = ioctl(sock, SIOCGIFCONF, &iflist); if (ret < 0) { perror("ioctl failed"); return 1; } + /* check that we have all data */ if (iflist.ifc_len == sizeof(buffer)) { printf("Probable overflow, too many interfaces, cannot read\n"); return 1; @@ -105,6 +107,7 @@ int main(int argc, char *argv[]) num = iflist.ifc_len/sizeof(struct ifreq); printf("Found %i interfaces \n", num); } + /* loop on interface to write data */ for (i=0; i < num; i++) { address = (struct sockaddr_in *) &iflist.ifc_req[i].ifr_addr; printf("Interface %s, address %s\n", iflist.ifc_req[i].ifr_name, -- 2.30.2