Modificato il makefile per la generazione automatica delle figure,
authorSimone Piccardi <piccardi@gnulinux.it>
Mon, 19 Aug 2002 17:34:23 +0000 (17:34 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Mon, 19 Aug 2002 17:34:23 +0000 (17:34 +0000)
eliminando  il vecchio script).

Riscritto il server di fortunes con le fifo per usare il trucchetto
della doppia apertura.

Aggiornato il materiale per il sito. Riviste varie referenze sballate.

13 files changed:
Makefile
gapil.tex
geneimg.sh [deleted file]
html/index.html
html/stampa.html
ipc.tex
ipprot.tex
network.tex
prochand.tex
sources/FortuneClient.c
sources/FortuneServer.c
sources/IPCTestId.c
sources/Makefile

index e50363e..3a268c2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,15 @@
+SOURCE_IMG = $(wildcard img/*.dia)
+EPS_IMG = $(SOURCE_IMG:.dia=.eps)
+PDF_IMG = $(SOURCE_IMG:.dia=.pdf)
 
-html: *.tex
+all: $(PDF_IMG) htm
+
+$(PDF_IMG): %.pdf: %.eps
+       epstopdf $< --outfile=$@
+$(EPS_IMG): %.eps : %.dia
+       dia -e $@ $< 
+
+htm: *.tex
        latex2html -local_icons -no_math -no_footnode gapil.tex
 
 gapil.dvi:  *.tex
index be7b703..6392012 100644 (file)
--- a/gapil.tex
+++ b/gapil.tex
@@ -21,8 +21,8 @@
 \usepackage{listings}
 \lstloadlanguages{C++}
 \usepackage{color} 
-\usepackage{mdwlist}              % scommentare per la stampa (PS e PDF)
-\usepackage{boxedminipage}        % scommentare per la stampa (PS e PDF)
+%\usepackage{mdwlist}              % scommentare per la stampa (PS e PDF)
+%\usepackage{boxedminipage}        % scommentare per la stampa (PS e PDF)
 %\usepackage{footnote} 
 %\usepackage{mdwtab} 
 %
@@ -73,7 +73,7 @@
 \tableofcontents
 \clearemptydoublepage
 
-%\include{compatib}    % commentare per la stampa PS e PDF
+\include{compatib}    % commentare per la stampa PS e PDF
 \include{macro}
 \setcounter{secnumdepth}{-2}
 \include{pref}
diff --git a/geneimg.sh b/geneimg.sh
deleted file mode 100644 (file)
index b648322..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-# Contributo di A. Frusciante
-for i in img/*dia
-do
-j=`basename $i .dia`
-dia -e img/$j.eps $i
-epstopdf  img/$j.eps --outfile=img/$j.pdf
-done
index 0c15b4e..52a7fec 100644 (file)
@@ -2,6 +2,11 @@
   <HEAD>
    <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
     <TITLE>GaPiL -- Guida alla Programmazione in Linux</TITLE>
+    <META name="author" content="Simone Piccardi">
+    <META name="title" content="Guida alla Programmazione in Linux">
+    <META name="description" content="Un manuale di programmazione avanzata in
+      Linux">
+    <META name="keywords" content="programmazione, programmazione linux, POSIX ">
     <style type="text/css">
 <!--
  a {text-decoration: none;}
                rilasciato sotto <A
                HREF="http://www.gnu.org/copyleft/fdl.html">GNU FDL</a>, che
                possa servire a chi si accosta per la prima volta alla
-               programmazione di sistema sotto Unix, con la speranza di poter
-               un giorno raggiungere la qualità dei testi del compianto
-               R. W. Stevens. 
+               programmazione avanzata e di sistema in Linux, con la speranza
+               di poter un giorno raggiungere la qualità dei testi del
+               compianto R. W. Stevens.
            </p>
          </td>
        </tr> 
          </td>
          <td bgcolor="lightblue"> 
            <p>
-             <b>16 - agosto - 2002</b> <br> Sedici capitoli, 347 pagine.
+             <b>19 - agosto - 2002</b> <br> Sedici capitoli, 355 pagine.
            </p>
          </td>
        </tr>
index 82ad0e1..270820f 100644 (file)
@@ -2,6 +2,12 @@
   <HEAD>
     <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
     <TITLE>GaPiL -- Guida alla Programmazione in Linux</TITLE>
+    <META name="author" content="Simone Piccardi">
+    <META name="title" content="Guida alla Programmazione in Linux">
+    <META name="description" content="Un manuale di programmazione avanzata in
+      Linux">
+    <META name="keywords" content="programmazione, programmazione linux, POSIX
+      ">
     <style type="text/css">
 <!--
  a {text-decoration: none;}
diff --git a/ipc.tex b/ipc.tex
index 6ae11a3..c3fa85a 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -584,41 +584,55 @@ diverso da quelli preimpostati. Il codice completo 
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
     \begin{lstlisting}{}
+char *fifoname = "/tmp/fortune.fifo";
 int main(int argc, char *argv[])
 {
-    int i, n = 10;
-    char *fortunefilename = "/usr/share/games/fortunes/kids";
-    char *fifoname = "/tmp/fortune.fifo";
+/* Variables definition */
+    int i, n = 0;
+    char *fortunefilename = "/usr/share/games/fortunes/italia";
     char **fortune;
     char line[80];
     int fifo_server, fifo_client;
     int nread;
     ...
     if (n==0) usage();          /* if no pool depth exit printing usage info */
+    Signal(SIGTERM, HandSIGTERM);            /* set handlers for termination */
+    Signal(SIGINT, HandSIGTERM);
+    Signal(SIGQUIT, HandSIGTERM);
     i = FortuneParse(fortunefilename, fortune, n);          /* parse phrases */
-    /* 
-     * Comunication section 
-     */
     if (mkfifo(fifoname, 0622)) {  /* create well known fifo if does't exist */
         if (errno!=EEXIST) {
             perror("Cannot create well known fifo");
-            exit(-1);
+            exit(1);
         }
     }
+    /* open fifo two times to avoid EOF */
+    fifo_server = open(fifoname, O_RDONLY);
+    if (fifo_server < 0) {
+        perror("Cannot open read only well known fifo");
+        exit(1);
+    }
+    if (open(fifoname, O_WRONLY) < 0) {                        
+        perror("Cannot open write only well known fifo");
+        exit(1);
+    }
+    /* Main body: loop over requests */
     while (1) {
-        fifo_server = open(fifoname, O_RDONLY);      /* open well known fifo */
-        if (fifo_server < 0) {
-            perror("Cannot open well known fifo");
-            exit(-1);
-        }
         nread = read(fifo_server, line, 79);                 /* read request */
-        line[nread] = 0;
+        if (nread < 0) {
+            perror("Read Error");
+            exit(1);
+        }
+        line[nread] = 0;                       /* terminate fifo name string */
         n = random() % i;                             /* select random value */
         fifo_client = open(line, O_WRONLY);              /* open client fifo */
+        if (fifo_client < 0) {
+            perror("Cannot open");
+            exit(1);
+        }
         nread = write(fifo_client,                           /* write phrase */
                       fortune[n], strlen(fortune[n])+1);
-        close(fifo_client);                         /* close well known fifo */
-        close(fifo_server);                             /* close client fifo */
+        close(fifo_client);                             /* close client fifo */
     }
 }
     \end{lstlisting}
