Relazione - Università di Bologna
Transcript
Relazione - Università di Bologna
PERMESSO (PERsistent MESSaging in ad hOc networks) Ermete Gaudenzi – matr. 0000231758 Corso di laurea specialistica in Ingegneria Informatica Università di Bologna Reti di Calcolatori LS – Prof. Antonio Corradi – A.A. 2005-06 Referente progetto: Eugenio Magistretti Gabicce Mare, 30-01-2007 Abstract I servizi di messaggistica istantanea rappresentano oggi un rilevante campo applicativo, soprattutto grazie alla notevole espansione che si ha avuto nel loro utilizzo (basti pensare agli innumerevoli client quali MSN, ICQ, AIM, che nel giro di pochi anni hanno preso prepotentemente piede). Il fine ultimo di tali applicazioni può essere molteplice: da un lato infatti l’obiettivo è essenzialmente quello di comunicare con altri utenti della rete che utilizzano lo stesso client; utenti che possono essere amici, conoscenti, colleghi di lavoro; non solo quindi situazioni di svago, ma anche possibilità concreta da parte di un’azienda di far comunicare tra loro dipendenti di uffici diversi. Tali servizi, così come sono pensati, necessitano per forza di cose di un’infrastruttura per la gestione delle comunicazioni, e quindi la presenza di un componente aggiuntivo (quale ad esempio un server). Allo stesso tempo è necessario un collegamento a internet per poterne usufruire. Quello che si vuole realizzare con PERMESSO è un sistema in grado di garantire messaggistica istantanea tra utenti appartenenti ad una stessa MANET wireless (Mobile Ad-hoc NETwork) senza bisogno di un’infrastruttura di servizio (che come tale ovviamente rappresenterebbe un costo aggiuntivo). Introduzione Quello che vogliamo realizzare con questo progetto è un servizio di messaggistica istantanea (d’ora in avanti, chat) utilizzabile in Mobile Ad hoc NETworks (MANET), reti wireless che possono essere utilizzate da dispositivi come laptop, PDA e smart phone, o più in generale da dispositivi che presentino almeno un’interfaccia 802.11. Per come viene concepito il servizio quindi non è richiesta connessione internet né alcun tipo di supporto infrastrutturale (come ad esempio degli access point), semplicemente la rete viene generata automaticamente quando almeno due dispositivi entrano nel raggio di funzionamento delle rispettive schede wireless. È ovvio quindi che tali reti, proprio per loro stessa natura, sono molto dinamiche e altamente variabili nel tempo. Il tutto viene quindi gestito direttamente dai singoli terminali (o, si veda successivamente nel paper, al più da un server) che possono così autonomamente entrare nella rete, scambiarsi messaggi e uscire. In particolare, per quanto riguarda lo scambio di messaggi, ci vengono richieste due tipologie comunicative (per i dettagli si rimanda alle sezioni successive): • chatting sincrono, nel quale i due host interessati allo scambio di messaggi sono contemporaneamente presenti all’interno della stessa MANET; • chatting asincrono; in questo caso uno dei due host è momentaneamente offline e per questo motivo bisognerà realizzare un meccanismo in grado di inoltrare il messaggio non appena il destinatario diventerà nuovamente raggiungibile all’interno della MANET. Ovviamente, così come avviene nei “classici” programmi di chat, è possibile inviare un messaggio a qualcuno solamente se è presente nella nostra “lista amici”: per amicizia si intende un legame biunivoco che lega due specifici host, legame che si instaura a fronte di una richiesta (e conseguente conferma) e che può essere interrotto in qualsiasi momento. Il recapito dei messaggi nel caso di chatting asincrono può avvenire in modo autonomo da parte degli host oppure mediante un'infrastruttura di servizio, denominata persistent server. Nel primo caso i messaggi da recapitare si spostano da host in host cercando di rimanere su chi è online nella rete. Nel secondo caso invece vengono mandati direttamente al server che si prende la responsabilità di inoltrarli. Si è scelto di non adottare alcuna misura riguardo alla raggiungibilità di rete per i motivi sopra evidenziati (mancanza di standard e non portabilità). Pertanto si suppone che tutti gli host appartenenti alla MANET siano raggiungibili fra loro. Come estensione futura si potrebbe aggiungere un protocollo di routing come livello di rete intermedio, situato al si sotto di quello di PERMESSO senza modificarne il funzionamento. In seguito sono approfonditi alcuni aspetti sulla rete PERMESSO di carattere generale, per poi scendere nel dettaglio delle scelte di progetto e terminare con alcune informazioni di base sull'implementazione. Identificazione degli host Considerazioni generali Raggiungibilità di rete Una delle caratteristiche delle MANET è la non completa raggiungibilità fra gli host. E' possibile per esempio che tre host A B C siano disposti spazialmente in modo tale che B vede gli altri due e gli altri due vedono solo B. Inoltre si possono muovere cambiando la condizione di raggiungibilità nel tempo. Questo problema è complesso da gestire in quanto occorre introdurre un protocollo che permette di monitorare la rete nel tempo e calcolare i percorsi migliori per l'instradamento dei dati. Purtroppo non esistono ancora standard definitivi sull'argomento e l'organizzazione IETF si sta prendendo cura di definirli. In attesa dello standard definitivo sono stati proposti molti protocolli che si possono suddividere in due gruppi principali: reactive e proactive. I reactive si propongono di trovare un percorso valido solo quando necessario, cioè quando ci sono pacchetti da trasmettere. Il vantaggio consiste nel basso uso della rete in caso di inattività mentre gli svantaggi sono il ritardo introdotto dal discovery e il traffico generato di conseguenza. I protocolli proactive invece mantengono sempre le informazioni per l'instradamento al costo di un continuo uso della rete per il discovery e la distribuzione delle tabelle di instradamento. Attualmente esistono implementazioni in C/C++ di alcuni protocolli con anche un'interfaccia Java, tuttavia non sono facilmente portabili su cellulari e palmari in quanto si basano su librerie native. Gli host devono essere in grado di riconoscersi fra loro. Una prima soluzione potrebbe essere di riconoscerli in base all'indirizzo IP, ma è scomoda perchè introduce un vincolo forte a livello di rete. Avendo migliaia di utenti occorrono migliaia di IP, a prescindere dal numero di client connessi in un dato istante. Una soluzione più promettente è quella di assegnare ad ogni host un identificativo univoco e usare quello per riconoscerlo. In questo modo l'indirizzo di rete del dispositivo diventa irrilevante. Rimane il problema dell'assegnazione degli identificativi: per ogni nuovo client si deve garantirne l'univocità. A tale scopo si potrebbe introdurre una fase di elezione dove sono gli altri ad assegnare l'ID oppure fare in modo che ognuno si generi il proprio in modo il più possibile casuale per diminuire le collisioni. Nel primo caso non è detto che l'elezione dia risultati positivi in quanto la scelta dipende da tutti gli altri host esistenti, anche quelli attualmente offline. In entrambi i casi quindi è una scelta probabilistica. Generare un identificativo localmente assumendo che sia univoco è molto più semplice e meno costoso rispetto ad un protocollo di elezione; in altre parole è più conveniente. Occorre fare in modo che sia il più possibile casuale e stabilirne una lunghezza adeguata. A tal scopo esiste lo standard UUID (Universally Unique Identifiers) che fornisce le specifiche per generare un numero di 128bit unico. L'ideale sarebbe generarlo tenendo conto dell'indirizzo MAC, cosa che però non è possibile su piattaforma J2ME perchè tale informazione è inaccessibile. Una possibile scelta ricade dunque su UUID random-based. Probabilità di collisione dell'ID La probabilità di collisione di due ID generati casualmente è calcolabile con la teoria del paradosso dei compleanni. Tale teoria evidenzia che anche in un gruppo piccolo di 23 persone la probabilità che due di loro festeggino il compleanno lo stesso giorno è molto alta, circa il 50%. Nel nostro caso abbiamo un insieme di n host, uno spazio di x possibili ID e la probabilità di collisione p. La formula esatta di p(n,x) è troppo complessa da calcolare per grandi numeri di x o di n. p n , x=1− p n , x 1 2 n−1 p n , x =1⋅1− ⋅1− ⋅⋅1− x x x x⋅ x−1⋅⋅ x −n1 x! = n p n , x = n x x ⋅ x−n! Esiste tuttavia una formula approssimata più adatta alla computazione. 2 p n≈1−e −n 2⋅x Il seguente grafico mostra la probabilità di collisione in funzione del numero di bit dell'ID e del numero di host presi in esame. Il numero di possibili ID è x=2bits . Per mortivi di chiarezza grafica log10(p) viene mostrato ugualmente anche per p=0. futuri; questo influenza notevolmente i conti. Supponiamo un numero di host pari a 1.000.000, per mantenere la probabilità intorno a 1E-10 basterebbero 72bit. Un UUID random-based ha 122 bit casuali su 128, 50bit (~6 byte) al di sopra del caso precedente, con una probabilità di collisione inferiore a 1E-15. Considerando che gli UUID sono standard e l'overhead introdotto è minimo si è optato per questa soluzione. Autenticazione In assenza di un sistema centralizzato di accounting per autenticare correttamente gli utenti emergono notevoli problemi. Nel modello client/server è il server a gestire un sistema di riconoscimento per esempio con nome utente e password. Ad ogni connessione il client deve autenticarsi ed ogni messaggio dal/al singolo client passa tramite il server che in un certo senso lo certifica. Nel modello peer-to-peer questo non è possibile perchè non vi è alcun servizio che certifica l'identità dei vari host. Per esempio se ogni host firmasse i propri messaggi con un codice univoco gli altri host lo conoscerebbero e potrebbero facilmente copiarlo per emettere messaggi a nome suo. Si potrebbe introdurre un sistema di firme digitali con crittografia asimmetrica per risolvere questo problema: ogni host memorizza la chiave pubblica degli altri host e controlla la loro identità mediante uno scambio di tipo challenge-response. Tuttavia occorre tener presente che la computazione è molto onerosa per un dispositivo portatile a batteria e che la piattaforma J2ME non integra tali funzionalità. L'unico modo per realizzarle sarebbe di basarsi su una libreria esterna nativa con relativa interfaccia Java, rinunciando però alla completa portabilità. Per questi motivi si è scelto di non introdurre particolari misure di sicurezza per l'autenticazione degli host. Riservatezza dei dati Illustration 1: Probabilità di collisione ID degli host In un caso reale gli host appartenenti alla stessa MANET difficilmente supererebbero quota 1.000. Tuttavia un host può muoversi da una rete all'altra nel tempo e quindi occorre considerare tutti gli host di tutte le reti: passati, presenti e Per quanto riguarda la riservatezza dei messaggi scambiati, un utente malintenzionato potrebbe modificare l'applicazione, o scriverne una ad-hoc, per esempio per mostrare all'utente il contenuto dei messaggi altrui memorizzati sul proprio dispositivo, oppure per modificarli. L'unico modo per evitare ciò è introdurre anche qui funzionalità di crittografia che, per i medesimi motivi evidenziati sopra, non abbiamo realizzato. nella ricerca per alias; contiene la stringa da cercare e il tipo di ricerca (match esatto o parziale) Progetto Comunicazione fra host Le specifiche richiedono esplicitamente uno scambio di messaggi basato sul protocollo UDP. La piattaforma J2ME con MIDP 2.0 mette a disposizione tali funzionalità attraverso le classi Datagram e UDPDatagramConnection. Occorre definire un protocollo di comunicazione per il formato dei datagrammi e la semantica di comunicazione. Considerando che ci sono diversi tipi di messaggi, che questi possono essere inoltrati tramite terzi e che si vuole introdurre il concetto di ordinamento causale, si è giunti alla definizione della struttura di un messaggio, denominato pacchetto, con la seguente struttura: • service: tipo di servizio • senderID: ID del'host mittente • receiverID: ID dell'host destinatario • timestamp: informazione necessaria per gestire l'ordinamento I pacchetti si possono suddividere in due gruppi principali: quelli che necessitano di cure particolari per il recapito offline e quelli che possiamo permetterci di perdere. E' chiaro che è importante che tutti i pacchetti arrivino a destinazione ma per alcuni di essi è più importante che per altri. • QUERY_ALIAS_RESPONSE: risposta alla ricerca per alias; contiene l'alias completo del client che risponde • FRIENDSHIP_ASK: richiesta amicizia; necessita di recapito offline • FRIENDSHIP_YES: conferma positiva di amicizia; necessita di recapito offline • FRIENDSHIP_NO: conferma negativa di amicizia; necessita di recapito offline • FRIENDSHIP_END: notifica di fine amicizia; necessita di recapito offline • FREE_MEMORY_ASK: inviato in broadcast in assenza del persistent server per richiedere la quantità di memoria libera degli altri host • FREE_MEMORY_RESPONSE: risposta alla richiesta di memoria libera; contiene questa informazione • FORWARD: contiene altri pacchetti che necessitano di recapito offline; usato per inoltrarli tramite terzi; necessita di recapitato offline di Segue una descrizione dei tipi di pacchetti usati. Alcuni di essi si riferiscono a funzionalità analizzate in seguito o nelle relazioni degli altri componenti del gruppo. Per ciascuno di essi è anche indicato se necessita di cure per il recapito. • JOIN_NETWORK: inviato in broadcast al momento di ingresso nella rete • LEAVE_NETWORK: inviato in broadcast al momento di uscita dalla rete • HOST_ONLINE: notifica a un host appena entrato che siamo presenti online • TEXT_MESSAGE: messaggio di testo fra due client; contiene il testo e la data/ora di invio (utile per i test); necessita di recapito offline • DUMMY: comunica la porta di rete di invio del mittente; usato durante l'apertura di una conversazione • QUERY_ALIAS: inviato in broadcast Illustration 2: Diagramma degli stati di un pacchetto Dato che ogni host è identificato dal suo ID anzichè dal suo indirizzo di rete, si suppone che al momento di invio di un pacchetto il campo senderID contenga l'ID dell'host che lo manda fisicamente. Questa considerazione potrebbe sembrare banale ma è di fondamentale importanza per la gestione del recapito dei messaggi offline, gestiti unicamente mediante i FORWARD. A livello locale ogni client associa uno stato ad ogni pacchetto per ricordarsi come lo deve trattare. I possibili stati sono sei: • CREATED: appena creato • SEND_WAIT: tutti i dati del pacchetto sono stati preparati ed è pronto per l'invio • SEND_COMPLETE: è stato inviato nella rete il datagramma UDP corrispondente • PROCESS_WAIT: appena ricevuto, in attesa di essere processato • PROCESS_COMPLETE: correttamente • DROPPED: c'è stato qualche errore, per esempio il pacchetto era inatteso si può risalire al suo host ID • Alias locale, modificabile • Stato: uno dei 5 possibili stati La relazione di amicizia è di tipo biunivoco, ovvero o entrambi sono amici oppure non si conoscono. Fra due client A e B nel momento in cui A decide di terminare l'amicizia rimuovendo B dalla sua rubrica, glielo comunica all'altro che completa l'operazione rimuovendo A dalla sua. processato Rete dal punto di vista del client Ogni host ha la propria visione della rete a cui sta partecipando, ha la sua rappresentazione degli altri host e delle informazioni ad essi associate: • ID di rete PERMESSO • stato (online, offline) • indirizzo IP di rete, se online • porta UDP per la conversazione, se instaurata Un host viene posto in stato online alla ricezione di un qualsiasi pacchetto proveniente da lui e viene posto offline alla ricezione di un LEAVE_NETWORK. Ogni client conosce sempre tre host speciali: quello locale, il broadcast e il persistent server. L'host locale è trattato in modo identico agli altri con la differenza che è sempre online. Anche il broadcast è sempre online ed ha ID fisso e indirizzo di rete non modificabile. Il persistent server ha anch'esso ID fisso come il broadcast. Relazione di amicizia Dal punto di vista di un client un amico è caratterizzato dalle seguenti informazioni: • Host al quale è associato, tramite il quale Illustration 3: Diagramma degli stati di un amico Quando due client vogliono instaurare una relazione di amicizia devono conoscersi: il client A effettua una ricerca per alias e sceglie B in base alle risposte che gli giungono dagli host attualmente online. A questo punto A invia una richiesta di amicizia a B, che la mostra all'utente in attesa di conferma. Quando l'utente di B ha deciso cosa fare, B manda ad A una conferma positiva o negativa e l'amicizia si instaura di conseguenza. Se la conferma è positiva B aggiunge immediatamente A come amico ed A aggiunge B quando la riceve. Se invece è negativa si torna allo stato iniziale prima della ricerca. Ovviamente ogni client deve ricordarsi tutte le richieste di amicizia inviate e ricevute. Nell'implementazione attuale al momento di invio o ricezione di una richiesta di amicizia viene aggiunto un amico temporaneo in rubrica in uno dei due stati di non-confermato, ovvero richiestainviata e richiesta-ricevuta. Alla ricezione o invio della conferma di amicizia questo amico viene eliminato se la conferma è negativa, oppure il suo stato viene aggiornato opportunamente. Messaggi e conversazioni I messaggi di testo mostrati all'utente sono indipendenti dai pacchetti che li trasportano nella rete, pertanto sono da gestire separatamente. Un messaggio di testo è così formato: disconnette dalla rete. Nella nostra implementazione attuale la conversazione sincrona di rete è gestita in accordo con le specifiche (un thread dedicato per ogni conversazione) ma l'interfaccia grafica presenta tutti i messaggi insieme, in modo analogo a come un telefono cellulare mostra gli SMS ricevuti. All'inizio di una conversazione sincrona l'host A che vuole inviare il primo messaggio crea internamente un gestore associato ad una porta UDP casuale e manda il messaggio tramite esso verso la porta di default del destinatario B. A quel punto B si accorge che ha ricevuto un messaggio da A ad una porta diversa da quella di default e crea a sua volta un gestore interno sempre associato ad una porta casuale. Infine esso provvede a notificare immediatamente ad A la sua porta locale inviando un pacchetto di tipo DUMMY da essa. La conversazione è ora instaurata e tutti i messaggi futuri verranno inviati nelle nuove porte che i due host si sono scambiati. Al momento di uscita dalla rete di uno dei due la conversazione viene automaticamente chiusa da entrambi. • sender: amico mittente • receiver: amico destinatario • localTime: data/ora di ricezione locale • sendTime: data/ora di invio; notare che gli orologi dei client non sono sincronizzati • text: corpo del messaggio Recapito dei pacchetti offline • unread: messaggio ricevuto ma non ancora letto • unsent: messaggio in coda di invio ma non ancora inviato Dato che i messaggi di testo sono pacchetti e che ci sono altri tipi di pacchetti che necessitano di recapito offline, si è scelto di gestirlo a livello di pacchetto. Occorre notare che uno dei due campi fra sender e receiver è il client locale, che viene gestito come se fosse un amico non appartenente alla rubrica. I campi sendTime, localTime, unread e unsent sono facoltativi e sono stati introdotti per completezza, per dare qualche informazione in più all'utente. Per limitare l'utilizzo di memoria è stato imposto un limite al numero di messaggi memorizzabili sia in ingresso che in uscita, superato il quale viene eliminato il messaggio più vecchio per lasciar spazio a quello nuovo. Due amici possono scambiarsi messaggi di testo in modo sincrono o asincrono. Nel primo caso A manda un messaggio a B che è però offline e il delivery viene gestito di conseguenza. Nel secondo caso invece sono entrambi online e si instaura una conversazione diretta. Essa termina automaticamente quando uno dei due client si Se l'host destinatario è offline ci sono due possibili scenari, con e senza persistent server. Se c'è il persistent server il pacchetto viene inoltrato a lui tramite un FORWARD e il client poi se ne dimentica. Nel caso che nemmeno il server sia presente il client si tiene il messaggio in locale in attesa che il destinatario arrivi online oppure che l'utente decida di lasciare la rete. In quest'ultimo caso viene effettuato un discovery sulla memoria libera degli altri host attraverso i pacchetti FREE_MEMORY_ASK e FREE_MEMORY_RESPONSE e vengono inviati i pacchetti in sospeso, in stato SEND_WAIT, all'host con più spazio libero disponibile. Il client sa quanta memoria libera ha l'host destinatario e si regola in modo tale da non eccedere questa quota. I pacchetti rimanenti vengono inviati al secondo candidato in ordine di spazio libero e così via. Dall'altro lato il client ricevente apre il FORWARD e aggiunge i pacchetti al suo interno nella propria memoria in stato SEND_WAIT. In caso non ci sia abbastanza memoria per salvarli vengono automaticamente scartati quelli più vecchi, facendo riferimento al timestamp. Suddivisione in package • permesso: interfacce della libreria accedere alle funzionalità offerte • Il persistent server Il persistent server ha come unico scopo quello di raccogliere i pacchetti da inoltrare che gli vengono mandati e restare in attesa che i destinatari vengano online. A tal fine deve mantenere nella sua memoria interna un gran numero di pacchetti. Generalmente si suppone che il persistent server sia sempre presente all'interno della rete, tuttavia nel caso che venga attivato in presenza di altri host, quando questi si accorgono della sua presenza dal suo pacchetto di JOIN gli mandano tutti i loro pacchetti in attesa di inoltro, delegando a lui la responsabilità di recapito. Questa operazione potrebbe causare la congestione della rete e per evitarlo è stato introdotto un ritardo casuale fra il momento in cui il client si accorge della presenza del server e l'invio del pacchetto di FORWARD. • • per lcdui: interfaccia grafica di esempio • contact: gestione della rubrica • message: gestione dei messaggi • server: GUI del server util: utilità varie come logging, quick-sort, generazione UUID, gestione dei task stud.retils.permesso: implementazione delle interfacce definite nel package permesso • io: serializzazione dei dati su data stream • net: tutto ciò che riguarda la gestione della comunicazione di rete • host: gestione della visione della rete dal punto di vista locale • packet: gestione dei pacchetti Architettura logica Il diagramma mostra l'architettura riassunta dei componenti realizzati nel prototipo. Implementazione Organizzazione generale Come organizzazione generale del codice si è scelto di utilizzare il pattern MVC con le classi J2ME come View, una libreria di interfacce Java come Model e gestione dell'interfaccia grafica come Controller. In altre parole l'interfaccia grafica da noi realizzata è il cliente di una libreria che gestisce le funzionalità del client PERMESSO, presentandole come insieme di interfacce Java. Gli obiettivi raggiunti con questa architettura sono molteplici: dalla corretta divisione delle responsabilità alla facile suddivisione del lavoro. Inoltre abbiamo ottenuto anche la separazione fra definizione delle funzionalità offerte e loro implementazione e l'offuscamento di tutte le funzionalità di gestione interna, aumentando la chiarezza ed eliminando problemi derivati dal loro abuso da parte dei clienti della libreria: l'interfaccia grafica. Illustration 4: Diagramma architetturale dei componenti L'area verticale evidenziata in giallo mostra lo stack per la comunicazione di rete. L'area orizzontale evidenziata in rosso rappresenta il livello di astrazione dei pacchetti dai datagrammi. I componenti in azzurro sono quelli principali usati dai clienti della libreria per accedere alle sue funzionalità. (de)serializzazione dei pacchetti PERMESSO da/a stream binari • PacketFactory: gestisce la creazione dei pacchetti • PacketStore: permette di memorizzare i pacchetti nella memoria permanente del dispositivo • Help: comprende il supporto alla serializzazione generica di classi, il logging, la gestione della configurazione permanente e altre utilità di tipo verticale Segue la descrizione delle responsabilità dei singoli componenti. • GUI: presenta all'utente le funzionalità della libreria PERMESSO • ClientMidlet: midlet di avvio del client, inizializza Client e la GUI • ServerMidlet: midlet di avvio del server, inizializza Server e la GUI del server • Client: componente di accesso alle funzionalità del client. Gestisce la ricerca degli host per alias e l'integrazione fra ContactList e MessageManager • Server: componente di accesso alle funzionalità del server. Permette l'acesso ad alcune informazioni come i messaggi da inoltrare e gli host di rete conosciuti • ContactList: gestisce la rubrica di un client • Friend: rappresenta un amico in rubrica • MessageManager: gestisce i messaggi di testo di un client in ingresso e in uscita • TextMessage: rappresenta un messaggio di testo • Host: rappresenta un host della rete • Connection: gestisce la logica del protocollo PERMESSO. Fa da intermediario fra Client o Server e il Router. • PacketRouter: gestisce l'invio/ricezione dei pacchetti in modo centralizzato, gestisce le conversazioni • PacketDispatcher: wrapper di PacketConnectionUdp che integra un thread di ricezione • • PacketConnectionUdp: astrae dalle classi J2ME una socket UDP con I/O orientato a pacchetti PERMESSO PacketSerializer: si occupa della I componenti qui evidenziati non corrispondono direttamente alle classi Java realizzate. In particolare Connection e PacketRouter sono in realtà sdoppiati in due versioni, una per il client e una per il server. PacketConnectionUdp è realizzata in modo tale da consentire l'introduzione di connessioni TCP come sviluppo futuro. Per ogni altro chiarimento sull'implementazione attuale si veda direttamente il codice, ampiamente commentato. Permanenza dei dati La permanenza dei dati nella memoria del dispositivo è gestita tramite le funzionalità offerte dal J2ME, ovvero i record store e la PIM. Fra i vari depositi di dati permanenti troviamo la configurazione, l'elenco dei messaggi, l'elenco dei pacchetti e l'elenco degli amici. La memorizzazione avviene tramite le utility di serializzazione dati (package stud.retils.permesso.io). Gli amici possono anche essere salvati tramite le API della PIM, se disponibili, creando nuovi contatti e salvando le informazioni necessarie nel campo NOTE. Conclusione Il progetto realizzato copre tutti i casi richiesti nelle specifiche e realizza in più l'identificazione degli host tramite ID e l'ingresso e uscita del persistent server nella MANET. I punti di forza di questo progetto sono: • dinamicità degli indirizzi IP degli host; essendo riconosciuti in base al loro ID • astrazione a pacchetti introdotta; la comunicazione è indipendente dal trasporto di rete usato • architettura modulare; aumenta gli scenari d'uso, semplifica le future estensioni, predispone al test automatizzato dei componenti I punti di forza del prototipo sono: • realizzazione quasi completa delle funzionalità; per realizzare l'applicazione finale si può partire dal prototipo ed estenderlo • corretta suddivisione delle responsabilità fra le classi • codice di servizio verticale scritto in modo il più possibile indipendente dal resto per favorire la riusabilità • tutti i parametri operativi significativi sono configurabili; alcuni a tempo di compilazione, come timeout e numero massimo di pacchetti inoltrabili mediante un FORWARD; altri sono modificabili a runtime come il numero massimo di messaggi di testo e la porta di rete Dall'altro lato della medaglia l'architettura modulare ha portato ad un aumento di complessità: il prototipo realizzato è computazionalmente più pesante da eseguire in confronto a soluzioni più essenziali e ugualmente funzionanti. Sviluppi futuri Per quanto riguarda la parte grafica si potrebbe migliorare notevolmente quella esistente ed implementare la gestione delle conversazioni. Da notare che la GUI è solo uno dei possibili clienti della libreria, è possibile come estensione futura scrivere dei BOT, proporre interfaccie grafiche alternative o integrare la libreria in un progetto più ampio. Per la parte di rete sarebbe opportuno aumentare la separazione fra PacketRouter e Connection spostando la gestione di tutti i pacchetti dentro quest'ultima. Inoltre si potrebbe sollevare PacketRouter dalla gestione dei dispatcher e incaricare di ciò la connessione o addirittura il Client. Infine resta da implementare la trasmissione con ACK per evitare la perdita di pacchetti dovuta alla rete, in quanto con il codice attuale l'applicazione risente pesantemente della qualità della rete sottostante. La duplicazione dei pacchetti da inoltrare e l'eliminazione dei duplicati ricevuti non è implementata e sarebbe una funzionalità chiave da aggiungere per risolvere il problema della caduta di un nodo. Bibliografia • Documento delle specifiche di progetto • Documentazione di J2ME, MIDP e CLDC • http://en.wikipedia.org/wiki/Birthday_paradox: analisi delle collisioni fra host ID • http://www.opengroup.org/onlinepubs/962939 9/apdxa.htm: per le specifiche sugli UUID • http://www.ietf.org/html.charters/manetcharter.html: protocolli di routing su MANET