Documentato l'uso di {{{SIOCGIFCONF}}} con tanto di programma di
authorSimone Piccardi <piccardi@gnulinux.it>
Sat, 30 Sep 2006 15:56:57 +0000 (15:56 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sat, 30 Sep 2006 15:56:57 +0000 (15:56 +0000)
esempio {{{iflist.c}}} che stampa l'elenco delle interfacce e relativi
indirizzi.

errors.tex
intro.tex
listati/iflist.c [new file with mode: 0644]
sockctrl.tex
sources/iflist.c

index 3028dc6cff6c56120ada38d10d35bf4468051062..4141761a0b961bc34670c776f85c9b49c4abee7c 100644 (file)
@@ -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}
 
 
index 9291d6d4cd266ef29d7ada943376a5e8a3820bda..6b95412caaeb82051b46823ee0599f5f0152a16c 100644 (file)
--- 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 (file)
index 0000000..256b1cb
--- /dev/null
@@ -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;
index 69894b38bcee7acf474f037ee8070383bc6f3ef9..a1490ade0640bf06b4e330eca2fed241ead24a3e 100644 (file)
@@ -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.
 
 
 
index 6020b5282b97f8f3e40918f3ee0f481797f9c4ce..371714f1684173be5816e024556d3a250558747f 100644 (file)
@@ -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,