@@ -629,51 +643,166 @@ int main(int argc, char *argv[])
   \label{fig:ipc_fifo_server}
 \end{figure}
 
-Il server richiede (\texttt{\small 11}) che sia stata impostata una dimensione
-dell'insieme delle frasi non nulla, stampando, nel caso ciò non avvenga, un
-messaggio apposito ed uscendo. Poi (\texttt{\small 12}) effettua la chiamata
-alla funzione \code{FortuneParse} che legge dal file specificato in
-\var{fortunefilename} le prime \var{n} frasi e le memorizza nel vettore di
-puntatori \var{fortune}. Il codice della funzione non è riportato, in quanto
-non direttamente attinente allo scopo dell'esempio, lo si può trovare nel file
-\file{FortuneParse.c} allegato coi sorgenti degli esempi.
-
-Il passo successivo \texttt{\small 16--21}) è quello di creare, se non esiste
-già, la fifo nota sulla quale il server ascolterà le richieste, qualora si
-riscontri un errore il server uscirà (escludendo ovviamente il caso in cui la
-funzione \func{mkfifo} fallisce per la precedente esistenza della fifo. 
-
-Fatto questo si entra nel ciclo principale del programma \texttt{\small
-  22--36}), che viene eseguito indefinitamente (l'uscita del server deve
-essere effettuata tramite segnale), e che provvede a fornire le risposte ai
-client. Il server è progettato per accettare le richieste dai client che
-devono scrivere il nome della fifo sulla quale vogliono ricevere la risposta
-sulla fifo su cui il server è in ascolto.
-
-Il primo passo è aprire in lettura la fifo (\texttt{\small 23}), se nessun
-client ha effettuato una richiesta la fifo non ha capi aperti in scrittura, e
-pertanto il server si bloccherà. Una volta che un client ha aperto la fifo in
-scrittura il server si sbloccherà ed effetturà la lettura (\texttt{\small 28})
-della richiesta del client (nel caso limitata a 79 byte).
-
-Dopo di che verrà calcolato (\texttt{\small 30}) un numero casuale nel range
-delle frasi disponibili nella nostra lista, e verrà aperta (\texttt{\small
-  31}) la fifo sulla quale il client vuole ricevere la risposta, che sarà poi
-scritta (\texttt{\small 32}). Dopo di che \texttt{\small 34--35}) entrambe le
-fifo verranno chiuse.
+Il server richiede (\texttt{\small 12}) che sia stata impostata una dimensione
+dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore
+\var{fortune} avviene solo quando questa dimensione viene specificata, la
+presenza di un valore nullo provoca l'uscita dal programma attraverso la
+routine (non riportata) che ne stampa le modalità d'uso.  Dopo di che installa
+(\texttt{\small 13--15}) la funzione che gestisce i segnali di interruzione
+(anche questa non è riportata in \figref{fig:ipc_fifo_server}) che si limita a
+rimuovere dal filesystem la fifo usata dal server per comunicare.
+
+Terminata l'inizializzazione (\texttt{\small 16}) si effettua la chiamata alla
+funzione \code{FortuneParse} che legge dal file specificato in
+\var{fortunefilename} le prime \var{n} frasi e le memorizza (allocando
+dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}.
+Anche il codice della funzione non è riportato, in quanto non direttamente
+attinente allo scopo dell'esempio.
+
+Il passo successivo (\texttt{\small 17--22}) è quello di creare con
+\func{mkfifo} la fifo nota sulla quale il server ascolterà le richieste,
+qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso
+in cui la funzione \func{mkfifo} fallisce per la precedente esistenza della
+fifo).
+
+Una volta che si è certi che la fifo di ascolto esiste si procede
+(\texttt{\small 23--32}) alla sua apertura. Questo viene fatto due volte
+per evitare di dover gestire all'interno del ciclo principale il caso in cui
+il server è in ascolto ma non ci sono client che effettuano richieste.
+Si ricordi infatti che quando una fifo è aperta solo dal capo in lettura,
+l'esecuzione di \func{read} ritorna con zero byte (si ha cioè una condizione
+di end-of-file).
+
+Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque
+client non apre a sua volta la fifo nota in scrittura per effettuare la sua
+richiesta. Pertanto all'inizio non ci sono probelmi, il client però, una volta
+ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la fifo.
+A questo punto il server resta (se non ci sono altri client che stanno
+effettuando richieste) con la fifo chiusa sul lato in lettura e a questo punto
+\func{read} non si bloccherà in attesa di input, ma ritornerà in continuazione
+restituendo un end-of-file.\footnote{Si è usata questa tecnica per
+  compatibilità, Linux infatti supporta l'apertura delle fifo in
+  lettura/scrittura, per cui si sarebbe potuto effettuare una singola apertura
+  con \macro{O\_RDWR}, la doppia apertura comunque ha il vantaggio che non si
+  può scrivere per errore sul capo aperto in sola lettura.}
+
+Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
+  24--28}),\footnote{di solito si effettua l'apertura del capo in lettura in
+  modalità non bloccante, per evitare il rischio di uno stallo (se nessuno
+  apre la fifo in scrittura il processo non ritornerà mai dalla \func{open})
+  che nel nostro caso non esiste, mentre è necessario potersi bloccare in
+  lettura in attesa di una richiesta.} si esegue una seconda apertura in
+scrittura (\texttt{\small 29--32}), scartando il relativo file descriptor che
+non sarà mai usato, ma lasciando la fifo comunque aperta anche in scrittura,
+cosicchè le successive possano bloccarsi.
+
+A questo punto si può entrare nel ciclo principale del programma che fornisce
+le risposte ai client (\texttt{\small 34--50}), che viene eseguito
+indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
+modo da passare attraverso la routine di chiusura che cancella la fifo). 
+
+Il server è progettato per accettare come richieste dai client delle stringhe
+che contengono il nome della fifo sulla quale deve essere inviata la risposta.
+Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
+richiesta dalla fifo nota (che a questo punto si bloccherà tutte le volte che
+non ci sono richieste). Dopo di che, una volta terminata la stringa
+(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
+ricavare la frase da invaire, si procederà (\texttt{\small 42--46})
+all'apertura della fifo per la risposta, che \texttt{\small 47--48}) poi vi
+sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
+non serve più. 
+
+Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
+in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
+a video le informazioni di utilizzo ed esce, riportando solo la sezione
+principale del programma e le definizioni delle variabili. Il codice completo
+è nel file \file{FortuneClient.c} dei sorgenti allegati.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+    int n = 0;
+    char *fortunefilename = "/tmp/fortune.fifo";
+    char line[80];
+    int fifo_server, fifo_client;
+    char fifoname[80];
+    int nread;
+    char buffer[PIPE_BUF];
+    ...
+    snprintf(fifoname, 80, "/tmp/fortune.%d", getpid());     /* compose name */
+    if (mkfifo(fifoname, 0622)) {                        /* open client fifo */
+        if (errno!=EEXIST) {
+            perror("Cannot create well known fifo");
+            exit(-1);
+        }
+    }
+    fifo_server = open(fortunefilename, O_WRONLY);       /* open server fifo */
+    if (fifo_server < 0) {
+        perror("Cannot open well known fifo");
+        exit(-1);
+    }
+    nread = write(fifo_server, fifoname, strlen(fifoname)+1);  /* write name */
+    close(fifo_server);                                 /* close server fifo */
+    fifo_client = open(fifoname, O_RDONLY);              /* open client fifo */
+    if (fifo_client < 0) {
+        perror("Cannot open well known fifo");
+        exit(-1);
+    }
+    nread = read(fifo_client, buffer, sizeof(buffer));        /* read answer */
+    printf("%s", buffer);                                   /* print fortune */
+    close(fifo_client);                                      /* close client */
+    close(fifo_server);                                      /* close server */
+    unlink(fifoname);                                  /* remove client fifo */
+}
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{Sezione principale del codice del client di \textit{fortunes}
+    basato sulle fifo.}
+  \label{fig:ipc_fifo_client}
+\end{figure}
+
+La prima istruzione (\texttt{\small 12}) compone il nome della fifo che dovrà
+essere utilizzata per ricevere la risposta dal server.  Si usa il \acr{pid}
+del processo per essere sicuri di avere un nome univoco; dopo di che
+(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo
+in caso di errore (a meno che il file non sia già presente sul filesystem).
+
+A questo punto il client può effettuare l'interrogazione del server, pe questo
+prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
+(\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
+della fifo da utilizzare per la risposta. Infine si richiude la fifo del
+server che a questo punto non serve più (\texttt{\small 25}).
+
+Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto
+si apre (\texttt{\small 26--30}) la fifo appena creata, da cui si deve
+riceverla, dopodiché si effettua una lettura (\texttt{\small 31})
+nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate
+dal server siano sempre di dimensioni inferiori a \macro{PIPE\_BUF},
+tralasciamo la gestione del caso in cui questo non è vero. Infine si stampa
+(\texttt{\small 32}) a video la risposta, si chiude (\texttt{\small 33}) la
+fifo e si cancella (\texttt{\small 34}) il relativo file.
+
+Si noti come la fifo per la risposta sia stata aperta solo dopo aver inviato
+la richiesta, se non si fosse fatto così si avrebbe avuto uno stallo, in
+quanto senza la richiesta, il server non avrebbe potuto aprirne il capo in
+scrittura e l'apertura si sarebbe bloccata indefinitamente.
 
 
 Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
 complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
   che esamina questa architettura in \cite{APUE}, nota come sia impossibile
   per il server sapere se un client è andato in crash, con la possibilità di
-  far restare le fifo temporanee sul filesystem, come sia necessario
+  far restare le fifo temporanee sul filesystem, di come sia necessario
   intercettare \macro{SIGPIPE} dato che un client può terminare dopo aver
-  fatto una richiesta, ma prima che la risposta sia inviata, e come occorra
-  gestire il caso in cui non ci sono client attivi (e la lettura dalla fifo
-  nota restituisca al serve un end-of-file.}; in generale infatti
-l'interfaccia delle fifo non è adatta a risolvere questo tipo di problemi, che
-possono essere affrontati in maniera più semplice ed efficace o usando i
+  fatto una richiesta, ma prima che la risposta sia inviata (cosa che nel
+  nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle
+fifo non è adatta a risolvere questo tipo di problemi, che possono essere
+affrontati in maniera più semplice ed efficace o usando i
 \textit{socket}\index{socket} (che tratteremo in dettaglio a partire da
 \capref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione diversi,
 come quelli che esamineremo in seguito.
@@ -791,9 +920,9 @@ che deve specificare il pathname di un file effettivamente esistente e di un
 numero di progetto \param{proj\_id)}, che di norma viene specificato come
 carattere, dato che ne vengono utilizzati solo gli 8 bit meno
 significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS,
-  l'argomento \param{proj\_id)} è dichiarato tipo \ctyp{char}, le \acr{glibc}
-  han modificato il prototipo, ma vengono lo stesso utilizzati gli 8 bit meno
-  significativi.}
+  l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le \acr{glibc}
+  usano il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli
+  8 bit meno significativi.}
 
 Il problema è che anche così non c'è la sicurezza che il valore della chiave
 sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)}
