%% othersock.tex
%%
%% Copyright (C) 2004 Simone Piccardi.  Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Prefazione",
%% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
\chapter{Gli altri tipi di socket}
\label{cha:other_socket}

Dopo aver trattato in \capref{cha:TCP_socket} i socket TCP, che costituiscono
l'esempio più comune dell'interfaccia dei socket, esamineremo in questo
capitolo gli altri tipi di socket, a partire dai socket UDP, e i socket deiit
\textit{Unix domain} già incontrati in \secref{sec:ipc_socketpair}.


\section{I socket UDP}
\label{sec:UDP_socket}

Dopo i socket TCP i socket più utilizzati nella programmazione di rete sono i
socket UDP: protocolli diffusi come NFS o il DNS usano principalmente questo
tipo di socket. Tratteremo in questa sezione le loro caratteristiche
principali e le modalità per il loro utilizzo.


\subsection{Le caratteristiche di un socket UDP}
\label{sec:UDP_characteristics}

Come illustrato in \secref{sec:net_udp} UDP è un protocollo molto semplice che
non supporta le connessioni e non è affidabile: esso si appoggia direttamente
sopra IP (per i dettagli sul protocollo si veda \secref{sec:udp_protocol}).  I
dati vengono inviati in forma di pacchetti, e non ne è assicurata né la
effettiva ricezione né l'arrivo nell'ordine in cui vengono inviati. Il
vantaggio del protocollo è la velocità, non è necessario trasmettere le
informazioni di controllo ed il risultato è una trasmissione di dati più
veloce ed immediata.

Questo significa che a differenza dei socket TCP i socket UDP non supportano
una comunicazione di tipo \textit{stream} in cui si ha a disposizione un
flusso continuo di dati che può essere letto un po' alla volta, ma piuttosto
una comunicazione di tipo \textit{datagram}, in cui i dati arrivano in singoli
blocchi che devono essere letti integralmente.

Questo diverso comportamento significa anche che i socket UDP, pur
appartenendo alla famiglia \const{PF\_INET}\footnote{o \const{PF\_INET6}
  qualora si usasse invece il protocollo IPv6, che pure supporta UDP.} devono
essere aperti quando si usa la funzione \func{socket} (si riveda quanto
illustrato a suo tempo in \tabref{tab:sock_sock_valid_combinations})
utilizzando per il tipo di socket il valore \const{SOCK\_DGRAM}.

Questa differenza comporta ovviamente che anche le modalità con cui si usano i
socket UDP sono completamente diverse rispetto ai socket TCP, ed in
particolare non esistendo il concetto di connessione non esiste il meccanismo
del \textit{three way handshake} nè quello degli stati del protocollo. In
realtà tutto quello che avviene nella comunicazione attraverso dei socket UDP
è la trasmissione di un pacchetto da un client ad un server o viceversa,
secondo lo schema illustrato in \figref{fig:UDP_packet-exchange}.

\begin{figure}[htb]
  \centering
  \includegraphics[width=10cm]{img/udp_connection}  
  \caption{Lo schema di interscambio dei pacchetti per una comunicazione via
     UDP.}
  \label{fig:UDP_packet-exchange}
\end{figure}

Come illustrato in \figref{fig:UDP_packet-exchange} la struttura generica di
un server UDP prevede, una volta creato il socket, la chiamata a \func{bind}
per mettersi in ascolto dei dati. Questa è l'unica parte comune con un server
TCP: non essendovi il concetto di connessione le funzioni \func{listen} ed
\func{accept} non sono mai utilizzate nel caso di server UDP. La ricezione dei
dati dal client avviene attraverso la funzione \func{recvfrom}, mentre una
eventuale risposta sarà inviata con la funzione \func{sendto}. 

Da parte del client invece, una volta creato il socket non sarà necessario
connettersi con \func{connect} (anche se, come vedremo in
\secref{sec:UDP_connect}, è possibile usare questa funzione, con un
significato comunque diverso) ma si potrà effettuare direttamente una
richiesta inviando un pacchetto con la funzione \func{sendto} e si potrà
leggere una eventuale risposta con la funzione \func{recvfrom}.

