%% License".
%%
\chapter{Socket TCP}
-\label{cha:elem_TCP_sock}
+\label{cha:TCP_socket}
In questo capitolo iniziamo ad approfondire la conoscenza dei socket TCP,
iniziando con una descrizione delle principali caratteristiche del
utilizzato un buffer troppo piccolo per \param{name} l'indirizzo risulterà
troncato.
-
La funzione si usa tutte le volte che si vuole avere l'indirizzo locale di un
socket; ad esempio può essere usata da un client (che usualmente non chiama
\func{bind}) per ottenere numero IP e porta locale associati al socket
capo della connessione. Ci si può chiedere a cosa serva questa funzione dato
che dal lato client l'indirizzo remoto è sempre noto quando si esegue la
\func{connect} mentre dal lato server si possono usare, come vedremo in
-\figref{fig:TCP_cunc_serv_code}, i valori di ritorno di \func{accept}.
+\figref{fig:TCP_daytime_cunc_server_code}, i valori di ritorno di
+\func{accept}.
Il fatto è che in generale quest'ultimo caso non è sempre possibile. In
particolare questo avviene quando il server, invece di gestire la connessione
l'ora locale della macchina a cui si effettua la richiesta, e che è assegnato
alla porta 13.
-In \figref{fig:TCP_cli_code} è riportata la sezione principale del codice del
-nostro client. Il sorgente completo del programma (\file{TCP_daytime.c}, che
-comprende il trattamento delle opzioni ed una funzione per stampare un
-messaggio di aiuto) è allegato alla guida nella sezione dei codici sorgente e
-può essere compilato su una qualunque macchina GNU/Linux.
+In \figref{fig:TCP_daytime_client_code} è riportata la sezione principale del
+codice del nostro client. Il sorgente completo del programma
+(\file{TCP\_daytime.c}, che comprende il trattamento delle opzioni ed una
+funzione per stampare un messaggio di aiuto) è allegato alla guida nella
+sezione dei codici sorgente e può essere compilato su una qualunque macchina
+GNU/Linux.
\begin{figure}[!htb]
\footnotesize \centering
Completata con successo la connessione il passo successivo (\texttt{\small
34--40}) è leggere la data dal socket; il protocollo prevede che il server
-invii sempre una stringa alfanumerica di 26 caratteri, nella forma giorno
-della settimana, mese, ora minuto e secondo, anno, seguita dai caratteri di
-terminazione \verb|\r\n|, cioè qualcosa del tipo:
+invii sempre una stringa alfanumerica, il formato della stringa non è
+specificato dallo standard, per cui noi useremo il formato usato dalla
+funzione \func{ctime}, seguito dai caratteri di terminazione \verb|\r\n|, cioè
+qualcosa del tipo:
\begin{verbatim}
Wed Apr 4 00:53:00 2001\r\n
\end{verbatim}
primo esempio realizzeremo un server iterativo, in grado di fornire una sola
risposta alla volta. Il codice del programma è nuovamente mostrato in
\figref{fig:TCP_daytime_iter_server_code}, il sorgente completo
-(\file{TCP_iter_daytimed.c}) è allegato insieme agli altri file degli esempi.
+(\file{TCP\_iter\_daytimed.c}) è allegato insieme agli altri file degli esempi.
\begin{figure}[!htbp]
\footnotesize \centering
\subsection{Un server \textit{daytime} concorrente}
\label{sec:TCP_daytime_cunc_server}
-Il server \texttt{daytime} dell'esempio in \secref{sec:TCP_daytime_client} è un
-tipico esempio di server iterativo, in cui viene servita una richiesta alla
-volta; in generale però, specie se il servizio è più complesso e comporta uno
-scambio di dati più sostanzioso di quello in questione, non è opportuno
-bloccare un server nel servizio di un client per volta; per questo si ricorre
-alle capacità di multitasking del sistema.
+Il server \texttt{daytime} dell'esempio in
+\secref{sec:TCP_daytime_iter_server} è un tipico esempio di server iterativo,
+in cui viene servita una richiesta alla volta; in generale però, specie se il
+servizio è più complesso e comporta uno scambio di dati più sostanzioso di
+quello in questione, non è opportuno bloccare un server nel servizio di un
+client per volta; per questo si ricorre alle capacità di multitasking del
+sistema.
Come accennato anche in \secref{sec:proc_gen} una delle modalità più comuni di
funzionamento da parte dei server è quella di usare la funzione \func{fork}
per creare, ad ogni richiesta da parte di un client, un processo figlio che si
incarichi della gestione della comunicazione. Si è allora riscritto il server
-\texttt{daytime} dell'esempio precedente in forma concorrente, inserendo anche
+\textit{daytime} dell'esempio precedente in forma concorrente, inserendo anche
una opzione per la stampa degli indirizzi delle connessioni ricevute.
-In \figref{fig:TCP_cunc_serv_code} è mostrato un estratto del codice, in cui
-si sono tralasciati il trattamento delle opzioni e le parti rimaste invariate
-rispetto al precedente esempio (cioè tutta la parte riguardante l'apertura
-passiva del socket). Al solito il sorgente completo del server, nel file
-\file{ElemDaytimeTCPCuncServ.c}, è allegato insieme ai sorgenti degli altri
-esempi.
+In \figref{fig:TCP_daytime_cunc_server_code} è mostrato un estratto del
+codice, in cui si sono tralasciati il trattamento delle opzioni e le parti
+rimaste invariate rispetto al precedente esempio (cioè tutta la parte
+riguardante l'apertura passiva del socket). Al solito il sorgente completo del
+server, nel file \file{TCP\_cunc\_daytimed.c}, è allegato insieme ai sorgenti
+degli altri esempi.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
- \includecodesample{listati/ElemDaytimeTCPCuncServ.c}
+ \includecodesample{listati/TCP_cunc_daytimed.c}
\end{minipage}
\normalsize
\caption{Esempio di codice di un server concorrente elementare per il
servizio daytime.}
- \label{fig:TCP_cunc_serv_code}
+ \label{fig:TCP_daytime_cunc_server_code}
\end{figure}
Stavolta (\texttt{\small 21--25}) la funzione \func{accept} è chiamata
complessi.
+
\section{Un esempio più completo: il servizio \textit{echo}}
\label{sec:TCP_echo_application}
le direzioni, implementando il servizio standard \textit{echo}, così come
definito dall'\href{http://www.ietf.org/rfc/rfc0862.txt}{RFC~862}.
-Si è scelto di usare questo servizio, seguendo l'esempio di \cite{UNP1},
-perché costituisce il prototipo ideale di una generica applicazione di rete in
-cui un server risponde alle richieste di un client; nel caso di una
-applicazione più complessa si potrà avere in più una elaborazione dell'input
-del client da parte del server nel fornire le risposte in uscita.
+Si è scelto, seguendo l'esempio di \cite{UNP1}, di usare questo servizio, che
+si limita a restituire in uscita quanto immesso in ingresso, perché nonostante
+la sua estrema semplicità costituisce il prototipo ideale di una generica
+applicazione di rete in cui un server risponde alle richieste di un client;
+nel caso di una applicazione più complessa si potrà avere in più una
+elaborazione dell'input del client da parte del server nel fornire le risposte
+in uscita.
-Ci limiteremo ad un esempio elementare, che usi solo le funzioni di base, ma
-prenderemo in esame, oltre al comportamento in condizioni normali, anche tutti
-i possibili scenari particolari (errori, sconnessione della rete, crash del
-client o del server durante la connessione) che possono avere luogo durante
-l'impiego di un'applicazione di rete.
+Ci limiteremo per ora ad una implementazione elementare, che usi solo le
+funzioni di base, ma prenderemo in esame, oltre al comportamento in condizioni
+normali, anche tutti i possibili scenari particolari (errori, sconnessione
+della rete, crash del client o del server durante la connessione) che possono
+avere luogo durante l'impiego di un'applicazione di rete, partendo da una
+versione primitiva che dovrà essere rimaneggiata di volta in volta per poter
+tenere conto di tutte le evenienze che si possono manifestare nella vita reale
+di un'applicazione di rete, fino ad arrivare ad un'implementazione completa.
-Partiremo da un'implementazione elementare che dovrà essere rimaneggiata di
-volta in volta per poter tenere conto di tutte le evenienze che si possono
-manifestare nella vita reale di un'applicazione di rete, fino ad arrivare ad
-un'implementazione completa.
\subsection{Il client: prima versione}
\label{sec:TCP_echo_client}
-Il codice del client è riportato in \figref{fig:TCPsimpl_client_elem}, anche
-esso ricalca la struttura del precedente client per il servizio
-\texttt{daytime} (vedi \secref{sec:TCP_daytime_client}) ma, come per il
-server, lo si è diviso in due parti, inserendo la parte relativa alle
-operazioni specifiche previste per il protocollo \textit{echo} in una funzione
-a parte.
+Il codice della prima versione client per il servizio \textit{echo} è
+riportato in \figref{fig:TCP_echo_client_1}. Esso ricalca la struttura del
+precedente client per il servizio \textit{daytime} (vedi
+\secref{sec:TCP_daytime_client}), e la prima parte (\texttt{\small 10--27}) è
+sostanzialmente identica, a parte l'uso di una porta diversa.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15.6 cm}
- \includecodesample{listati/EchoServerWrong.c}
+ \includecodesample{listati/TCP_echo_client.c}
\end{minipage}
\normalsize
\caption{Codice della prima versione del client \textit{echo}.}
- \label{fig:TCPsimpl_client_elem}
+ \label{fig:TCP_echo_client_1}
\end{figure}
-La funzione \code{main} si occupa della creazione del socket e della
-connessione (linee \texttt{\small 10--27}) secondo la stessa modalità spiegata
-in \secref{sec:TCP_daytime_client}, il client si connette sulla porta 7
-all'indirizzo specificato dalla linea di comando (a cui si è aggiunta una
-elementare gestione delle opzioni non riportata in figura).
-
-Completata la connessione, al ritorno di \func{connect}, la funzione
-\code{ClientEcho}, riportata in \figref{fig:TCPsimpl_client_echo_sub}, si
-preoccupa di gestire la comunicazione, leggendo una riga alla volta dallo
-\file{stdin}, scrivendola sul socket e ristampando su \file{stdout} quanto
-ricevuto in risposta dal server.
+Al solito si è tralasciata la sezione relativa alla gestione delle opzioni a
+riga di comando; una volta dichiarate le variabili, si prosegue
+(\texttt{\small 10--13}) con della creazione del socket, la preparazione
+(\texttt{\small 14--17}) la struttura per l'indirizzo, con la relativa
+conversione (\texttt{\small 18--22}) di quanto specificato a riga di comando.
+
+A questo punto (\texttt{\small 23--27}) si può eseguire la connessione al
+server secondo la stessa modalità usata in \secref{sec:TCP_daytime_client}.
+Completata la connessione, al ritorno di \func{connect}, si usa la funzione
+\code{ClientEcho}, il cui codice è riportato in
+\figref{fig:TCPsimpl_client_echo_sub}. Questa si preoccupa di gestire tutta la
+comunicazione, leggendo una riga alla volta dallo standard input \file{stdin},
+scrivendola sul socket e ristampando su \file{stdout} quanto ricevuto in
+risposta dal server. Al ritorno dalla funzione (\texttt{\small 30--31}) anche
+il programma termina.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:TCPsimpl_client_echo_sub}
\end{figure}
-La funzione utilizza due buffer per gestire i dati inviati e letti sul socket
-(\texttt{\small 3}). La comunicazione viene gestita all'interno di un ciclo
-(linee \texttt{\small 5--10}), i dati da inviare sulla connessione vengono
-presi dallo \file{stdin} usando la funzione \func{fgets} che legge una
-linea di testo (terminata da un \texttt{CR} e fino al massimo di
-\const{MAXLINE} caratteri) e la salva sul buffer di invio, la funzione
-\func{FullWrite} (\texttt{\small 3}) scrive detti dati sul socket (gestendo
-l'invio multiplo qualora una singola \func{write} non basti, come spiegato
-in \secref{sec:sock_io_behav}).
+La funzione \code{ClientEcho} utilizza due buffer (\texttt{\small 3}) per
+gestire i dati inviati e letti sul socket. La comunicazione viene gestita
+all'interno di un ciclo (\texttt{\small 5--10}), i dati da inviare sulla
+connessione vengono presi dallo \file{stdin} usando la funzione \func{fgets},
+trattata in \secref{sec:file_line_io}, che legge una linea di testo (terminata
+da un \texttt{CR} e fino al massimo di \const{MAXLINE} caratteri) e la salva
+sul buffer di invio, la funzione \func{FullWrite}, già vista in
+\figref{fig:sock_FullWrite_code}, scrive (\texttt{\small 6}) i dati sul socket
+(gestendo l'invio multiplo qualora una singola \func{write} non basti, come
+spiegato in \secref{sec:sock_io_behav}).
-I dati che vengono riletti indietro con una \func{FullRead} sul buffer di
-ricezione e viene inserita la terminazione della stringa (\texttt{\small
- 7--8}) e per poter usare la funzione \func{fputs} per scriverli su
-\file{stdout}.
+I dati vengono riletti indietro (\texttt{\small 7}) con una \func{FullRead}
+sul buffer di ricezione e viene inserita (\texttt{\small 8}) la terminazione
+della stringa e per poter usare (\texttt{\small 9}) la funzione \func{fputs}
+per scriverli su \file{stdout}.
-Un end of file inviato su \file{stdin} causa il ritorno di \func{fgets}
-con un puntatore nullo e l'uscita dal ciclo, al che la subroutine ritorna ed
-il client esce.
+Un end-of-file inviato su \file{stdin} (ad esempio con la pressione di
+\texttt{C-d}) causa il ritorno di \func{fgets} con un puntatore nullo e la
+conseguente uscita dal ciclo, al che la subroutine ritorna ed il client esce.
-\subsection{La struttura del server}
+\subsection{Il server: prima versione}
\label{sec:TCPsimp_server_main}
Il servizio \textit{echo} è uno dei servizi standard solitamente provvisti
La struttura di questa prima versione del server è sostanzialmente identica a
quella dell'esempio citato, ed ad esso si applicano le considerazioni fatte in
\secref{sec:TCP_daytime_cunc_server}. Le uniche differenze rispetto
-all'esempio in \figref{fig:TCP_daytime_iter_server_code} sono che in questo
+all'esempio in \figref{fig:TCP_daytime_cunc_server_code} sono che in questo
caso per il socket in ascolto viene usata la porta 7 e che tutta la gestione
della comunicazione è delegata alla funzione \code{ServEcho}.
% Per ogni connessione viene creato un
int ComputeValues(struct dirent * direntry)
{
struct stat data;
- stat(direntry->d_name, &data); /* get stat data */
+ stat(direntry->d_name, &data); /* get stat data */
shmptr->tot_size += data.st_size;
shmptr->tot_files++;
if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
{
int i, pause = 10;
...
- if ((argc - optind) != 1) { /* There must be remaing parameters */
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
- if (chdir(argv[1])) { /* chdir to be sure dir exist */
+ if (chdir(argv[1])) { /* chdir to be sure dir exist */
perror("Cannot find directory to monitor");
}
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
Signal(SIGINT, HandSIGTERM);
Signal(SIGQUIT, HandSIGTERM);
- key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
- shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */
if (!shmptr) {
perror("Cannot create shared memory");
exit(1);
}
- if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
+ if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
perror("Cannot create mutex");
exit(1);
}
/* main loop, monitor directory properties each 10 sec */
- daemon(1, 0); /* demonize process, staying in monitored dir */
+ daemon(1, 0); /* demonize process, staying in monitored dir */
while (1) {
- MutexLock(mutex); /* lock shared memory */
- memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
- DirScan(argv[1], ComputeValues); /* execute scan */
- MutexUnlock(mutex); /* unlock shared memory */
- sleep(pause); /* sleep until next watch */
+ MutexLock(mutex); /* lock shared memory */
+ memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
+ DirScan(argv[1], ComputeValues); /* execute scan */
+ MutexUnlock(mutex); /* unlock shared memory */
+ sleep(pause); /* sleep until next watch */
}
}
DIR * dir;
struct dirent *direntry;
- if ( (dir = opendir(dirname)) == NULL) { /* oper directory */
- printf("Opening %s\n", dirname); /* on error print messages */
- perror("Cannot open directory"); /* and then return */
+ if ( (dir = opendir(dirname)) == NULL) { /* open directory */
+ printf("Opening %s\n", dirname); /* on error print messages */
+ perror("Cannot open directory"); /* and then return */
return -1;
}
- fd = dirfd(dir); /* get file descriptor */
- fchdir(fd); /* change directory */
+ fd = dirfd(dir); /* get file descriptor */
+ fchdir(fd); /* change directory */
/* loop on directory entries */
- while ( (direntry = readdir(dir)) != NULL) { /* read entry */
- if (compute(direntry)) { /* execute function on it */
- return -1; /* on error return */
+ while ( (direntry = readdir(dir)) != NULL) { /* read entry */
+ if (compute(direntry)) { /* execute function on it */
+ return -1; /* on error return */
}
}
closedir(dir);
+++ /dev/null
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int sock_fd, i;
- struct sockaddr_in serv_add;
- ...
- /* create socket */
- if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- return -1;
- }
- /* initialize address */
- memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(7); /* echo port is 7 */
- /* build address using inet_pton */
- if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
- perror("Address creation error");
- return -1;
- }
- /* extablish connection */
- if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("Connection error");
- return -1;
- }
- /* read daytime from server */
- ClientEcho(stdin, sock_fd);
- /* normal exit */
- return 0;
-}
+++ /dev/null
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utililites */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-
-int main(int argc, char *argv[])
-{
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add, client;
- char buffer[MAXLINE];
- socklen_t len;
- time_t timeval;
- pid_t pid;
- int logging=0;
- ...
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
- <0 ) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd);
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- if (logging) {
- inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
- printf("Request from host %s, port %d\n", buffer,
- ntohs(client.sin_port));
- }
- close(conn_fd);
- exit(0);
- } else { /* parent */
- close(conn_fd);
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
+++ /dev/null
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utilities */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-#define MAXLINE 80
-#define BACKLOG 10
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add;
- char buffer[MAXLINE];
- time_t timeval;
- ...
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
- perror("accept error");
- exit(-1);
- }
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- close(conn_fd);
- }
- /* normal exit */
- exit(0);
-}
int main(int argc, char *argv[])
{
- int type = F_UNLCK; /* lock type: default to unlock (invalid) */
- off_t start = 0; /* start of the locked region: default to 0 */
- off_t len = 0; /* length of the locked region: default to 0 */
- int fd, res, i; /* internal variables */
- int bsd = 0; /* semantic type: default to POSIX */
- int cmd = F_SETLK; /* lock command: default to non-blocking */
- struct flock lock; /* file lock structure */
+ int type = F_UNLCK; /* lock type: default to unlock (invalid) */
+ off_t start = 0; /* start of the locked region: default to 0 */
+ off_t len = 0; /* length of the locked region: default to 0 */
+ int fd, res, i; /* internal variables */
+ int bsd = 0; /* semantic type: default to POSIX */
+ int cmd = F_SETLK; /* lock command: default to non-blocking */
+ struct flock lock; /* file lock structure */
...
- if ((argc - optind) != 1) { /* There must be remaing parameters */
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
- if (type == F_UNLCK) { /* There must be a -w or -r option set */
+ if (type == F_UNLCK) { /* There must be a -w or -r option set */
printf("You should set a read or a write lock\n");
usage();
}
- fd = open(argv[optind], O_RDWR); /* open the file to be locked */
- if (fd < 0) { /* on error exit */
+ fd = open(argv[optind], O_RDWR); /* open the file to be locked */
+ if (fd < 0) { /* on error exit */
perror("Wrong filename");
exit(1);
}
/* do lock */
- if (bsd) { /* if BSD locking */
+ if (bsd) { /* if BSD locking */
/* rewrite cmd for suitables flock operation values */
- if (cmd == F_SETLKW) { /* if no-blocking */
- cmd = LOCK_NB; /* set the value for flock operation */
- } else { /* else */
- cmd = 0; /* default is null */
+ if (cmd == F_SETLKW) { /* if no-blocking */
+ cmd = LOCK_NB; /* set the value for flock operation */
+ } else { /* else */
+ cmd = 0; /* default is null */
}
- if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
- if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
- res = flock(fd, cmd); /* esecute lock */
- } else { /* if POSIX locking */
+ if (type == F_RDLCK) cmd |= LOCK_SH; /* set for shared lock */
+ if (type == F_WRLCK) cmd |= LOCK_EX; /* set for exclusive lock */
+ res = flock(fd, cmd); /* esecute lock */
+ } else { /* if POSIX locking */
/* setting flock structure */
- lock.l_type = type; /* set type: read or write */
+ lock.l_type = type; /* set type: read or write */
lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = start; /* set the start of the locked region */
- lock.l_len = len; /* set the length of the locked region */
- res = fcntl(fd, cmd, &lock); /* do lock */
+ lock.l_start = start; /* set the start of the locked region */
+ lock.l_len = len; /* set the length of the locked region */
+ res = fcntl(fd, cmd, &lock); /* do lock */
}
/* check lock results */
- if (res) { /* on error exit */
+ if (res) { /* on error exit */
perror("Failed lock");
exit(1);
- } else { /* else write message */
+ } else { /* else write message */
printf("Lock acquired\n");
}
- pause(); /* stop the process, use a signal to exit */
+ pause(); /* stop the process, use a signal to exit */
return 0;
}
int nread;
char buffer[PIPE_BUF];
...
- snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */
- if (mkfifo(fifoname, 0622)) { /* open client fifo */
+ 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 */
+ 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 */
+ 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 */
+ 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 */
}
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 */
+ 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 */
- if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
if (errno!=EEXIST) {
perror("Cannot create well known fifo");
exit(1);
}
/* Main body: loop over requests */
while (1) {
- nread = read(fifo_server, line, 79); /* read request */
+ nread = read(fifo_server, line, 79); /* read request */
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 */
+ 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 */
+ nread = write(fifo_client, /* write phrase */
fortune[n], strlen(fortune[n])+1);
- close(fifo_client); /* close client fifo */
+ close(fifo_client); /* close client fifo */
}
}
#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h> /* unix standard functions */
+#include <unistd.h> /* Unix standard functions */
/*
* Function LockFile:
*/
exit(1);
}
/* Main body: do request and write result */
- msg_read.mtype = 1; /* type for request is always 1 */
- msg_read.pid = getpid(); /* use pid for communications */
+ msg_read.mtype = 1; /* type for request is always 1 */
+ msg_read.pid = getpid(); /* use pid for communications */
size = sizeof(msg_read.pid);
- msgsnd(msgid, &msg_read, size, 0); /* send request message */
+ msgsnd(msgid, &msg_read, size, 0); /* send request message */
msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR);
printf("%s", msg_write.mtext);
}
-int msgid; /* Message queue identifier */
+int msgid; /* Message queue identifier */
int main(int argc, char *argv[])
{
/* Variables definition */
int i, n = 0;
- char **fortune; /* array of fortune message string */
- char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */
- struct msgbuf_read { /* message struct to read request from clients */
- long mtype; /* message type, must be 1 */
- long pid; /* message data, must be the pid of the client */
+ char **fortune; /* array of fortune message string */
+ char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */
+ struct msgbuf_read { /* message struct to read request from clients */
+ long mtype; /* message type, must be 1 */
+ long pid; /* message data, must be the pid of the client */
} msg_read;
- struct msgbuf_write { /* message struct to write result to clients */
- long mtype; /* message type, will be the pid of the client*/
- char mtext[MSGMAX]; /* message data, will be the fortune */
+ struct msgbuf_write { /* message struct to write result to clients */
+ long mtype; /* message type, will be the pid of the client*/
+ char mtext[MSGMAX]; /* message data, will be the fortune */
} msg_write;
- key_t key; /* Message queue key */
- int size; /* message size */
+ key_t key; /* Message queue key */
+ int size; /* message size */
...
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ 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 */
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
/* Create the queue */
key = ftok("./MQFortuneServer.c", 1);
msgid = msgget(key, IPC_CREAT|0666);
daemon(0, 0);
while (1) {
msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR);
- n = random() % i; /* select random value */
+ n = random() % i; /* select random value */
strncpy(msg_write.mtext, fortune[n], MSGMAX);
size = min(strlen(fortune[n])+1, MSGMAX);
- msg_write.mtype=msg_read.pid; /* use request pid as type */
+ msg_write.mtype=msg_read.pid; /* use request pid as type */
msgsnd(msgid, &msg_write, size, 0);
}
}
* Signal Handler to manage termination
*/
void HandSIGTERM(int signo) {
- msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
+ msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
exit(0);
}
int flag;
/* first open the object, creating it if not existent */
flag = O_CREAT|O_EXCL|O_RDWR;
- fd = shm_open(shm_name, flag, perm); /* get object file descriptor */
+ fd = shm_open(shm_name, flag, perm); /* get object file descriptor */
if (fd < 0) {
return NULL;
}
if (shm_ptr == MAP_FAILED) {
return NULL;
}
- memset((void *) shm_ptr, fill, shm_size); /* fill segment */
+ memset((void *) shm_ptr, fill, shm_size); /* fill segment */
return shm_ptr;
}
/* Function FindShm: Find a POSIX shared memory segment */
void * FindShm(char * shm_name, off_t shm_size)
{
void * shm_ptr;
- int fd; /* ID of the IPC shared memory segment */
+ int fd; /* ID of the IPC shared memory segment */
/* find shared memory ID */
if ((fd = shm_open(shm_name, O_RDWR|O_EXCL, 0)) < 0) {
return NULL;
/* Function MutexCreate: create a mutex/semaphore */
int MutexCreate(key_t ipc_key)
{
- const union semun semunion={1}; /* semaphore union structure */
+ const union semun semunion={1}; /* semaphore union structure */
int sem_id, ret;
- sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
- if (sem_id == -1) { /* if error return code */
+ sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
+ if (sem_id == -1) { /* if error return code */
return sem_id;
}
- ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
+ ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
if (ret == -1) {
return ret;
}
return semctl(sem_id, 0, GETVAL);
}
/* Define sembuf structures to lock and unlock the semaphore */
-struct sembuf sem_lock={ /* to lock semaphore */
- 0, /* semaphore number (only one so 0) */
- -1, /* operation (-1 to use resource) */
- SEM_UNDO}; /* flag (set for undo at exit) */
-struct sembuf sem_ulock={ /* to unlock semaphore */
- 0, /* semaphore number (only one so 0) */
- 1, /* operation (1 to release resource) */
- SEM_UNDO}; /* flag (in this case 0) */
+struct sembuf sem_lock={ /* to lock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ -1, /* operation (-1 to use resource) */
+ SEM_UNDO}; /* flag (set for undo at exit) */
+struct sembuf sem_ulock={ /* to unlock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ 1, /* operation (1 to release resource) */
+ SEM_UNDO}; /* flag (in this case 0) */
/* Function MutexLock: to lock a mutex/semaphore */
int MutexLock(int sem_id)
{
/* Function LockMutex: lock mutex using file locking. */
int LockMutex(int fd)
{
- struct flock lock; /* file lock structure */
+ struct flock lock; /* file lock structure */
/* set flock structure */
- lock.l_type = F_WRLCK; /* set type: read or write */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
+ lock.l_type = F_WRLCK; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
/* do locking */
return fcntl(fd, F_SETLKW, &lock);
}
/* Function UnlockMutex: unlock a file. */
int UnlockMutex(int fd)
{
- struct flock lock; /* file lock structure */
+ struct flock lock; /* file lock structure */
/* set flock structure */
- lock.l_type = F_UNLCK; /* set type: unlock */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
+ lock.l_type = F_UNLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
/* do locking */
return fcntl(fd, F_SETLK, &lock);
}
int ReadMutex(int fd)
{
int res;
- struct flock lock; /* file lock structure */
+ struct flock lock; /* file lock structure */
/* set flock structure */
- lock.l_type = F_WRLCK; /* set type: unlock */
- lock.l_whence = SEEK_SET; /* start from the beginning of the file */
- lock.l_start = 0; /* set the start of the locked region */
- lock.l_len = 0; /* set the length of the locked region */
+ lock.l_type = F_WRLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
/* do locking */
if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
return res;
key_t key;
...
/* create needed IPC objects */
- key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
- if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */
perror("Cannot find shared memory");
exit(1);
}
- if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
+ if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
perror("Cannot find mutex");
exit(1);
}
/* main loop */
- MutexLock(mutex); /* lock shared memory */
+ MutexLock(mutex); /* lock shared memory */
printf("Ci sono %d file dati\n", shmptr->tot_regular);
printf("Ci sono %d directory\n", shmptr->tot_dir);
printf("Ci sono %d link\n", shmptr->tot_link);
printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
printf("Totale %d file, per %d byte\n",
shmptr->tot_files, shmptr->tot_size);
- MutexUnlock(mutex); /* unlock shared memory */
+ MutexUnlock(mutex); /* unlock shared memory */
}
void * ShmCreate(key_t ipc_key, int shm_size, int perm, int fill)
{
void * shm_ptr;
- int shm_id; /* ID of the IPC shared memory segment */
- shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */
+ int shm_id; /* ID of the IPC shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */
if (shm_id < 0) {
return NULL;
}
- shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
if (shm_ptr < 0) {
return NULL;
}
- memset((void *)shm_ptr, fill, shm_size); /* fill segment */
+ memset((void *)shm_ptr, fill, shm_size); /* fill segment */
return shm_ptr;
}
/* Function ShmFind: Find a SysV shared memory segment */
void * ShmFind(key_t ipc_key, int shm_size)
{
void * shm_ptr;
- int shm_id; /* ID of the SysV shared memory segment */
- shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */
+ int shm_id; /* ID of the SysV shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */
if (shm_id < 0) {
return NULL;
}
- shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
if (shm_ptr < 0) {
return NULL;
}
/* Function ShmRemove: Schedule removal for a SysV shared memory segment */
int ShmRemove(key_t ipc_key, void * shm_ptr)
{
- int shm_id; /* ID of the SysV shared memory segment */
+ int shm_id; /* ID of the SysV shared memory segment */
/* first detach segment */
if (shmdt(shm_ptr) < 0) {
return -1;
}
/* schedule segment removal */
- shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */
+ shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */
if (shm_id < 0) {
if (errno == EIDRM) return 0;
return -1;
}
- if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */
+ if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */
if (errno == EIDRM) return 0;
return -1;
}
struct sigaction new_handl, old_handl;
new_handl.sa_handler = func;
/* clear signal mask: no signal blocked during execution of func */
- if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */
+ if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */
return SIG_ERR;
}
- new_handl.sa_flags=0; /* init to 0 all flags */
+ new_handl.sa_flags=0; /* init to 0 all flags */
/* change action for signo signal */
if (sigaction(signo, &new_handl, &old_handl)){
return SIG_ERR;
--- /dev/null
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utililites */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+#include <time.h>
+
+int main(int argc, char *argv[])
+{
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add, client;
+ char buffer[MAXLINE];
+ socklen_t len;
+ time_t timeval;
+ pid_t pid;
+ int logging=0;
+ ...
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
+ <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd);
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ if (logging) {
+ inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+ printf("Request from host %s, port %d\n", buffer,
+ ntohs(client.sin_port));
+ }
+ close(conn_fd);
+ exit(0);
+ } else { /* parent */
+ close(conn_fd);
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
--- /dev/null
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int sock_fd, i;
+ struct sockaddr_in serv_add;
+ ...
+ /* create socket */
+ if ( (sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ return -1;
+ }
+ /* initialize address */
+ memset((void *) &serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(7); /* echo port is 7 */
+ /* build address using inet_pton */
+ if ( (inet_pton(AF_INET, argv[optind], &serv_add.sin_addr)) <= 0) {
+ perror("Address creation error");
+ return -1;
+ }
+ /* extablish connection */
+ if (connect(sock_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("Connection error");
+ return -1;
+ }
+ /* read daytime from server */
+ ClientEcho(stdin, sock_fd);
+ /* normal exit */
+ return 0;
+}
\label{sec:ip_protocol}
L'attuale \textit{Internet Protocol} (IPv4) viene standardizzato nel 1981
-dall'RFC~719; esso nasce per disaccoppiare le applicazioni della struttura
-hardware delle reti di trasmissione, e creare una interfaccia di trasmissione
-dei dati indipendente dal sottostante substrato di rete, che può essere
-realizzato con le tecnologie più disparate (Ethernet, Token Ring, FDDI, etc.).
+dall'\href{http://www.ietf.org/rfc/rfc0719.txt}{RFC~719}; esso nasce per
+disaccoppiare le applicazioni della struttura hardware delle reti di
+trasmissione, e creare una interfaccia di trasmissione dei dati indipendente
+dal sottostante substrato di rete, che può essere realizzato con le tecnologie
+più disparate (Ethernet, Token Ring, FDDI, etc.).
\subsection{Introduzione}
Per questo motivo si iniziò a progettare una nuova versione del protocollo
L'attuale Internet Protocol (IPv4) viene standardizzato nel 1981
-dall'RFC~719; esso nasce per disaccoppiare le applicazioni della struttura
-hardware delle reti di trasmissione, e creare una interfaccia di trasmissione
-dei dati indipendente dal sottostante substrato di rete, che può essere
-realizzato con le tecnologie più disparate (Ethernet, Token Ring, FDDI,
-etc.).
+dall'\href{http://www.ietf.org/rfc/rfc0719.txt}{RFC~719}; esso nasce per
+disaccoppiare le applicazioni della struttura hardware delle reti di
+trasmissione, e creare una interfaccia di trasmissione dei dati indipendente
+dal sottostante substrato di rete, che può essere realizzato con le tecnologie
+più disparate (Ethernet, Token Ring, FDDI, etc.).
\subsection{I motivi della transizione}
\label{sec:IP_ipv6_unicast}
Gli indirizzi \textit{provider-based} sono gli indirizzi usati per le
-comunicazioni globali, questi sono definiti nell'RFC 2073 e sono gli
+comunicazioni globali, questi sono definiti
+nell'\href{http://www.ietf.org/rfc/rfc2073.txt}{RFC~2073} e sono gli
equivalenti degli attuali indirizzi delle classi da A a C.
L'autorità che presiede all'allocazione di questi indirizzi è la IANA; per
\textbf{Uso}& \textbf{Indirizzi riservati} & \textbf{Definizione}\\
\hline
\hline
- all-nodes & \texttt{FFxx:0:0:0:0:0:0:1} & RFC 1970\\
- all-routers & \texttt{FFxx:0:0:0:0:0:0:2} & RFC 1970\\
- all-rip-routers & \texttt{FFxx:0:0:0:0:0:0:9} & RFC 2080\\
- all-cbt-routers & \texttt{FFxx:0:0:0:0:0:0:10} &\\
- reserved & \texttt{FFxx:0:0:0:0:0:1:0} & IANA \\
- link-name & \texttt{FFxx:0:0:0:0:0:1:1} & \\
- all-dhcp-agents & \texttt{FFxx:0:0:0:0:0:1:2} & \\
- all-dhcp-servers & \texttt{FFxx:0:0:0:0:0:1:3} & \\
- all-dhcp-relays & \texttt{FFxx:0:0:0:0:0:1:4} & \\
- solicited-nodes & \texttt{FFxx:0:0:0:0:1:0:0} & RFC 1970\\
+ all-nodes & \texttt{FFxx:0:0:0:0:0:0:1} &
+ \href{http://www.ietf.org/rfc/rfc1970.txt}{RFC~1970} \\
+ all-routers & \texttt{FFxx:0:0:0:0:0:0:2} &
+ \href{http://www.ietf.org/rfc/rfc1970.txt}{RFC~1970} \\
+ all-rip-routers & \texttt{FFxx:0:0:0:0:0:0:9} &
+ \href{http://www.ietf.org/rfc/rfc2080.txt}{RFC~2080} \\
+ all-cbt-routers & \texttt{FFxx:0:0:0:0:0:0:10} & \\
+ reserved & \texttt{FFxx:0:0:0:0:0:1:0} & IANA \\
+ link-name & \texttt{FFxx:0:0:0:0:0:1:1} & \\
+ all-dhcp-agents & \texttt{FFxx:0:0:0:0:0:1:2} & \\
+ all-dhcp-servers& \texttt{FFxx:0:0:0:0:0:1:3} & \\
+ all-dhcp-relays & \texttt{FFxx:0:0:0:0:0:1:4} & \\
+ solicited-nodes & \texttt{FFxx:0:0:0:0:1:0:0} &
+ \href{http://www.ietf.org/rfc/rfc1970.txt}{RFC~1970} \\
\hline
\end{tabular}
\caption{Gruppi multicast predefiniti.}
vuole frammentare un pacchetto, ed è riprocessato automaticamente alla
destinazione che riassembla i frammenti.
\item \textbf{Authentication} gestisce l'autenticazione e il controllo di
- integrità dei pacchetti; è documentato dall'RFC 162.
+ integrità dei pacchetti; è documentato
+ dall'\href{http://www.ietf.org/rfc/rfc1826.txt}{RFC~1826}.
\item \textbf{Encapsulation} serve a gestire la segretezza del contenuto
- trasmesso; è documentato dall'RFC 1827.
+ trasmesso; è documentato
+ dall'\href{http://www.ietf.org/rfc/rfc1827.txt}{RFC~1827}.
\end{itemize}
La presenza di opzioni è rilevata dal valore del campo \textit{next header}
IPv6 è stato progettata la possibilità di intervenire al livello di rete (il
terzo) prevedendo due apposite estensioni che possono essere usate per fornire
livelli di sicurezza a seconda degli utenti. La codifica generale di questa
-architettura è riportata nell'RFC 2401.
+architettura è riportata
+nell'\href{http://www.ietf.org/rfc/rfc2401.txt}{RFC~2401}.
Il meccanismo in sostanza si basa su due estensioni:
\begin{itemize}
Quando si parla di IP ci si riferisce in genere alla versione attualmente in
uso che è la versione 4 (e viene pertanto chiamato IPv4). Questa versione
-venne standardizzata nel 1981 dall'RFC~719.
+venne standardizzata nel 1981
+dall'\href{http://www.ietf.org/rfc/rfc0719.txt}{RFC~719}.
Internet Protocol nasce per disaccoppiare le applicazioni della struttura
hardware delle reti di trasmissione, e creare una interfaccia di trasmissione
\label{sec:net_udp}
UDP è un protocollo di trasporto molto semplice, la sua descrizione completa è
-contenuta dell'RFC~768, ma in sostanza esso è una semplice interfaccia a IP
-dal livello di trasporto. Quando un'applicazione usa UDP essa scrive un
-pacchetto di dati (il cosiddetto \textit{datagram} che da il nome al
-protocollo) su un socket\index{socket}, al pacchetto viene aggiunto un header
-molto semplice (per una descrizione più accurata vedi \secref{sec:xxx_udp}), e
-poi viene passato al livello superiore (IPv4 o IPv6 che sia) che lo spedisce
-verso la destinazione. Dato che né IPv4 né IPv6 garantiscono l'affidabilità
-niente assicura che il pacchetto arrivi a destinazione, né che più pacchetti
-arrivino nello stesso ordine in cui sono stati spediti.
+contenuta dell'\href{http://www.ietf.org/rfc/rfc0768.txt}{RFC~768}, ma in
+sostanza esso è una semplice interfaccia a IP dal livello di trasporto. Quando
+un'applicazione usa UDP essa scrive un pacchetto di dati (il cosiddetto
+\textit{datagram} che da il nome al protocollo) su un socket\index{socket}, al
+pacchetto viene aggiunto un header molto semplice (per una descrizione più
+accurata vedi \secref{sec:xxx_udp}), e poi viene passato al livello superiore
+(IPv4 o IPv6 che sia) che lo spedisce verso la destinazione. Dato che né IPv4
+né IPv6 garantiscono l'affidabilità niente assicura che il pacchetto arrivi a
+destinazione, né che più pacchetti arrivino nello stesso ordine in cui sono
+stati spediti.
Pertanto il problema principale che si affronta quando si usa UDP è la
mancanza di affidabilità, se si vuole essere sicuri che i pacchetti arrivino a
\subsection{Transport Control Protocol (TCP)}
\label{sec:net_tcp}
-Il TCP è un protocollo molto complesso, definito nell'RFC~739 e completamente
+Il TCP è un protocollo molto complesso, definito
+nell'\href{http://www.ietf.org/rfc/rfc0739.txt}{RFC~739} e completamente
diverso da UDP; alla base della sua progettazione infatti non stanno
semplicità e velocità, ma la ricerca della massima affidabilità possibile
nella trasmissione dei dati.
\textit{path MTU discovery} che permette di determinare il \textit{path MTU}
fra due stazioni; per la realizzazione del procedimento si usa il flag DF di
IPv4 e il comportamento normale di IPv6 inviando delle opportune serie di
-pacchetti (per i dettagli vedere l'RFC~1191 per IPv4 e l'RFC~1981 per IPv6)
-fintanto che non si hanno più errori.
+pacchetti (per i dettagli vedere
+l'\href{http://www.ietf.org/rfc/rfc1191.txt}{RFC~1191} per IPv4 e
+l'\href{http://www.ietf.org/rfc/rfc1981.txt}{RFC~1981} per IPv6) fintanto che
+non si hanno più errori.
Il TCP usa sempre questo meccanismo, che per le implementazioni di IPv4 è
opzionale, mentre diventa obbligatorio per IPv6. Per IPv6 infatti, non
+++ /dev/null
-/* ElemDaytimeTCPCuncServ.c
- *
- * Copyright (C) 2001 Simone Piccardi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/****************************************************************
- *
- * Program ElemDaytimeTCPCuncServ.c
- * Elementary TCP cuncurrent server for daytime service (port 13)
- *
- * Author: Simone Piccardi
- * May. 2001
- *
- * Usage: daytimed -h give all info
- *
- * $Id: ElemDaytimeTCPCuncServ.c,v 1.2 2001/09/09 17:39:15 piccardi Exp $
- *
- ****************************************************************/
-/*
- * Include needed headers
- */
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utiliites */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-
-#define MAXLINE 80
-#define BACKLOG 10
-/* Program begin */
-void usage(void);
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add, client;
- char buffer[MAXLINE];
- socklen_t len;
- time_t timeval;
- pid_t pid;
- int logging=0;
- /*
- * Input section: decode parameters passed in the calling
- * Use getopt function
- */
- opterr = 0; /* don't want writing to stderr */
- while ( (i = getopt(argc, argv, "hv")) != -1) {
- switch (i) {
- /*
- * Handling options
- */
- case 'h':
- printf("Wrong -h option use\n");
- usage();
- return(0);
- break;
- case '?': /* unrecognized options */
- printf("Unrecognized options -%c\n",optopt);
- usage();
- return(0);
- break;
- case 'v':
- logging = 1;
- break;
- default: /* should not reached */
- usage();
- return(0);
- }
- }
- /* ***********************************************************
- *
- * Options processing completed
- *
- * Main code beginning
- *
- * ***********************************************************/
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
- <0 ) {
- perror("accept error");
- exit(-1);
- }
- /* fork to handle connection */
- if ( (pid = fork()) < 0 ){
- perror("fork error");
- exit(-1);
- }
- if (pid == 0) { /* child */
- close(list_fd);
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- if (logging) {
- inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
- printf("Request from host %s, port %d\n", buffer,
- ntohs(client.sin_port));
- }
- close(conn_fd);
- exit(0);
- } else { /* parent */
- close(conn_fd);
- }
- }
- /* normal exit, never reached */
- exit(0);
-}
-/*
- * routine to print usage info and exit
- */
-void usage(void) {
- printf("Simple daytime server\n");
- printf("Usage:\n");
- printf(" daytimed [-hv] \n");
- printf(" -h print this help\n");
- printf(" -v print request source on stdout\n");
- exit(1);
-}
-
+++ /dev/null
-/* ElemDaytimeTCPServer.c
- *
- * Copyright (C) 2001 Simone Piccardi
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/****************************************************************
- *
- * Program daytimed:
- * Elementary TCP server for daytime service (port 13)
- *
- * Author: Simone Piccardi
- * Apr. 2001
- *
- * Usage: daytimed -h give all info
- *
- * $Id: ElemDaytimeTCPServer.c,v 1.3 2001/09/09 22:45:34 piccardi Exp $
- *
- ****************************************************************/
-/*
- * Include needed headers
- */
-#include <sys/types.h> /* predefined types */
-#include <unistd.h> /* include unix standard library */
-#include <arpa/inet.h> /* IP addresses conversion utiliites */
-#include <sys/socket.h> /* socket library */
-#include <stdio.h> /* include standard I/O library */
-#include <time.h>
-
-#define MAXLINE 80
-#define BACKLOG 10
-/* Program begin */
-void usage(void);
-int main(int argc, char *argv[])
-{
-/*
- * Variables definition
- */
- int list_fd, conn_fd;
- int i;
- struct sockaddr_in serv_add;
- char buffer[MAXLINE];
- time_t timeval;
- /*
- * Input section: decode parameters passed in the calling
- * Use getopt function
- */
- opterr = 0; /* don't want writing to stderr */
- while ( (i = getopt(argc, argv, "h")) != -1) {
- switch (i) {
- /*
- * Handling options
- */
- case 'h':
- printf("Wrong -h option use\n");
- usage();
- return(0);
- break;
- case '?': /* unrecognized options */
- printf("Unrecognized options -%c\n",optopt);
- usage();
- default: /* should not reached */
- usage();
- }
- }
- /* ***********************************************************
- *
- * Options processing completed
- *
- * Main code beginning
- *
- * ***********************************************************/
- /* create socket */
- if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- perror("Socket creation error");
- exit(-1);
- }
- /* initialize address */
- memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
- serv_add.sin_family = AF_INET; /* address type is INET */
- serv_add.sin_port = htons(13); /* daytime port is 13 */
- serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
- /* bind socket */
- if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
- perror("bind error");
- exit(-1);
- }
- /* listen on socket */
- if (listen(list_fd, BACKLOG) < 0 ) {
- perror("listen error");
- exit(-1);
- }
- /* write daytime to client */
- while (1) {
- if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
- perror("accept error");
- exit(-1);
- }
- timeval = time(NULL);
- snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
- if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
- perror("write error");
- exit(-1);
- }
- close(conn_fd);
- }
-
- /* normal exit */
- exit(0);
-}
-/*
- * routine to print usage info and exit
- */
-void usage(void) {
- printf("Simple daytime server\n");
- printf("Usage:\n");
- printf(" daytimed [-h] \n");
- printf(" -h print this help\n");
- exit(1);
-}
*
* Usage: echo -h give all info's
*
- * $Id: ElemEchoTCPClient.c,v 1.5 2003/02/02 20:35:33 piccardi Exp $
+ * $Id: ElemEchoTCPClient.c,v 1.6 2003/04/29 15:33:39 piccardi Exp $
*
****************************************************************/
/*
return -1;
}
/* read daytime from server */
- EchoClient(stdin, sock_fd);
+ ClientEcho(stdin, sock_fd);
/* normal exit */
return 0;
}
echod: SimpleEchoTCPServer.c
$(CC) $(CFLAGJ) $^ -o $@
-daytimed: ElemDaytimeTCPCuncServ.c
+daytimed: TCP_cunc_daytimed.c
$(CC) $(CFLAGJ) $^ -o $@
-iterdaytimed: ElemDaytimeTCPServer.c
+iterdaytimed: TCP_iter_daytimed.c
$(CC) $(CFLAGJ) $^ -o $@
daytime: TCP_daytime.c
--- /dev/null
+/* TCP_cunc_daytimed.c
+ *
+ * Copyright (C) 2001 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program TCP_cunc_daytimed.c
+ * Elementary TCP cuncurrent server for daytime service (port 13)
+ *
+ * Author: Simone Piccardi
+ * May. 2001
+ *
+ * Usage: daytimed -h give all info
+ *
+ * $Id: TCP_cunc_daytimed.c,v 1.1 2003/04/29 15:33:39 piccardi Exp $
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utiliites */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+#include <time.h>
+
+#define MAXLINE 80
+#define BACKLOG 10
+/* Program begin */
+void usage(void);
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add, client;
+ char buffer[MAXLINE];
+ socklen_t len;
+ time_t timeval;
+ pid_t pid;
+ int logging=0;
+ /*
+ * Input section: decode parameters passed in the calling
+ * Use getopt function
+ */
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "hv")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h':
+ printf("Wrong -h option use\n");
+ usage();
+ return(0);
+ break;
+ case '?': /* unrecognized options */
+ printf("Unrecognized options -%c\n",optopt);
+ usage();
+ return(0);
+ break;
+ case 'v':
+ logging = 1;
+ break;
+ default: /* should not reached */
+ usage();
+ return(0);
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ /* create socket */
+ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ exit(-1);
+ }
+ /* initialize address */
+ memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime port is 13 */
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
+ /* bind socket */
+ if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("bind error");
+ exit(-1);
+ }
+ /* listen on socket */
+ if (listen(list_fd, BACKLOG) < 0 ) {
+ perror("listen error");
+ exit(-1);
+ }
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *)&client, &len))
+ <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ /* fork to handle connection */
+ if ( (pid = fork()) < 0 ){
+ perror("fork error");
+ exit(-1);
+ }
+ if (pid == 0) { /* child */
+ close(list_fd);
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ if (logging) {
+ inet_ntop(AF_INET, &client.sin_addr, buffer, sizeof(buffer));
+ printf("Request from host %s, port %d\n", buffer,
+ ntohs(client.sin_port));
+ }
+ close(conn_fd);
+ exit(0);
+ } else { /* parent */
+ close(conn_fd);
+ }
+ }
+ /* normal exit, never reached */
+ exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Simple daytime server\n");
+ printf("Usage:\n");
+ printf(" daytimed [-hv] \n");
+ printf(" -h print this help\n");
+ printf(" -v print request source on stdout\n");
+ exit(1);
+}
+
-/* ElemDaytimeTCPClient.c
+/* TCP_daytime.c
*
* Copyright (C) 2001 Simone Piccardi
*
*
* Usage: daytime -h give all info's
*
- * $Id: TCP_daytime.c,v 1.1 2003/04/28 14:13:50 piccardi Exp $
+ * $Id: TCP_daytime.c,v 1.2 2003/04/29 15:33:39 piccardi Exp $
*
****************************************************************/
/*
--- /dev/null
+/* TCP_iter_daytimed.c
+ *
+ * Copyright (C) 2001 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program daytimed:
+ * Elementary TCP server for daytime service (port 13)
+ *
+ * Author: Simone Piccardi
+ * Apr. 2001
+ *
+ * Usage: daytimed -h give all info
+ *
+ * $Id: TCP_iter_daytimed.c,v 1.1 2003/04/29 15:33:39 piccardi Exp $
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#include <sys/types.h> /* predefined types */
+#include <unistd.h> /* include unix standard library */
+#include <arpa/inet.h> /* IP addresses conversion utiliites */
+#include <sys/socket.h> /* socket library */
+#include <stdio.h> /* include standard I/O library */
+#include <time.h>
+
+#define MAXLINE 80
+#define BACKLOG 10
+/* Program begin */
+void usage(void);
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int list_fd, conn_fd;
+ int i;
+ struct sockaddr_in serv_add;
+ char buffer[MAXLINE];
+ time_t timeval;
+ /*
+ * Input section: decode parameters passed in the calling
+ * Use getopt function
+ */
+ opterr = 0; /* don't want writing to stderr */
+ while ( (i = getopt(argc, argv, "h")) != -1) {
+ switch (i) {
+ /*
+ * Handling options
+ */
+ case 'h':
+ printf("Wrong -h option use\n");
+ usage();
+ return(0);
+ break;
+ case '?': /* unrecognized options */
+ printf("Unrecognized options -%c\n",optopt);
+ usage();
+ default: /* should not reached */
+ usage();
+ }
+ }
+ /* ***********************************************************
+ *
+ * Options processing completed
+ *
+ * Main code beginning
+ *
+ * ***********************************************************/
+ /* create socket */
+ if ( (list_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ perror("Socket creation error");
+ exit(-1);
+ }
+ /* initialize address */
+ memset((void *)&serv_add, 0, sizeof(serv_add)); /* clear server address */
+ serv_add.sin_family = AF_INET; /* address type is INET */
+ serv_add.sin_port = htons(13); /* daytime port is 13 */
+ serv_add.sin_addr.s_addr = htonl(INADDR_ANY); /* connect from anywhere */
+ /* bind socket */
+ if (bind(list_fd, (struct sockaddr *)&serv_add, sizeof(serv_add)) < 0) {
+ perror("bind error");
+ exit(-1);
+ }
+ /* listen on socket */
+ if (listen(list_fd, BACKLOG) < 0 ) {
+ perror("listen error");
+ exit(-1);
+ }
+ /* write daytime to client */
+ while (1) {
+ if ( (conn_fd = accept(list_fd, (struct sockaddr *) NULL, NULL)) <0 ) {
+ perror("accept error");
+ exit(-1);
+ }
+ timeval = time(NULL);
+ snprintf(buffer, sizeof(buffer), "%.24s\r\n", ctime(&timeval));
+ if ( (write(conn_fd, buffer, strlen(buffer))) < 0 ) {
+ perror("write error");
+ exit(-1);
+ }
+ close(conn_fd);
+ }
+
+ /* normal exit */
+ exit(0);
+}
+/*
+ * routine to print usage info and exit
+ */
+void usage(void) {
+ printf("Simple daytime server\n");
+ printf("Usage:\n");
+ printf(" daytimed [-h] \n");
+ printf(" -h print this help\n");
+ exit(1);
+}
devono essere specificati come OR binario delle costanti riportate in
\secref{tab:sys_timex_mode}.
-La funzione utilizza il meccanismo di David L. Mills, descritto nell'RFC~1305,
-che è alla base del protocollo NTP; la funzione è specifica di Linux e non
-deve essere usata se la portabilità è un requisito, le \acr{glibc} provvedono
-anche un suo omonimo \func{ntp\_adjtime}. La trattazione completa di questa
-funzione necessita di una lettura approfondita del meccanismo descritto
-nell'RFC~1305, ci limitiamo a descrivere in \tabref{tab:sys_timex_mode} i
-principali valori utilizzabili per il campo \var{mode}, un elenco più
-dettagliato del significato dei vari campi della struttura \struct{timex} può
-essere ritrovato in \cite{glibc}.
+La funzione utilizza il meccanismo di David L. Mills, descritto
+nell'\href{http://www.ietf.org/rfc/rfc1305.txt}{RFC~1305}, che è alla base del
+protocollo NTP. La funzione è specifica di Linux e non deve essere usata se la
+portabilità è un requisito, le \acr{glibc} provvedono anche un suo omonimo
+\func{ntp\_adjtime}. La trattazione completa di questa funzione necessita di
+una lettura approfondita del meccanismo descritto nell'RFC~1305, ci limitiamo
+a descrivere in \tabref{tab:sys_timex_mode} i principali valori utilizzabili
+per il campo \var{mode}, un elenco più dettagliato del significato dei vari
+campi della struttura \struct{timex} può essere ritrovato in \cite{glibc}.
\begin{table}[htb]
\footnotesize