@@ -805,14 +934,15 @@ su dispositivi con lo stesso \textit{minor number}, come \file{/dev/hda1} e
 \file{/dev/sda1}.
 
 In genere quello che si fa è utilizzare un file comune usato dai programmi che
-devono comunicare (ad esempio un haeder, o uno dei programmi che devono usare
-l'oggetto in questione), utilizzando il numero di progetto per ottere le
+devono comunicare (ad esempio un haeder comune, o uno dei programmi che devono
+usare l'oggetto in questione), utilizzando il numero di progetto per ottere le
 chiavi che interessano. In ogni caso occorre sempre controllare, prima di
 creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
 bene in fase di creazione, le cose possono complicarsi per i programmi che
 devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
 attributi di \var{ipc\_perm}, non esiste una modalità semplice per essere
-sicuri della validità di una certa chiave.
+sicuri che l'oggetto associato ad una certa chiave sia stato effettivamente
+creato da chi ci si aspetta.
 
 Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
 contatore di riferimenti per la cancellazione automatica, il principale
@@ -830,45 +960,43 @@ Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in
 \var{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
 (nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
 \var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
-questo modo è possibile definire un controllo di accesso sugli oggetti, simile
-a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).  
-
-Benché il controllo di accesso relativo agli oggetti di intercomunicazione sia
-molto simile a quello dei file, restano delle importanti differenze. La prima
-è che il permesso di esecuzione non esiste (e viene ignorato), per cui si può
-parlare solo di permessi di lettura e scrittura (nel caso dei semafori poi
-quest'ultimo è più propriamente il permesso di modificarne lo stato). I valori
-di \var{mode} sono gli stessi ed hanno lo stesso significato di quelli
-riportati in \secref{tab:file_mode_flags}\footnote{se però si vogliono usare
-  le costanti simboliche ivi definite occorrerà includere il file
-  \file{sys/stat.h}, alcuni sistemi definiscono le costanti \macro{MSG\_R}
-  (\texttt{0400}) e \macro{MSG\_W} (\texttt{0200}) per indicare i permessi
-  base di lettura e scrittura per il proprietario, da utilizzare, con gli
-  opportuni shift, pure per il gruppo e gli altri, in Linux, visto la loro
-  scarsa utilità, queste costanti non sono definite.} e come per i file
-definiscono gli accessi per il proprietario, il suo gruppo e tutti gli altri.
-
-Si tenga presente che per gli oggetti di IPC han senso solo i permessi di
-lettura e scrittura, quelli di esecuzione vengono ignorati. Quando l'oggetto
-viene creato i campi \var{cuid} e \var{uid} di \var{ipc\_perm} ed i campi
-\var{cgid} e \var{gid} vengono settati rispettivamente al valore dell'userid e
-del groupid effettivo del processo che ha chiamato la funzione, ma mentre i
-campi \var{uid} e \var{gid} possono essere cambiati, \var{cuid} e \var{cgid}
-restano sempre gli stessi.
-
-Il controllo di accesso è effettuato a due livelli. Il primo è nelle funzioni
-che richiedono l'identificatore di un oggetto data la chiave, che specificano
-tutte un argomento \param{flag}.  In tal caso quando viene effettuata la
-ricerca di una chiave, se \param{flag} specifica dei permessi, questi vengono
-controllati e l'identificatore viene restituito solo se essi corrispondono a
-quelli dell'oggetto. Se sono presenti dei permessi non presenti in \var{mode}
-l'accesso sarà invece negato. Questo però è di utilità indicativa, dato che è
-sempre possibile specificare un valore nullo per \param{flag}, nel qual caso
-il controllo avrà sempre successo.
-
-Il secondo livello è quello delle varie funzioni che accedono (in lettura o
-scrittura) all'oggetto. In tal caso lo schema dei controlli è simile a quello
-dei file, ed avviene secondo questa sequenza:
+questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
+simile a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).
+
+Benché questo controllo di accesso sia molto simile a quello dei file, restano
+delle importanti differenze. La prima è che il permesso di esecuzione non
+esiste (e se specificato viene ignorato), per cui si può parlare solo di
+permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
+propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
+ed hanno lo stesso significato di quelli riportati in
+\secref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
+  simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
+  alcuni sistemi definiscono le costanti \macro{MSG\_R} (\texttt{0400}) e
+  \macro{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
+  scrittura per il proprietario, da utilizzare, con gli opportuni shift, pure
+  per il gruppo e gli altri, in Linux, visto la loro scarsa utilità, queste
+  costanti non sono definite.} e come per i file definiscono gli accessi per
+il proprietario, il suo gruppo e tutti gli altri.
+
+Quando l'oggetto viene creato i campi \var{cuid} e \var{uid} di
+\var{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono settati
+rispettivamente al valore dell'userid e del groupid effettivo del processo che
+ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
+essere cambiati, i campi \var{cuid} e \var{cgid} restano sempre gli stessi.
+
+Il controllo di accesso è effettuato a due livelli. Il primo livello è nelle
+funzioni che richiedono l'identificatore di un oggetto data la chiave. Queste
+specificano tutte un argomento \param{flag}, in tal caso quando viene
+effettuata la ricerca di una chiave, qualora \param{flag} specifichi dei
+permessi, questi vengono controllati e l'identificatore viene restituito solo
+se corrispondono a quelli dell'oggetto. Se ci sono dei permessi non presenti
+in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
+indicativa, dato che è sempre possibile specificare per \param{flag} un valore
+nullo, nel qual caso l'identificatore sarà restituito comunque.
+
+Il secondo livello di controllo è quello delle varie funzioni che accedono
+direttamente (in lettura o scrittura) all'oggetto. In tal caso lo schema dei
+controlli è simile a quello dei file, ed avviene secondo questa sequenza:
 \begin{itemize}
 \item se il processo ha i privilegi di amministatore l'accesso è sempre
   consentito. 
@@ -884,9 +1012,10 @@ dei file, ed avviene secondo questa sequenza:
 \end{itemize}
 solo se tutti i controlli elencati falliscono l'accesso è negato. Si noti che
 a differenza di quanto avviene per i permessi dei file, fallire in uno dei
-passi elencati non comporta il fallimento dell'accesso. Un'altra differenza è
-che per gli oggetti di IPC il valore di \var{umask} (si ricordi quanto esposto
-in \secref{sec:file_umask}) non ha alcun effetto.
+passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
+differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
+il valore di \var{umask} (si ricordi quanto esposto in
+\secref{sec:file_umask}) non ha alcun significato.
 
 
 \subsection{Gli identificatori ed il loro utilizzo}
@@ -894,7 +1023,7 @@ in \secref{sec:file_umask}) non ha alcun effetto.
 
 L'unico campo di \var{ipc\_perm} del quale non abbiamo ancora parlato è
 \var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
-``\textit{numero di sequenza}'', ne parliamo adesso dato che esso è
+``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
 strettamente attinente alle modalità con cui il kernel assegna gli
 identificatori degli oggetti del sistema di IPC.
 
@@ -903,7 +1032,7 @@ assegnato un numero progressivo, pari al numero di oggetti di quel tipo
 esistenti. Se il comportamente fosse sempre questo sarebbe identico a quello
 usato nell'assegnazione dei file descriptor nei processi, ed i valori degli
 identificatori tenderebbero ad essere riutilizzati spesso e restare di piccole
-dimensioni ed inferiori al numero massimo di oggetti diponibili.
+dimensioni (inferiori al numero massimo di oggetti diponibili).
 
 Questo va benissimo nel caso dei file descriptor, che sono locali ad un
 processo, ma qui il comportamento varrebbe per tutto il sistema, e per
@@ -935,14 +1064,9 @@ sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
 di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
   serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato
   dalla costante \macro{IPCMNI}, definita in \file{include/linux/ipc.h}, che
-  indica il limite massimo per il numero di oggetti di IPC, ed il cui valore è
-  32768.}  si evita così il riutilizzo degli stessi numeri, e si fa sì che
-l'identificatore assuma tutti i valori possibili.
-
-In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
-di test che si limita a creare un oggetto (specificato a riga di comando),
-stamparne il numero di identificatore e cancellarlo per un numero specificato
-di volte. 
+  indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui
+  valore è 32768.}  si evita così il riutilizzo degli stessi numeri, e si fa
+sì che l'identificatore assuma tutti i valori possibili.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -989,11 +1113,19 @@ int main(int argc, char *argv[])
   \label{fig:ipc_sysv_idtest}
 \end{figure}
 
+In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
+di test che si limita a creare un oggetto (specificato a riga di comando),
+stamparne il numero di identificatore e cancellarlo per un numero specificato
+di volte. Al solito non si è riportato il codice della gestione delle opzioni
+a riga di comando, che permette di specificare quante volte effettuare il
+ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
+
+
 La figura non riporta il codice di selezione delle opzioni, che permette di
 inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
 \var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
 stampa, cancellazione. I valori di default sono per l'uso delle code di
-messaggi e un ciclo di 10 volte. Se si lancia il comando si otterrà qualcosa
+messaggi e un ciclo di 5 volte. Se si lancia il comando si otterrà qualcosa
 del tipo:
 \begin{verbatim}
 piccardi@gont sources]$ ./ipctestid