Anche se UDP è completamente diverso rispetto a TCP resta identica la
possibilità di gestire più canali di comunicazione fra due macchine
utilizzando le porte. In questo caso il server dovrà usare comunque la
funzione \func{bind} per scegliere la porta su cui ricevere i dati, e come nel
caso dei socket TCP si potrà usare il comando \cmd{netstat}\footnote{per
  ottenere il risultato mostrato occorre usare le opzioni \texttt{-anu}.} per
verificare quali socket sono in ascolto:
\begin{verbatim}
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
udp        0      0 0.0.0.0:32768           0.0.0.0:*
udp        0      0 192.168.1.2:53          0.0.0.0:*
udp        0      0 127.0.0.1:53            0.0.0.0:*
udp        0      0 0.0.0.0:67              0.0.0.0:*
\end{verbatim}
in questo caso abbiamo attivi il DNS (sulla porta 53, e sulla 32768 per la
connessione di controllo del server \cmd{named}) ed un server DHCP (sulla
porta 67).

Si noti però come in questo caso la colonna che indica lo stato sia vuota. I
socket UDP infatti non hanno uno stato. Inoltre anche in presenza di traffico
non si avranno indicazioni delle connessioni attive, proprio perché questo
concetto non esiste per i socket UDP, il kernel si limita infatti a ricevere i
pacchetti ed inviarli al processo in ascolto sulla porta cui essi sono
destinati, oppure a scartarli inviando un messaggio \textit{ICMP port
  unreachable} qualora non vi sia nessun processo in ascolto.


\subsection{Le funzioni \func{sendto} e \func{recvfrom}}
\label{sec:UDP_sendto_recvfrom}

Come accennato in \secref{sec:UDP_characteristics} le due funzioni principali
usate per la trasmissione di dati attraverso i socket UDP sono \func{sendto} e
\func{recvfrom}. La necessità di usare queste funzioni è dovuta al fatto che
non esistendo con UDP il concetto di connessione, non si ha neanche a
disposizione un \textsl{socket connesso} su cui sia possibile usare
direttamente \func{read} e \func{write} avendo già stabilito (grazie alla
chiamata ad \func{accept} che lo associa ad una connessione) quali sono
sorgente e destinazione dei dati.

Per questo motivo nel caso di UDP diventa essenziale utilizzare queste due
funzioni, che sono comunque usabili in generale per la trasmissione di dati
attraverso qualunque tipo di socket. Esse hanno la caratteristica di prevedere
tre argomenti aggiuntivi attraveso i quali è possibile specificare la
destinazione o l'origine dei dati trasmessi. La prima di queste funzioni è
\funcd{sendto} ed il suo prototipo\footnote{il prototipo illustrato è quello
  utilizzato dalle \acr{glibc}, che seguono le \textit{Single Unix
    Specification}, l'argomento \param{flags} era di tipo \type{int} nei vari
  BSD4.*, mentre nelle \acr{libc4} e \acr{libc5} veniva usato un
  \type{unsigned int}; l'argomento \param{len} era \type{int} nei vari BSD4.*
  e nelle \acr{libc4}, ma \type{size\_t} nelle \acr{libc5}; infine l'argomento
  \param{tolen} era \type{int} nei vari BSD4.* nelle \acr{libc4} e nelle
  \acr{libc5}.} è:
