1 Reti di Calcolatori Esercitazione 4 Implementazione di TFTP in C / XDR Copyright © by D. Romagnoli & C. Salati Alma Mater Studiorum - Universita' di Bologna Sede di Cesena II Facolta' di Ingegneria
2 Servizio di file transfer TFTP in C e XDR su UDP Questa esercitazione, come la numero 3, richiede limplementazione di un servizio di file transfer. Il protocollo applicativo utilizzato per fornire questo servizio e derivato dal protocollo TFTP. In questo caso pero il protocollo applicativo (Layer 7) deve essere descritto (come parte dellesercitazione) in forma di sintassi astratta tramite XDR. Il servizio e quindi implementato utilizzando i servizi del Layer di Presentazione. Come Servizio di Trasporto si usera quello fornito dal protocollo UDP. Poiche questo servizio e di tipo non affidabile occorrera gestire il caso di perdita di datagram (in particolare i PDU di tipo DAT e ACK). Il linguaggio di programmazione da utilizzare e il C (oltre che lXDR). Si dovra realizzare una coppia di programmi, un client e un server, e il server dovra essere implementato come un filtro Unix interfacciato alla rete dal superserver inetd dellesercitazione 1.
3 Servizio applicativo TFTP vs. protocol entity TFTP Come nel caso dellesercitazione 3, quello che si chiede di implementare e sia il protocollo applicativo (di Layer 7) TFTP, lati client e server, che due moduli, client e server, di applicazioni utente TFTP. I due diversi layer dovrebbero essere mantenuti il piu possibile separati. In questo caso, pero, il Layer di Presentazione (ovviamente anchesso presente) viene implementato utilizzando il sistema di programmazione XDR. La struttura delle due applicazioni client e server deve quindi essere la seguente: TSAP User Application TFTP Protocol Entity Presentation Layer Transport Layer Layer Utente Layer 7 - Application Layer 6 - Presentation Generato automaticamente da rpcgen a partire dalla sintassi astratta descritta in XDR (+XDR library)
4 1.Le specifiche per lapplicazione utente, sia lato client che lato server, devono essere derivate da quelle utilizzate per lesercitazione 3. 2.Le specifiche per le protocol entity TFTP devono essere adattate al fatto che in questo caso il protocollo di trasporto utilizzato e UDP. 3.Protocol entity TFTP, lato client: Non hanno senso le due operazioni, previste in esercitazione 3, di apertura e chiusura della sessione di file transfer. Linterazione con il server (sessione) inizia tramite linvio del primo PDU di WRQ o RRQ (della sessione di file transfer). La gestione del primo PDU di sessione dovra quindi essere diversa da quella dei successivi PDU di WRQ e RRQ (vedi seguito). Linterazione con il server (la sessione) viene terminata in modo fisiologico per timeout, in quanto a valle di un trasferimento di file non ne e iniziato uno successivo per un tempo sufficientemente lungo. Linterazione con il server puo anche terminare in modo patologico a seguito di errori di comunicazione (e.g. caduta delle comunicazioni) o di protocollo, e con leventuale scambio di un PDU di ERR. Continua Specifiche.1
5 3.Protocol entity TFTP, lato client ( continua): Oltre ad una terminazione per timeout fisiologica dovra essere prevista anche una terminazione per timeout patologica, dovuta a problemi di comunicazione o alla morte del pari remoto. Deve essere gestito il protocollo di interazione con i server UDP che prevede che lindirizzo mittente della prima risposta ricevuta (quella relativa al primo PDU di sessione inviato, di tipo WRQ o RRQ) debba diventare lindirizzo destinazione di tutte le comunicazioni future della sessione. 4.Protocol entity TFTP, lato server: Deve essere gestita la terminazione per timeout della sessione di file transfer con il client: terminato un trasferimento file il client non ne richiede piu un altro. Oltre ad una terminazione per timeout fisiologica dovra essere prevista anche una terminazione per timeout patologica, dovuta a problemi di comunicazione o alla morte del pari remoto. Linterazione con il client puo anche terminare in modo patologico a seguito di un errore di protocollo e per la ricezione di un PDU di ERR. Specifiche.2
6 1.Il server deve poter essere utilizzabile come server (sia concorrente che sequenziale) che si offre in rete tramite il superserver: deve cioe essere strutturato come un filtro Unix. 2.Il servizio deve seguire lo schema di servizio UDP visto a lezione, cioe: rispondere al cliente non tramite il socket well known ma tramite una porta effimera, lasciare il socket well known disponibile a ricevere il primo messaggio WRQ/RRQ di richiesta di nuovi clienti. 3.In realta, per come funziona il superserver: e lui che determina se un servizio si comporta o meno in modo concorrente; e lui che: (a) crea il socket effimero su cui il cliente ottiene effettivamente il servizio, (b) lo connette al cliente, e gli trasferisce il primo messaggio ricevuto dal cliente sulla porta well known, (c) lo rimappa sui file descriptor 0 e 1. 4.Il server specifico si limita a interagire come filtro Unix con un singolo cliente, il cliente cui e connesso il socket che gli e stato passato sui file descriptor 0 e 1 dal superserver. Specifiche per il server.1
7 1.Prima dellattivazione del server specifico, il superserver ha ridiretto linput stream e loutput stream del socket connesso sul quale il cliente deve essere servito sui file descriptor 0 e 1. 2.Il server specifico si limita a interagire con il cliente inviandogli messaggi tramite il file descriptor 1 e leggendo i messaggi ricevuti da questo tramite il file descriptor 0. 3.Poiche il socket acceduto tramite i file descriptor 0 e 1 e connesso (alla porta del client), il server puo operare su di essi tramite le system call read() e write() (rispettivamente). N.B.: il server puo anche sapere lindirizzo del client cui e connesso utilizzando la system call getpeername(). 4.I file descriptor 0 e 1 sono accessibili nel programma C anche tramite le variabili stdin e stdout. Specifiche per il server.2
8 1.Detto serverTftpUdp il file eseguibile del programma server, il file di configurazione del superserver dovra contenere una linea del tipo:./serverTftp udp nowait 2.Alla ricezione di un PDU di ERR il server (la sessione) deve terminare. 3.In caso di terminazione di errore il server deve indicare la cosa tracciando levento sul file stderr ereditato dal superserver (presumibilmente la shell di attivazione del superserver). 4.Durante una interazione (sessione) con il client devono poter essere trasferiti diversi file, sia in una direzione che nellaltra. 5.La sessione di file transfer viene considerata chiusa (in modo normale) dal server se, esaurito il trasferimento di un file, passa un tempo abbastanza lungo (dimensione definita staticamente) senza che il client richieda il trasferimento di un altro file. In questo caso il server/filtro Unix termina la propria esecuzione. Specifiche per il server.3
9 1.Notare che le specifiche per il server richiedono anche di poterlo attivare in modo diretto, al di fuori del contesto superserver. Vedi le stringhe di attivazione previste per distinguere i due casi in esercitazione 3. 2.Quando e attivato direttamente il server e responsabile di gestire lofferta del servizio sulla porta well known. 3.Poiche lattivazione diretta e utilizzata solo allo scopo di debugging del programma, il fatto che il servizio offerto sia sequenziale o concorrente e irrilevante. Il server, in questo caso, deve essere realizzato in modo da facilitare al massimo il lavoro di debugging. Quindi conviene considerare di realizzare un servizio sequenziale. 4.Quando, essendo stato attivato in modo diretto, il server decide di terminare una sessione di file transfer, esso ritorna in attesa del prossimo cliente sulla porta well known del servizio. Specifiche per il server.4
10 Il client, alla ricezione della risposta al primo messaggio, deve: Estrarre dal datagram UDP lindirizzo della porta mittente. E tramite questa porta che ricevera effettivamente il servizio da parte del server. Connettere il proprio socket a questo indirizzo. (Di conseguenza) utilizzare questo nuovo indirizzo come indirizzo destinatario nel seguito della sua interazione con il server (per il trasferimento non solo di questo ma anche di altri file). Notare che questo tipo di comportamento del client e compatibile con qualunque comportamento/implementazione del server, e.g. anche se il server fosse sequenziale e fornisse effettivamente il proprio servizio attraverso la porta well known. Notare che quando si dice primo messaggio si intende primo messaggio in assoluto della sessione (ovviamente di tipo WRQ o RRQ). Specifiche per il client
11 Il protocollo TFTP e a conferma di ricezione positiva con ritrasmissione, cioe gestisce la perdita dei PDU attraverso un meccanismo di ritrasmissione a timeout. A differenza dellesercitazione 3, in cui il servizio di trasporto utilizzato era quello affidabile del TCP, e in cui il meccanismo dellacknowledgement serviva solo per il flow control, qui esso serve anche (soprattutto) al recupero degli errori. Il mittente del file spedisce il PDU DAT #N e si mette in attesa di una risposta usando una select() con il timeout definito. Quando la select() termina: Se la terminazione e dovuta alla ricezione di un PDU (ACK o ERR, altrimenti si tratta di un errore di protocollo) gestisce il PDU (se e un PDU di ACK controlla che il numero di blocco sia corretto, altrimenti considera che ci sia stato un errore di protocollo). Se la terminazione e dovuta allo spirare del timeout (cioe in assenza di ACK entro il termine atteso) ritrasmette il PDU DAT #N; Se la terminazione e dovuta ad un errore (di ricezione o di protocollo) invia un PDU di ERR al ricevitore (se possibile!) e termina. Si deve prevedere un limite massimo di ritrasmissioni (definito a compile time in modo condiviso tra client e server) superato il quale il trasmettitore inviera al ricevitore un PDU di ERR e terminera la sessione. Affidabilita.1
12 Il ricevitore del file e in attesa di PDU di tipo DAT. Alla ricezione del PDU DAT #N si comportera nel modo seguente: se lultimo ACK spedito era il numero N-1 allora si tratta di un nuovo PDU DAT: ne copia il contenuto nel file ed invia lACK #N; se lultimo ACK spedito era proprio il numero N allora si tratta di una ritrasmissione del PDU DAT #N: lo scarta ed invia lACK #N; in tutti i rimanenti casi (per qualunque altro valore del campo block# ), inviera un PDU di errore al mittente del file e terminera. Il ricevitore del file non ritrasmette mai ACK a timeout! Ma in ogni caso e opportuno prevedere che la ricezione del prossimo PDU di DAT avvenga sotto la supervisione di un timeout di salvaguardia: allo scadere di questo timeout il ricevitore, se non ha ricevuto alcun PDU di DAT, decide che il mittente del file (o la rete) ha dei problemi e termina (eventualmente inviando al mittente un PDU di ERR). Esercizio: come si correla questo timeout lato ricevitore con il valore del timeout lato trasmettitore e il numero massimo di retry? Specificare nella soluzione! Affidabilita.2
13 Un caso particolare e costituito dallattesa (da parte del client, ovvio!) della risposta ai PDU RRQ e WRQ. Qui bisogna anche distinguere 2 sottocasi: 1.attesa della risposta al primo PDU RRQ/WRQ della sessione, quello che apre la sessione stessa. 2.attesa della risposta a un PDU RRQ/WRQ che non e il primo della sessione. Questa distinzione e significativa in generale, ma lo e particolarmente nel nostro caso (quando larchitettura server e basata sulla presenza di un superserver) perche se il client, a fronte dello scadere del timeout, trasmette un nuovo PDU (ritrasmissione di RRQ/WRQ o PDU di ERR) nel primo caso questo e inviato alla porta well known, quindi al superserver, nel secondo caso esso e inviato al server specifico. Affidabilita.3.1
14 La gestione consigliata e la seguente: Nel caso scada il timeout sul primo PDU RRQ/WRQ della sessione, abortire semplicemente la sessione senza inviare piu niente al server. Esercizio: cosa succederebbe se il client ripetesse linvio del PDU RRQ/WRQ? Immaginare lo scenario in cui ad essere persa dalla rete fosse stata la risposta al primo PDU inviato dal client. Specificare nella soluzione! Nel caso scada il timeout su un PDU RRQ/WRQ che non e il primo della sessione, mandare al server un PDU di ERR e abortire il trasferimento file informandone loperatore. E evidente che un server, deve gestire la ricezione di un PDU di ERR anche come primo PDU di un trasferimento file. N.B.: e quello che capiterebbe nel primo caso se, a seguito dello scadere del timeout, il client, anziche limitarsi a terminare, decidesse di inviare anche questo PDU. Affidabilita.3.2
15 Attesa a timeout Lesercitazione richiede la gestione di timeout per 3 scopi differenti: 1.Effettuare la ritrasmissione di un PDU di DAT per il recupero dei PDU persi dalla rete. Quando attendiamo un PDU di ACK (timeout to1). 2.Accorgersi, lato server, della terminazione di una sessione di file transfer. Quando attendiamo un PDU di WRQ o RRQ (timeout to0). Ovviamente questo caso non e significativo per il PDU di WRQ o RRQ relativo al primo trasferimento della sessione. 3.Come salvaguardia per gestire il caso di scomparsa inattesa dellinterlocutore. Quando attendiamo un PDU di DAT (timeout to2). Useremo timeout di dimensione fissa, definita a compile time in modo coordinato da client e server, ma differenziata per i diversi casi (to0 to1 to2). Infatti i diversi casi sono alternativi tra loro. Il dimensionamento congruente dei timeout per i diversi casi e largomentazione delle scelte effettuate sono parte integrante dellesercitazione.
16 Attesa a timeout Supervisioneremo a tempo loperazione di ricezione dalla rete utilizzando la system call select(). Detti fd il socket descriptor di interesse e to il timeout int fd_set fds; struct timeval to = {2, 0}; // to pari a 2sec FD_ZERO(&fds); FD_SET(fd,&fds); int ready = select(fd+1, &fd_set, 0, 0, &to); Il valore ritornato dalla select() sara: 0< in caso di errore in questo caso bisogna preoccuparsi di gestire il codice di errore EINTR ? Perche? Commentare nella soluzione! 0 nel caso di timeout esaurito. 1 nel caso ci sia qualcosa da leggere sul socket descriptor fd.
17 Acknowledgment (ACK) 04 2 bytes opcode block# 2 bytes error (ERR) 05 2 bytes opcode errcode 2 bytes errstring n bytes string 0 1 byte EOS write-request (WRQ) 02 2 bytes opcode filename n bytes string 0 1 byte EOS mode n bytes string 0 1 byte EOS 03 2 bytes opcode data n bytes, 0 <= n <= 512 block# 2 bytes data (DAT) read-request (RRQ) 01 2 bytes opcode filename n bytes string 0 1 byte EOS mode n bytes string 0 1 byte EOS PDU del protocollo TFTP: mappa di byte
18 Notare che non e piu presente il campo length. Perche? Si presuppone che la sintassi sia descritta nel file XDR tftp.x. Quella che viene presentata cone esempio e una sintassi astratta sconveniente e piena di errori formali: Cercate di definire una buona sintassi astratta. Tenete conto dei limiti del compilatore rpcgen. La struttura di PDU (il tipo dei singoli campi del PDU) descritta nella mappa di byte non deve essere considerata vincolante: Siete incoraggiati a modificarla nel modo piu opportuno. Sfruttate bene i tipi primitivi e i costruttori di tipo previsti da XDR. Non dovete cercare una definizione XDR che produca come sintassi di trasferimento quella descritta nella mappa di byte di TFTP. E linformazione contenuta nei PDU TFTP che dovete considerare. PDU del protocollo: sintassi astratta sconsigliata.0
19 const MAX_FILE_NAME_LENGTH = 500; /* max lunghezza del nome del file */ const MAX_MODE_LENGTH = 6; /* max lunghezza del modi di trasferimento */ const MAX_DAT_LENGTH = 512; /* max lunghezza di un blocco dati */ const MAX_STRING_ERR_LEN = 100; /* max lunghezza della stringa di errore */ enum OpType { RRQ = 0x01,/* PDU di richiesta operazione get */ WRQ = 0x02,/* PDU di richiesta operazione put */ DAT = 0x03,/* PDU di trasferimento di un blocco dati */ ACK = 0x04,/* PDU di ACK */ ERR = 0x05/* PDU di errore */ };/* enumerato che identifica i 5 sottotipi di PDU del protocollo TFTP */ PDU del protocollo: sintassi astratta sconsigliata.1
20 struct RrqAndWrqMsg { char fileName ; char mode ; }; /* tipo XDR per i pacchetti RRQ e WRQ */ struct DatMsg { short blkn; char dat ; }; /* tipo XDR per il pacchetto DAT */ struct AckMsg { short blkn; }; /* tipo XDR per il pacchetto ACK */ struct ErrMsg { ErrCode errCode; char errStr ; }; /* tipo XDR per il pacchetto ERR */ PDU del protocollo: sintassi astratta sconsigliata.2
21 enum ErrCode { NOT_DEFINED = 0, /* errore non definito: vedi stringa di errore se presente */ FILE_NOT_FOUND = 1, ACCESS_VIOLATION = 2, DISK_FULL = 3, /* disco pieno o allocazione eccessiva */ ILL_OP_TFTP = 4, /* operazione tftp illegale */ UNKNOWN_PORT = 5, FILE_ALREADY_EXIST = 6, NO_SUCH_USER = 7 }; /* enumerato XDR che definisce i codici ci errore */ union TftpMsg switch (OpType opType) { case RRQ: RrqAndWrqMsgrrqMsg; case WRQ:RrqAndWrqMsgwrqMsg; case DAT:DatMsgdatMsg; case ACK:AckMsgackMsg; case ERR:ErrMsgerrMsg; }; /* tipo XDR per generico PDU TFTP tra client e server */ PDU del protocollo: sintassi astratta sconsigliata.3
22 Suggerimenti di Denis Romagnoli per rendere il codice piu leggibile: 1.wrappare la parte di network UDP dentro apposite funzioni che gestiscono linterazione con la rete e la gestione del cambio di indirizzo sul primo messaggio; 2.wrappare lutilizzo dellXDR con opportune funzioni; 3.definire una opportuna funzione per gestire il timeout. Domande di Claudio Salati: 1.Come mai nella descrizione del PDU a mappa di byte abbiamo eliminato il campo length ? 2.Fare questo esercizio utilizzando come servizio di trasporto quello stream oriented del TCP sarebbe stato un problema: perche? Vedi anche lesercizio alla fine della lezione sui socket. 3.Perche la sintassi astratta data come esempio e sconveniente da usare? Perche dico che e piena di errori anche se, provando a compilarla, rpcgen la accetta? Suggerimenti e domande
23 Per compilare la sintassi astratta dare il comando: rpcgen –C tftp.x che produce due file: tftp.h che deve essere incluso nei file sorgente del vostro programma, sia lato client che lato server. tftp_xdr.c che deve essere compilato e linkato sia al programma client che a quello server. Per la compilazione del client dare il comando : gcc –g client.c tftp_xdr.c –o client Per la compilazione del server dare il comando: gcc –g server.c tftp_xdr.c –o server Si e fatta lipotesi che i file tftp.x, client.c e server.c siano tutti nella stessa directory. Loutput della compilazione/link saranno i 2 eseguibili client e server. Generazione del codice eseguibile