@@ -1002,27 +1134,17 @@ Identifier Value 32768
 Identifier Value 65536 
 Identifier Value 98304 
 Identifier Value 131072 
-Identifier Value 163840 
-Identifier Value 196608 
-Identifier Value 229376 
-Identifier Value 262144 
-Identifier Value 294912 
 \end{verbatim}%$
 il che ci mostra che abbiamo un kernel della serie 2.4.x nel quale non avevamo
 ancora usato nessuna coda di messaggi. Se ripetiamo il comando otterremo
 ancora:
 \begin{verbatim}
 [piccardi@gont sources]$ ./ipctestid
-Identifier Value 327680 
-Identifier Value 360448 
-Identifier Value 393216 
-Identifier Value 425984 
-Identifier Value 458752 
-Identifier Value 491520 
-Identifier Value 524288 
-Identifier Value 557056 
-Identifier Value 589824 
-Identifier Value 622592 
+Identifier Value 163840 
+Identifier Value 196608 
+Identifier Value 229376 
+Identifier Value 262144 
+Identifier Value 294912 
 \end{verbatim}%$
 che ci mostra come il valore di \var{seq} sia in effetti una quantità
 mantenuta staticamente all'interno del sistema.
@@ -1174,7 +1296,7 @@ evitasse i principali problemi evidenziati in coda a
 
 
 \subsection{Memoria condivisa}