\begin{functions}
  \headdecl{sys/types.h}
  \headdecl{sys/socket.h}
  
  \funcdecl{ssize\_t sendto(int sockfd, const void *buf, size\_t len, int
    flags, const struct sockaddr *to, socklen\_t tolen)}
  
  Trasmette un messaggio ad un altro socket.
  
  \bodydesc{La funzione restituisce il numero di caratteri inviati in caso di
    successo e -1 per un errore; nel qual caso \var{errno} viene impostata al
    rispettivo codice di errore:
  \begin{errlist}
  \item[\errcode{EAGAIN}] il socket è in modalità non bloccante, ma
    l'operazione richede che la funzione si blocchi.
  \item[\errcode{ECONNRESET}] l'altro capo della comunicazione ha resettato la
    conessione.
  \item[\errcode{EDESTADDRREQ}] il socket non è di tipo connesso, e non si è
    specificato un indirizzo di destinazione.
  \item[\errcode{EISCONN}] il socket è già connesso, ma si è specificato un
    destinatario.
  \item[\errcode{EMSGSIZE}] il tipo di socket richiede l'invio dei dati in un
    blocco unico, ma la dimensione del messaggio lo rende impossibile.
  \item[\errcode{ENOBUFS}] la coda di uscita dell'interfaccia è già piena (di
    norma Linux non usa questo messaggio ma scarta silenziosamente i
    pacchetti).
  \item[\errcode{ENOTCONN}] il socket non è connesso e non si è specificata
    una destinazione.
  \item[\errcode{EOPNOTSUPP}] il valore di \param{flag} non è appropriato per
    il tipo di socket usato.
  \item[\errcode{EPIPE}] il capo locale della connessione è stato chiuso, si
    riceverà anche un segnale di \const{SIGPIPE}, a meno di non aver impostato
    \const{MSG\_NOSIGNAL} in \param{flags}.
  \end{errlist}
  ed anche \errval{EFAULT}, \errval{EBADF}, \errval{EINVAL}, \errval{EINTR},
  \errval{ENOMEM}, \errval{ENOTSOCK} più gli eventuali altri errori relativi
  ai protocolli utilizzati.}
\end{functions}

I primi tre argomenti sono identici a quelli della funzione \func{write} e
specificano il socket \param{sockfd} a cui si fa riferimento ed il buffer
\param{buf} (e relativa lunghezza \param{len}) che contiene i dati da inviare.
Come per \func{write} la funzione ritorna il numero di byte inviati; nel caso
di UDP però questo deve sempre corrispondere alla dimensione totale
specificata da \param{len} in quanto i dati vengono sempre inviati in forma di
pacchetto e non possono essere spezzati in invii successivi. Qualora non ci
sia spazio nel buffer di uscita la funzione si blocca (a meno di non avere
aperto il socket in modalità non bloccante), se invece non è possibile inviare
il messaggio all'interno di un unico pacchetto essa fallisce con l'errore di
\errcode{EMSGSIZE}.

I due argomenti \param{to} e \param{tolen} servono a specificare la
destinazione del messaggio da inviare, e prendono l'indirizzo di quest'ultima,
nella stessa forma in cui lo si specificherebbe per \func{connect}: \param{to}
deve cioè contenere l'indirizzo IP e la porta di destinazione cui si vogliono
inviare i dati e \param{tolen} la relativa dimensione.

Se il socket è di un tipo che prevede le connessioni, questo deve essere già
connesso prima di eseguire la funzione (altrimenti si avrà un errore di
\errcode{ENOTCONN}) ed inoltre questi due ultimi argomenti devono essere
inizializzati rispettivamente a \const{NULL} e 0 (di solito vengono ignorati,
ma si potrebbe ricevere altrimenti anche un errore di \errcode{EISCONN}).

Infine l'argomento \param{flags} è un intero usato come maschera binaria che
permette di impostare una serie di modalità di funzionamento della
comunicazione attraverso il socket (come \const{MSG\_NOSIGNAL} che impedisce
l'invio del segnale \const{SIGPIPE} quando si è già chiuso il capo locale
della connessione). Torneremo con maggiori dettagli sul significato di questo
argomento in \secref{sec:xxx_sendmsg}, per il momento ci si può limitare ad
usare sempre un valore nullo.

La seconda funzione utilizzata nella comunicazione fra socket UDP è
\funcd{recvfrom} che serve invece a ricevere i dati inviati da un altro
socket, il suo prototipo\footnote{il prototipo è quello delle \acr{glibc} che
  seguono le \textit{Single Unix Specification}, i vari BSD4.*, le \acr{libc4}
  e le \acr{libc5} usano un \type{int} come valore di ritorno; per gli
  argomenti \param{flags} e \param{len} vale quanto detto a proposito di
  \func{sendto}; infine l'argomento \param{fromlen} è \type{int} per i vari
  BSD4.*, le \acr{libc4} e le \acr{libc5}.} è:
