%\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
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}
-\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
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
\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}
--- /dev/null
+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;
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}).
\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.}
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
\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
\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
\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.
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;
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,