-\label{sec:ipc_sysv_shm}
+\label{sec:ipc_posix_shm}
 
 %%% Local Variables: 
 %%% mode: latex
index 6faf9eb..818abcb 100644 (file)
@@ -242,7 +242,7 @@ grandi linee nei seguenti punti:
 Per capire le caratteristiche di IPv6 partiamo dall'intestazione usata dal
 protocollo per gestire la trasmissione dei pacchetti; in
 \figref{fig:IP_ipv6head} è riportato il formato dell'intestazione di IPv6 da
-confrontare con quella di IPv4 in \figref{fig:IP_ipv4head}. La spiegazione del
+confrontare con quella di IPv4 in \figref{fig:IP_ipv4_head}. La spiegazione del
 significato dei vari campi delle due intestazioni è riportato rispettivamente
 in \tabref{tab:IP_ipv6field} e \tabref{tab:IP_ipv4field})
 
@@ -331,7 +331,7 @@ numero dei campi da 12 a 8.
 Abbiamo già anticipato in \secref{sec:IP_ipv6over} uno dei criteri principali
 nella progettazione di IPv6 è stato quello di ridurre al minimo il tempo di
 processamento dei pacchetti da parte dei router, un confronto con
-l'intestazione di IPv4 (vedi \figref{fig:IP_ipv4head}) mostra le seguenti
+l'intestazione di IPv4 (vedi \figref{fig:IP_ipv4_head}) mostra le seguenti
 differenze:
 
 \begin{itemize}
