From b51bcef6bcf8c8622107b8ab8a22626dbdf6ba96 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 8 Dec 2004 14:49:24 +0000 Subject: [PATCH] Completata sezione sulla risoluzione di nomi ed indirizzi, iniziato a strutturare il prosieguo del lavoro. --- listati/TCP_echod_third.c | 1 - sockadv.tex | 20 ++-- sockctrl.tex | 217 ++++++++++++++++++++++---------------- sources/TCP_echod.c | 4 +- sources/TCP_echod_third.c | 6 +- 5 files changed, 141 insertions(+), 107 deletions(-) diff --git a/listati/TCP_echod_third.c b/listati/TCP_echod_third.c index c150ad4..a9149ae 100644 --- a/listati/TCP_echod_third.c +++ b/listati/TCP_echod_third.c @@ -13,7 +13,6 @@ int main(int argc, char *argv[]) } /* create and bind socket */ if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) { - if (errno) perror("Socket creation error"); return 1; } ... diff --git a/sockadv.tex b/sockadv.tex index b5d58db..9297e1c 100644 --- a/sockadv.tex +++ b/sockadv.tex @@ -18,12 +18,12 @@ e la gestione dei dati urgenti e \textit{out-of-band}. -\section{Socket TCP avanzati} -\label{sec:TCP_advanced_socket} - -Trattereno in questa sezione alcune delle funzionalità più avanzate relative -ai socket TCP. Da fare +\section{Le funzioni di I/O avanzate} +\label{sec:sock_advanced_IO} +Trattereno in questa sezione le funzioni di I/O più avanzate che permettono di +controllare le funzionalità specifiche della comunicazione dei dati che sono +disponibili con i vari tipi di socket. \subsection{I dati \textit{out-of-band}} @@ -33,11 +33,13 @@ Una caratteristica speciale dei socket TCP cosiddetti dati \textit{out-of-band} ... -\section{Socket UDP avanzati} -\label{sec:UDP_advanced_socket} +\section{L'uso dell'I/O non bloccante} +\label{sec:sock_noblok_IO} + +Trattereno in questa sezione le modalità avanzate che permettono di utilizzare +i socket con una comunicazione non bloccante, in modo da + -Trattereno in questa sezione alcune delle funzionalità più avanzate relative -ai socket UDP. Da fare diff --git a/sockctrl.tex b/sockctrl.tex index 594e608..a67e9b6 100644 --- a/sockctrl.tex +++ b/sockctrl.tex @@ -1688,17 +1688,14 @@ indicano il nome della macchina a cui collegarsi ed il relativo servizio su cui sarà effettuata la risoluzione; seguono il protocollo da usare (da specificare con il valore numerico di \file{/etc/protocols}) ed il tipo di socket (al solito specificato con i valori illustrati in -sez.~\ref{sec:sock_type}). - -La funzione ritorna il valore del file descriptor (un numero positivo) -associato al socket in caso di successo, o -1 in caso di errore. Per risolvere -il problema di non poter passare indietro i valori di ritorno di -\func{getaddrinfo} con i codici di errore\footnote{non si può avere nessuna - certezza che detti valori siano negativi, è questo è invece nessario per - evitare ogni possibile ambiguità nei confronti del valore di ritorno in caso - di successo.} si è provvisto a stampare direttamente all'interno della -funzione i rispettivi errori, si potrà riconoscere questo caso ottenendo -1 -per il valore di ritorno, ma un valore nullo di \var{errno}. +sez.~\ref{sec:sock_type}). La funzione ritorna il valore del file descriptor +associato al socket (un numero positivo) in caso di successo, o -1 in caso di +errore; per risolvere il problema di non poter passare indietro i valori di +ritorno di \func{getaddrinfo} contenenti i relativi codici di +errore\footnote{non si può avere nessuna certezza che detti valori siano + negativi, è questo è invece nessario per evitare ogni possibile ambiguità + nei confronti del valore di ritorno in caso di successo.} si sono stampati i +messaggi d'errore direttamente nella funzione. Una volta definite le variabili necessarie (\texttt{\small 3--5}) la funzione prima (\texttt{\small 6}) azzera il contenuto della struttura \var{hint} e poi @@ -1707,40 +1704,46 @@ chiamata (\texttt{\small 10}) a \func{getaddrinfo}. Di quest'ultima si controlla (\texttt{\small 12-16}) il codice di ritorno, in modo da stampare un avviso di errore, azzerare \var{errno} ed uscire in caso di errore. Dato che ad una macchina possono corrispondere più indirizzi IP, e di tipo diverso (sia -IPv4 che IPv6), ed il servizio può essere in ascolto soltanto su uno solo di -questi, si provvede a tentare la connessione per ciascun indirizzo restituito -all'interno di un ciclo (\texttt{\small 18-40}) di scansione della lista -restituita da \func{getaddrinfo}, ma prima (\texttt{\small 17}) si salva il -valore del puntatore per poterlo riutilizzare alla fine per disallocare la +IPv4 che IPv6), mantre il servizio può essere in ascolto soltanto su uno solo +di questi, si provvede a tentare la connessione per ciascun indirizzo +restituito all'interno di un ciclo (\texttt{\small 18-40}) di scansione della +lista restituita da \func{getaddrinfo}, ma prima (\texttt{\small 17}) si salva +il valore del puntatore per poterlo riutilizzare alla fine per disallocare la lista. -Il ciclo viene ripetuto fintanto che si hanno indirizzi validi, ed inizia -(\texttt{\small 19}) con l'apertura del socket; se questa fallisce si -controlla (\texttt{\small 20}) se sono disponibili altri indirizzi, nel qual -caso si passa al successivo (\texttt{\small 21}) ricominciando il ciclo -(\texttt{\small 22}), se non ve ne sono si stampa l'errore ritornado -immediatamente (\texttt{\small 24-27}). Se la creazione del socket ha avuto -successo si procede (\texttt{\small 29}) con la connessione - - - - - -Se la risoluzione del nome ha successo si provvede (\texttt{\small 19--23}) ad -aprire il socket, ed a connettersi ad esso (\texttt{\small 25--29}); in -entrambi casi si gestisce il caso di errore, con una stampa ed il ritorno del -valore -1. Infine prima di ritornare (\texttt{\small 31}) il valore del file -descriptor del socket si provvede (\texttt{\small 30}) a liberare le strutture -\struct{addrinfo} allocate da \func{getaddrinfo}. - -Si noti come la funzione si limiti ad usare i valori contenuti nella prima -struttura \struct{addrinfo} ritornata da \func{getaddrinfo}, non eseguendo -ulteriori tentativi sulle successive in caso di errore. Un'altra -caratteristica della funzione è che è del tutto irrilevante se la struttura -ritornata usa indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei dati -relativi alle strutture degli indirizzi di \struct{addrinfo} che sono +Il ciclo viene ripetuto (\texttt{\small 18}) fintanto che si hanno indirizzi +validi, ed inizia (\texttt{\small 19}) con l'apertura del socket; se questa +fallisce si controlla (\texttt{\small 20}) se sono disponibili altri +indirizzi, nel qual caso si passa al successivo (\texttt{\small 21}) e si +riprende (\texttt{\small 22}) il ciclo da capo; se non ve ne sono si stampa +l'errore ritornando immediatamente (\texttt{\small 24-27}). Quando la +creazione del socket ha avuto successo si procede (\texttt{\small 29}) +direttamente con la connessione, di nuovo in caso di fallimento viene ripetuto +(\texttt{\small 30--38}) il controllo se vi sono o no altri indirizzi da +provare nella stessa modalità fatta in precedenza, aggiungendovi però in +entrambi i casi (\texttt{\small 32} e (\texttt{\small 36}) la chiusura del +socket precedentemente aperto, che non è più utilizzabile. + +Se la connessione ha avuto successo invece si termina (\texttt{\small 39}) +direttamente il ciclo, e prima di ritornare (\texttt{\small 31}) il valore del +file descriptor del socket si provvede (\texttt{\small 30}) a liberare le +strutture \struct{addrinfo} allocate da \func{getaddrinfo} utilizzando il +valore del relativo puntatore precedentemente (\texttt{\small 17}) salvato. +Si noti come per la funzione sia del tutto irrilevante se la struttura +ritornata contiene indirizzi IPv6 o IPv4, in quanto si fa uso direttamente dei +dati relativi alle strutture degli indirizzi di \struct{addrinfo} che sono \textsl{opachi} rispetto all'uso della funzione \func{connect}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/TCP_echo_fifth.c} + \end{minipage} + \normalsize + \caption{Il nuovo codice per la connessione del client \textit{echo}.} + \label{fig:TCP_echo_fifth} +\end{figure} + Per usare questa funzione possiamo allora modificare ulteriormente il nostro programma client per il servizio \textit{echo}; in questo caso rispetto al codice usato finora per collegarsi (vedi fig.~\ref{fig:TCP_echo_client_1}) @@ -1755,11 +1758,11 @@ dell'indirizzo numerico, e pu \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \includecodesample{listati/TCP_echo_fifth.c} + \includecodesample{listati/sockbind.c} \end{minipage} \normalsize - \caption{Il nuovo codice per la connessione del client \textit{echo}.} - \label{fig:TCP_echo_fifth} + \caption{Il codice della funzione \func{sockbind}.} + \label{fig:sockbind_code} \end{figure} La seconda funzione di ausilio è \func{sockbind}, il cui corpo principale è @@ -1768,55 +1771,37 @@ nel file \file{sockbind.c} dei sorgenti allegati alla guida). Come si pu notare la funzione è del tutto analoga alla precedente \func{sockconn}, e prende gli stessi argomenti, però invece di eseguire una connessione con \func{connect} si limita a chiamare \func{bind} per collegare il socket ad una -porta. +porta. -Dato che la funzione è pensata per utilizzata da un server ci si può chiedere -a quale scopo mantenere l'argomento \param{host} quando l'indirizzo di questo -è usualmente noto. Si ricordi però quanto detto in +Dato che la funzione è pensata per essere utilizzata da un server ci si può +chiedere a quale scopo mantenere l'argomento \param{host} quando l'indirizzo +di questo è usualmente noto. Si ricordi però quanto detto in sez.~\ref{sec:TCP_func_bind}, relativamente al significato della scelta di un indirizzo specifico come argomento di \func{bind}, che consente di porre il server in ascolto su uno solo dei possibili diversi indirizzi presenti su di -una macchina. - -Se non si vuole che la funzione esegua \func{bind} su un indirizzo specifico, -ma utilizzi l'indirizzo generico, occorrerà avere cura di passare un valore -\const{NULL} come valore per l'argomento \var{host}; l'uso del valore -\const{AI\_PASSIVE} serve ad ottenere il valore generico nella rispettiva -struttura degli indirizzi. - -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \includecodesample{listati/sockbind.c} - \end{minipage} - \normalsize - \caption{Il codice della funzione \func{sockbind}.} - \label{fig:sockbind_code} -\end{figure} +una macchina. Se non si vuole che la funzione esegua \func{bind} su un +indirizzo specifico, ma utilizzi l'indirizzo generico, occorrerà avere cura di +passare un valore \const{NULL} come valore per l'argomento \var{host}; l'uso +del valore \const{AI\_PASSIVE} serve ad ottenere il valore generico nella +rispettiva struttura degli indirizzi. Come già detto la funzione è analoga a \func{sockconn} ed inizia azzerando ed inizializzando (\texttt{\small 6-11}) opportunamente la struttura \var{hint} con i valori ricevuti come argomenti, soltanto che in questo caso si è usata (\texttt{\small 8}) una impostazione specifica dei flag di \var{hint} usando \const{AI\_PASSIVE} per indicare che il socket sarà usato per una apertura -passiva. Per il resto la chiamata a \func{getaddrinfo} (\texttt{\small 12-17}) -e quella a \func{socket} (\texttt{\small 19--23}) sono identiche, mentre si è -sostituita (\texttt{\small 25--29}) la chiamata a \func{connect} con una -chiamata a \func{bind}. La conclusione (\texttt{\small 30--31}) della funzione -è identica. Si noti come anche in questo caso si siano inserite le stampe -degli errori sullo standard output, nonostante la funzione possa essere -invocata da un demone. Nel nostro caso questo non è un problema in quanto se -la funzione non ha successo il programma deve uscire immediatamente prima di -essere posto in background, e può quindi scrivere gli errori direttamente -sullo standard output. - -Con l'uso di questa funzione si può modificare anche il codice del nostro -server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale -di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma -riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui -porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \func{sockbind} -che si cura anche della eventuale risoluzione di un indirizzo specifico sul -quale si voglia far ascoltare il server. +passiva. Per il resto la chiamata (\texttt{\small 12-18}) a \func{getaddrinfo} +e ed il ciclo principale (\texttt{\small 20--42}) sono identici, solo che si è +sostituita (\texttt{\small 31}) la chiamata a \func{connect} con una chiamata +a \func{bind}. Anche la conclusione (\texttt{\small 43--44}) della funzione è +identica. + +Si noti come anche in questo caso si siano inserite le stampe degli errori +sullo standard error, nonostante la funzione possa essere invocata da un +demone. Nel nostro caso questo non è un problema in quanto se la funzione non +ha successo il programma deve uscire immediatamente prima di essere posto in +background, e può quindi scrivere gli errori direttamente sullo standard +error. \begin{figure}[!htb] \footnotesize \centering @@ -1828,23 +1813,73 @@ quale si voglia far ascoltare il server. \label{fig:TCP_echod_third} \end{figure} +Con l'uso di questa funzione si può modificare anche il codice del nostro +server \textit{echo}, che rispetto a quanto illustrato nella versione iniziale +di fig.~\ref{fig:TCP_echo_server_first_code} viene modificato nella forma +riportata in fig.~\ref{fig:TCP_echod_third}. In questo caso il socket su cui +porsi in ascolto viene ottenuto (\texttt{\small 15--18}) da \func{sockbind} +che si cura anche della eventuale risoluzione di un indirizzo specifico sul +quale si voglia far ascoltare il server. + \section{Le opzioni dei socket} -\label{sec:TCP_sock_options} +\label{sec:sock_options} + +Benché dal punto di vista del loro uso come canali di trasmissione di dati i +socket siano trattati allo stesso modo dei file, associandoli a dei file +descriptor, e utilizzando le varie funzioni di I/O su di questi, la normale +interfaccia usata per la gestione dei file non è ovviamente sufficiente a +poterne controllare tutte le caratteristiche, che variano tra l'altro a +seconda del loro tipo. In questa sezione vedremo allora quali sono le funzioni +dedicate alla gestione di tutte le caratteristiche specifiche dei vari tipi di +socket, le cosiddette \textit{socket options}. + + +\subsection{Le funzioni \func{setsockopt} e \func{getsockopt}} +\label{sec:sock_setsockopt} + + + + +Le due funzioni principali per gestire le caratteristiche specifiche dei vari +tipi di socket sono \func{setsockopt} e \func{getsockopt}. -Finora abbiamo trattato i socket nel loro comportamento più comune, è però -possibile attivare alcune modalità diverse di funzionamento degli stessi -Dato che la maggior parte delle opzioni dei socket sono relative ai socket - TCP, ed hanno poi significato analogo quando usate con altri socket, abbiamo -preferito trattare l'argomento in generale in questa sezione piuttosto che nel -capitolo dedicato alla trattazione generica dei socket. +\subsection{Le opzioni generiche} +\label{sec:sock_generic_options} + +Anche se ciascun tipo di socket presenta una serie di caratteristiche +particolari, gestite attraverso delle opzioni specifiche, ma esiste un insieme +generico di opzioni che possono applicarsi a qualunque tipo di socket. + \section{Altre funzioni di controllo} -\label{sec:TCP_sock_ctrl} +\label{sec:sock_ctrl_func} + +Benché la maggior parte delle caratteristiche dei socket sia gestita +attraverso le due funzioni \func{setsockopt} e \func{getsockopt}, alcune +funzionalità possono essere impostate attraverso quelle che sono le funzioni +classiche per il controllo delle proprietà dei file, cioè \func{fcntl} e +\func{ioctl}. + + +\subsection{L'uso di \func{fcntl} per i socket} +\label{sec:sock_fcntl} + +Abbiamo già trattato l'uso di \func{fcntl} in sez.~\ref{sec:file_fcntl}, dove +però ne abbiamo descritto le funzionalità nell'ambito della sua applicazione a +file descriptor associati a file normali; tratteremo qui invece il suo uso +specifico quando la si impiega su file descriptor associati a dei socket. + +\subsection{L'uso di \func{ioctl} per i socket} +\label{sec:sock_ioctl} +Come per \func{fcntl} abbiamo trattato l'uso di \func{ioctl} in +sez.~\ref{sec:file_ioctl}, dove ne abbiamo descritto le funzionalità +nell'ambito dell'applicazione su file normali; tratteremo qui il suo uso +specifico quando la si impiega su file descriptor associati a dei socket. diff --git a/sources/TCP_echod.c b/sources/TCP_echod.c index 6890492..cca4933 100644 --- a/sources/TCP_echod.c +++ b/sources/TCP_echod.c @@ -64,7 +64,7 @@ int main(int argc, char *argv[]) int waiting = 0; int compat = 0; pid_t pid; - struct sockaddr_in serv_add, cli_add; + struct sockaddr_in cli_add; socklen_t len; char debug[MAXLINE], ipaddr[20]; /* @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) SignalRestart(SIGCHLD, HandSigCHLD); /* restarting handler */ } /* create and bind socket */ - if ( (list_fd = sockbind(NULL, "echo", 6, SOCK_STREAM)) < 0) { + if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) { return 1; } /* release privileges and go daemon */ diff --git a/sources/TCP_echod_third.c b/sources/TCP_echod_third.c index 86c154f..6890492 100644 --- a/sources/TCP_echod_third.c +++ b/sources/TCP_echod_third.c @@ -1,4 +1,4 @@ -/* TCP_echod_third.c +/* TCP_echod.c * * Copyright (C) 2001-2004 Simone Piccardi * @@ -20,7 +20,6 @@ * * Program echod * Elementary TCP server for echo service (port 7) - * Third version, use sockbind * * Author: Simone Piccardi * Jun. 2001 @@ -117,8 +116,7 @@ int main(int argc, char *argv[]) SignalRestart(SIGCHLD, HandSigCHLD); /* restarting handler */ } /* create and bind socket */ - if ( (list_fd = sockbind(argv[optind], "echo", 6, SOCK_STREAM)) < 0) { - if (errno) perror("Socket creation error"); + if ( (list_fd = sockbind(NULL, "echo", 6, SOCK_STREAM)) < 0) { return 1; } /* release privileges and go daemon */ -- 2.30.2