\begin{functions}
  \headdecl{sys/types.h}
  \headdecl{sys/socket.h}
  
  \funcdecl{ssize\_t recvfrom(int sockfd, const void *buf, size\_t len, int
    flags, const struct sockaddr *from, socklen\_t *fromlen)}
  
  Riceve un messaggio ad un altro socket.
  
  \bodydesc{La funzione restituisce il numero di byte ricevuti in caso di
    successo e -1 in caso di errore; nel qual caso \var{errno} assumerà il
    valore:
  \begin{errlist}
  \item[\errcode{EAGAIN}] il socket è in modalità non bloccante, ma
    l'operazione richede che la funzione si blocchi, oppure si è impostato un
    timeout in ricezione e questo è scaduto.
  \item[\errcode{ECONNREFUSED}] l'altro capo della comunicazione ha rifiutato
    la connessione (in genere perché il relativo servizio non è disponibile).
  \item[\errcode{ENOTCONN}] il socket è di tipo connesso, ma non si è eseguita
    la connessione.
  \end{errlist}
  ed anche \errval{EFAULT}, \errval{EBADF}, \errval{EINVAL}, \errval{EINTR},
  \errval{ENOMEM}, \errval{ENOTSOCK} più gli eventuali altri errori relativi
  ai protocolli utilizzati.}
\end{functions}

Come per \func{sendto} i primi tre argomenti sono identici agli analoghi di
\func{read}: dal socket vengono letti \param{len} byte che vengono salvati nel
buffer \param{buf}. A seconda del tipo di socket (se di tipo \textit{datagram}
o \textit{stream}) inoltre i byte in eccesso che non sono stati letti possono
rispettivamente andare persi o restare disponibili per una lettura successiva.
Se non sono disponibili dati la funzione si blocca, a meno di non aver aperto
il socket in modalità non bloccante, nel qual caso si avrà il solito errore di
\errcode{EAGAIN}.  Qualora \param{len} ecceda la dimensione del pacchetto la
funzione legge comunque i dati disponibili, ed il suo valore di ritorno è
comunque il numero di byte letti.

I due argomenti \param{from} e \param{fromlen} sono utilizzati per ottenere
l'indirizzo del mittente del pacchetto che è stato ricevuto, e devono essere
opportunamente inizializzati con i puntatori alle variabili dove quest'ultimo
e la sua lunghezza saranno memorizzati (si noti che \param{fromlen} è un
valore intero ottenuto come \textit{value return argoment}).  Se non si è
interessati a questa informazione, entrambi gli argomenti devono essere
inizializzati al valore \const{NULL}.

Un'altra differenza fondamentale di queste funzioni rispetto alle usuali
\func{read} e \func{write} che abbiamo usato con i socket TCP è che in questo
caso è perfettamente legale inviare con \func{sendto} un pacchetto vuoto (che
nel caso conterrà solo le intestazioni di IP e di UDP), scrivendo 0 byte. Allo
stesso è possibile ricevere con \func{recvfrom} un valore di ritorno di 0
byte, senza che questo possa configurarsi come una chiusura della
connessione\footnote{dato che la connessione non esiste, non ha senso parlare
  di chiusura della connessione, pertanto con i socket UDP non è necessario
  usare \func{close} per terminare la cominicazione.} o come una cessazione
delle comunicazioni.


\subsection{Un client elementare}
\label{sec:UDP_simple_server}

Vediamo allora come implementare un primo server elementare su UDP; ricalcando
quanto fatto nel caso dei socket TCP prenderemo come primo esempio l'uso del
servizio \textit{time}, utilizzanto questa volta UDP.




\subsection{L'uso della funzione \func{connect} con i socket UDP}
\label{sec:UDP_connect}

Come illustrato in \secref{sec:UDP_characteristics} essendo i socket UDP privi
di connessione non è necessario per i client usare \func{connect} prima di
iniziare una comunicazione con un server.



\section{I socket \textit{Unix domain}}
\label{sec:unix_socket}

Benché i socket Unix domain non siano strattamente attinenti alla rete, in
quanto definiscono una interfaccia di comunicazione locale alla singola
macchina, li tratteremo comunque in questa sezione in quanto la loro
interfaccia è comunque basata sulla più generale interfaccia dei socket.




%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "gapil"
%%% End: 