@@ -373,7 +373,7 @@ differenze:
   \centering
   \includegraphics[width=10cm]{img/ipv4_head}
   \caption{L'intestazione o \textit{header} di IPv4.}
-  \label{fig:IP_ipv4head}
+  \label{fig:IP_ipv4_head}
 \end{figure}
 
 \begin{table}[htb]
index f18e3ba..cb17b81 100644 (file)
@@ -70,7 +70,7 @@ macchine diverse conversano tramite lo stesso protocollo. Questo modello di
 funzionamento è stato stato standardizzato dalla \textit{International
   Standards Organization} (ISO) che ha preparato fin dal 1984 il Modello di
 Riferimento \textit{Open Systems Interconnection} (OSI), strutturato in sette
-livelli, secondo quanto riportato in \ntab.
+livelli, secondo quanto riportato in \tabref{tab:net_osilayers}.
 
 \begin{table}[htb]
   \centering
@@ -513,7 +513,7 @@ loro origini ed alle eventuali implicazioni che possono avere:
 \item La dimensione massima di un pacchetti IP è di 65535 byte, compreso
   l'header. Questo è dovuto al fatto che la dimensione è indicata da un campo
   apposito nell'header di IP che è lungo 16 bit (vedi
-  \tabref{tab:IP_ipv4head}).
+  \figref{fig:IP_ipv4_head}).
 \item La dimensione massima di un pacchetto normale di IPv6 è di 65575 byte,
   il campo apposito nell'header infatti è sempre a 16 bit, ma la dimensione
   dell'header è fissa e di 40 byte e non è compresa nel valore indicato dal
index 181b1bd..1dddefc 100644 (file)
@@ -614,7 +614,7 @@ comune dopo l'esecuzione di una \func{fork} 
 \item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigmask}) e le
   azioni installate (vedi \secref{sec:sig_gen_beha}).
 \item i segmenti di memoria condivisa agganciati al processo (vedi
-\secref{sec:ipc_shar_mem}). 
+  \secref{sec:ipc_sysv_shm}).
 \item i limiti sulle risorse (vedi \secref{sec:sys_resource_limit}).
 \item le variabili di ambiente (vedi \secref{sec:proc_environ}).
 \end{itemize*}
@@ -2428,7 +2428,7 @@ atomicamente le operazioni necessarie, occorre che quelle parti di codice in
 cui si compiono le operazioni sulle risorse condivise (le cosiddette
 \textsl{sezioni critiche}) del programma, siano opportunamente protette da
 meccanismi di sincronizzazione (torneremo su queste problematiche di questo
-tipo in \secref{sec:ipc_semaph}).
+tipo in \capref{cha:IPC}).
 
 Un caso particolare di \textit{race condition} sono poi i cosiddetti
 \textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
index 9d5c546..37aaef4 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Usage: fortune -h give all info
  *
- * $Id: FortuneClient.c,v 1.1 2002/08/18 10:34:09 piccardi Exp $
+ * $Id: FortuneClient.c,v 1.2 2002/08/19 17:34:23 piccardi Exp $
  *
  ****************************************************************/
 /* 
@@ -87,31 +87,30 @@ int main(int argc, char *argv[])
      *               Main code beginning
      * 
      * ***********************************************************/
-    snprintf(fifoname, 80, "/tmp/fortune.%d", getpid());
-    if (mkfifo(fifoname, 0622)) {
+    snprintf(fifoname, 80, "/tmp/fortune.%d", getpid());     /* compose name */
+    if (mkfifo(fifoname, 0622)) {                        /* open client fifo */
        if (errno!=EEXIST) {
            perror("Cannot create well known fifo");
            exit(-1);
        }
     }
-    fifo_server = open(fortunefilename, O_WRONLY);
+    fifo_server = open(fortunefilename, O_WRONLY);       /* open server fifo */
     if (fifo_server < 0) {
        perror("Cannot open well known fifo");
        exit(-1);
     }
     debug("%s\n", fifoname);
-    nread = write(fifo_server, fifoname, strlen(fifoname)+1);
-    close(fifo_server);
-    fifo_client = open(fifoname, O_RDONLY);
+    nread = write(fifo_server, fifoname, strlen(fifoname)+1);  /* write name */
+    close(fifo_server);                                 /* close server fifo */
+    fifo_client = open(fifoname, O_RDONLY);              /* open client fifo */
     if (fifo_client < 0) {
        perror("Cannot open well known fifo");
        exit(-1);
     }
-    nread = read(fifo_client, buffer, sizeof(buffer));
-    printf("%s", buffer);
-    close(fifo_client);
-    close(fifo_server);
-    unlink(fifoname);
+    nread = read(fifo_client, buffer, sizeof(buffer));        /* read answer */
+    printf("%s", buffer);                                   /* print fortune */
+    close(fifo_client);                                      /* close client */
+    unlink(fifoname);                                  /* remove client fifo */
 }
 /*
  * routine to print usage info and exit
index 5f10062..69e3b34 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Usage: fortuned -h give all info
  *
- * $Id: FortuneServer.c,v 1.3 2002/08/18 23:24:44 piccardi Exp $
+ * $Id: FortuneServer.c,v 1.4 2002/08/19 17:34:23 piccardi Exp $
  *
  ****************************************************************/
 /* 
 #include <stdlib.h>     /* standard library */
 #include <string.h>     /* ANSI C standard string */
 #include <errno.h>      /* errorstring */
+#include <signal.h>     /* signals */
 #include <fcntl.h>      /*  */
 
 #include "macros.h"
+#include "wrappers.h"
 
 /* Subroutines declaration */
 void usage(void);
+void HandSIGTERM(int signo);
 int FortuneParse(char *file, char **fortune, int n);
 
 /* name of well known fifo */
@@ -53,7 +56,7 @@ int main(int argc, char *argv[])
 {
 /* Variables definition */
     int i, n = 0;
-    char *fortunefilename = "/usr/share/games/fortunes/kids";
+    char *fortunefilename = "/usr/share/games/fortunes/italia";
     char **fortune;
     char line[80];
     int fifo_server, fifo_client;
@@ -94,39 +97,53 @@ int main(int argc, char *argv[])
      *               Main code beginning
      * 
      * ***********************************************************/
-    Signal(SIGTERM, HandSIGTERM);
+    if (n==0) usage();          /* if no pool depth exit printing usage info */
+    Signal(SIGTERM, HandSIGTERM);            /* set handlers for termination */
     Signal(SIGINT, HandSIGTERM);
     Signal(SIGQUIT, HandSIGTERM);
-    if (n==0) usage();          /* if no pool depth exit printing usage info */
     i = FortuneParse(fortunefilename, fortune, n);          /* parse phrases */
-    for (n=0; n<i; n++) debug("%s\n\n", fortune[n]);
+    for (n=0; n<i; n++) debug("%s%%\n", fortune[n]);
     /* 
      * Comunication section 
      */
     if (mkfifo(fifoname, 0622)) {  /* create well known fifo if does't exist */
        if (errno!=EEXIST) {
            perror("Cannot create well known fifo");
-           exit(-1);
+           exit(1);
        }
     }
+    /* open fifo two times to avoid EOF */
+    fifo_server = open(fifoname, O_RDONLY);
+    if (fifo_server < 0) {
+       perror("Cannot open read only well known fifo");
+       exit(1);
+    }
+    if (open(fifoname, O_WRONLY) < 0) {
+       perror("Cannot open write only well known fifo");
+       exit(1);
+    }
     /* Main body: loop over requests */
     while (1) {
-       fifo_server = open(fifoname, O_RDONLY);      /* open well known fifo */
-       if (fifo_server < 0) {
-           perror("Cannot open well known fifo");
-           exit(-1);
-       }
        nread = read(fifo_server, line, 79);                 /* read request */
-       line[nread] = 0;
+       if (nread < 0) {
+           perror("Read Error");
+           exit(1);
+       }
+       line[nread] = 0;                       /* terminate fifo name string */
        debug("%s %d\n", line,nread);
        n = random() % i;                             /* select random value */
        debug("fortune[%d]=%s\n", n, fortune[n]);
        fifo_client = open(line, O_WRONLY);              /* open client fifo */
+       if (fifo_client < 0) {
+           debug("Client fifo is %s\n", line);
+           perror("Cannot open");
+           exit(1);
+       }
        nread = write(fifo_client,                           /* write phrase */
                      fortune[n], strlen(fortune[n])+1);
-       close(fifo_client);                         /* close well known fifo */
-       close(fifo_server);                             /* close client fifo */
+       close(fifo_client);                             /* close client fifo */
     }
+    debug("Exiting for unknown reasons\n");
 }
 /*
  * routine to print usage info and exit
@@ -144,6 +161,7 @@ void usage(void) {
  * Signal Handler to manage termination
  */
 void HandSIGTERM(int signo) {
+    debug("Terminated by %s\n", strsignal(signo));
     unlink(fifoname);
     exit(0);
 }
index de39a47..2aa66ee 100644 (file)
@@ -26,7 +26,7 @@
  *
  * Usage: ipctestid -h give all info's
  *
- * $Id: IPCTestId.c,v 1.1 2002/08/16 22:29:38 piccardi Exp $
+ * $Id: IPCTestId.c,v 1.2 2002/08/19 17:34:23 piccardi Exp $
  *
  ****************************************************************/
 /* 
@@ -52,8 +52,8 @@ int main(int argc, char *argv[])
  * Variables definition  
  */
     int i; 
-    int n = 10;           /* default is 10 tryes */
-    char type='q';        /* default is use queues */
+    int n = 5;                                        /* default is 10 tryes */
+    char type='q';                                  /* default is use queues */
     int id;
     /*
      * Input section: decode command line parameters 
index cd22c14..868ff58 100644 (file)
@@ -14,7 +14,7 @@ FINAL = forktest errcode echo echod daytimed iterdaytimed daytime testfopen \
 fortune: FortuneClient.c
        $(CC) $^ -o $@
 
-fortuned: FortuneServer.c FortuneParse.c
+fortuned: FortuneServer.c FortuneParse.c 
        $(CC) $^ -o $@
 
 barcode: BarCode.c
@@ -77,14 +77,3 @@ clean:
        rm -f *.o
        rm -f prova*
        rm -f output*
-
-
-
-
-
-
-
-
-
-
-