Progetto di Reti: Agenti Mobili e Sicurezza
Indice
Integrità dell'agente ( di Dati e Codice)
-
Hijacking dell’Agente
- Integrità dello stato
Dividiamo i Place in due categorie
Place Sicuri:
- Place di Partenza
- Place Certificati (da una terza parte)
Place Insicuri:
- Tutti gli altri.
Ogni volta che ci dobbiamo spostare su un Place Insicuro, non ci andiamo direttamente, ma cloniamo il nostro agente e mandiamo il clone. Sul Place Insicuro non si fanno Cambiamenti ai Dati, ma si possono aggiungere dei dati in un’area temporanea (possibilmente crittografata e firmata). Le aggiunte (ai dati) vere e proprie verranno fatte solo quando si sarà raggiunto un Place Sicuro.
Nel Place Sicuro:
- Aggiungo i dati raccolti nel Place insicuro algi altri ( a Stack)
- Firmo tutto (i dati)
Analogamente, i dati raccolti sul Place sicuro sono aggiunti agli altri, e poi firmati.
Nota: dovendo lavorare su più Place Insicuri, si può parallelizzare (lancio di più cloni in parallelo verso diversi Place).
- Integrità del Codice
Visto che dei Place sicuri ci fidiamo, ogni volta che arriviamo su un Place Sicuro controlliamo l’integrità dell’Agente (la Firma), anche quando siamo di ritorno da un Place insicuro.
Se la firma non è buona l'Agente viene eliminato.
Sicurezza della Comunicazione tra Agenti.
Comunicazione su Canale Sicuro, esclusivamente tra Agenti entrambi su Place Sicuri.
" Gestione Risorse assegnate del Server "
Nel momento in cui un Agente deve spostarsi su un Place, chiede all’Agente dei Servizi (Service Agent) la disponibilità delle risorse per Sé (per l’agente che eventualmente dovrà andare sul Place).
In caso la memoria che gli verrebbe assegnata sia insufficiente, rinuncia a muoversi verso quel Place.
In base al compito che l’agente deve portare a termine, deciderà se accontentarsi delle altre risorse o evitare quel Place (in base anche alla politica del Principal).
Quando su un Place Sicuro si ha un Agente che aspetta il ritorno di Cloni che ha mandato in altri Place (Insicuri), ed essendo il tempo a disposizione su quel Place quasi scaduto:
L’Agente nel muoversi da un Place ad un altro è crittato, quindi non può essere intercettato.
Ottimizzazioni (Varie ed Eventuali
)
Nel mandare un Clone ad un Place Insicuro, si può evitare di mandare lo stato.... (dipende dall’implementazione della primitiva di Clonazione)
- Primitive per la Gestione degli Agenti
- Supporto per la Comunicazione tra Agenti
- Sicurezza del Sistema
- Autenticazione dell'Agente (Credenziali)
- Controllo degli Accessi (nel Server)
- Disponibilità del Server
- Integrità del Server
- Metering delle Risorse e Charging
Gestione con Lista (Dinamica) della Risorse:
Handle |
Tipo |
Nome |
Cont |
Perm |
Er. Sp. – Er. Tm |
Limite |
File System |
R- W |
Cond |
Sp |
|||
Memoria |
Dup Cond |
Sp – Tm |
||||
Comunicazione |
AXS |
Cond |
Banda – Num |
|||
Cpu |
% |
|||||
MultiPresenza |
Num |
Agli Altri Tipi di Risorsa possono accedere solo i Service Agent, che le possono mettere a disposizione degli altri Agenti in modo Controllato.
Legenda:
Cont: Contatore Sp: Spazio
Perm: Permessi Tm: Tempo
Er: Eredita Cond: Condivisa (la quantità rimasta)
AXS: Accesso Dup: Duplicato
Problemi Aperti:
-
I servizi dei Server Insicuri sono A Rischio: sull'Utilizzazione delle Risorse Possono Mentire-
Non Ripudio dell'Origine: ci si fida dei Place Sicuri, mentre quelli Insicuri non hanno voce in Capitolo (quindi un caso di richieste di pagamento "dubbie", le si ignora).Implementazione
(Sicuro):
Sul server viene caricata un'applicazione Java che farà da Server per gli agenti.
L'Agent Server rimane in ascolto su una porta (predefinita), in attesa di richieste da Agenti esterni.
Il Server apre una Socket a Datagramma su una porta predefinita (Server Concorrente e non parallelo).
Quando riceve una richiesta da un Agente esterno, inizia la negoziazione:
( Il Server potrebbe avere una cache per le chiavi pubbliche degli Agenti (autenticazione)
(quando verificare la validità ? Revocazione ?) (Si potrebbe associare un TTL ad ogni chiave)
( in pratica invia una lista di interi con questo significato:
( minuti in mem (int)– num max Socket (byte) – %CPU (byte)– num max Agenti (byte) – Costo Tot (int)- num Agenti pres (byte)– last access(minuti)(int) ( 0 / 1 (caricamento delayed)(byte) - num porta Server (int) ) - un Padding per arrivare a 32 Byte)
( si potrebbe anche mandare la lista dei servizi presenti sul Server)
(in caso il Server abbia raggiunto il num max di Agenti dello stesso Principal presenti, gli manda un "segnale" di wait ( caricamento delayed) ).
Delle semplici send e receive.
Il controllo delle credenziali (identificazione e autenticazione) viene fatto usando il file Agent.res .
Ci sarà un programma esterno per editare il file, per gestire i diritti degli Agenti: sia quelli gestiti direttamente da java (con l’access controller), sia quelli gestiti dalle nostre classi.
( cioè il Server destinazione si mette in ascolto sulla porta stabilita (num porta Server), per un certo tempo, nel quale dovrebbe arrivare la richiesta di caricamento (URL del Agente (sul Server) e metodo da riattivare, tutto crittato con la chiave simmetrica ).
Appena arriva la richiesta se può caricarlo subito, lo carica, altrimenti aspetta che si liberi un posto e poi lo carica
(Vedi Schema Riassuntivo Negoziazione )Se dopo un certo tempo non arriva, il Server chiude la connessione e decrementa il contatore presenze e tutti i Contatori Risorse)
Il Server crea un Thread in ascolto sulla nuova porta.
Il Server usa il SecureClassLoader per caricare l’Agente esterno.
C’è un contatore per il Numero di Thread, per il calcolo della priorità degli Agenti.
Il Server da cui l’Agente parte, alla partenza di questo, libera le risorse, e controlla se ci sono agenti in attesa, ed eventualmente ne carica il primo. ( => il Server gestisce una lista di Agenti in attesa).
Un array di triple (Public key, URL, metodo da riattivare), e un intero (valore corrente (modulo max val)).
Il server Destinazione carica l'Agente Esterno e ne controlla l'integrità (decrittandolo).
I permessi gestiti dall'Access Controller riguardano il file system (può aprire file temporanei solo nelle directory permesse (dall’Access Controller) e nelle quantità assegnategli), e la comunicazione (numero max di connessioni).
In caso l'Agente voglia clonarsi, deve passare attraverso il Server, che lo clona (se non si è raggiunto il numero max), e aggiorna i contatori delle risorse.
Le primitive (del Server) sono realizzate come Classi nel ClassPath, così tutti riescono ad utilizzarle, bypassando l’Access Controller.
Sono le primitive stesse, al loro interno, che controllano i diritti di esecuzione da parte dell’Agente, e l’eventuale fallimento delle stesse.
Periodicamente, il server controlla il tempo di permanenza dell'Agente in memoria e la quantità di disco usata ( e cancella dal Log i record Out-of-Date).
C’è un Thread dedicato al controllo di questi parametri. In Polling, ed il periodo e lasciato alla politica dell’utente. Un ciclo For (;;) nel quale, un ciclo for (i=0; i<=MaxAgentID; i++) controlla tutti gli Agenti (confronto contatori Agenti con parametri Attuali), e poi lo mette in attesa del periodo definito dall’utente.
Il Server fa il Log degli Accessi, del consumo di risorse sottoposte al pagamento ( ed eventualmente qualcos'altro per Auditing o a scopi statistici).
L'Agent Server inoltre, mette a disposizione delle primitive ( metodi) agli Agenti esterni per la clonazione, suicidio, generazione di chiavi simmetriche, cifrazione, decifrazione e firma di dati (vedi place insicuri) e per la comunicazione tra agenti sullo stesso place (una MailBox per ogni Agente, visibile solo agli Agenti dello stesso Principal) e forwarding delle Mail, il servizio di nomi (per i Place Sicuri e Non), timer (messaggio di time out nella mailbox), o per offrire altri servizi (che possono variare da Place a Place).
Tutte queste Primitive hanno Interfacce Standard (tranne i servizi "proprietari" dei vari Server).
Tutte le primitive sono implementate come classi presenti nel ClassPath del Server, ma sono le primitive stesse ad implementare i controlli sui diritti degli Agenti (di esecuzione). (con Agent.res)
Problemi aperti:
- Controllo Banda Comunicazione: troppo pesante, quindi si mette da parte.
Variazione:
Agente:
Appena è generato, l’Agente legge da un file i parametri per inizializzare i propri contatori ( per esempio quelli di uso risorse).
Ma il principal può gestire l’Agente ed i suoi parametri con un Front End grafico in Java.
partendo dal Place del suo Principal quando vuole muoversi chiede al Server del Principal un lista (query ) di Place (Sicuri ed eventualmente Non).
Il Place del Principal può avere una lista di Place oppure può appoggiarsi ad un Name Server esterno.
Si fa generare una chiave simmetrica (one time password), la aggiunge alle credenziali e si fa crittare il tutto con la chiave pubblica del primo Place su cui vuole andare.
Poi apre una comunicazione col primo Place, per la negoziazione: gli manda il pacchetto con le credenziali, la chiave ed il Flag=0 (negoziazione normale) (tutto crittato) come richiesta di connessione.
Un Semplice Datagramma UDP. (Nota post – implementazione: si usa la primitiva di send )
(Vedi Figura Riassuntiva Negoziazione)
Se le risorse disponibili per lui sul server (dalla risposta di connessione) fossero sufficienti ( almeno un canale di comunicazione per poter fare richieste ad altri server, la memoria sufficiente per se stesso ( requisiti minimi per poter lavorare e spostarsi su un altro place), ed eventualmente dei servizi che gli servono ( in base alla politica del Principal) ), annuncia al Server (su cui si trova) di doversi spostare (passandogli AgentID, indirizzo e porta dell’altro server, chiave simmetrica e metodo da riattivare ), e quindi il server lo critta con la chiave simmetrica e manda all’altro Server l’URL da cui prelevare l’Agente con il metodo da riattivare.
Quindi rimane nel Server finché dall'altra parte non arriva la richiesta di caricamento ( o scade il Time - Out, nel qual caso l'Agente viene "spacchettato" e avvisato del time out (mediante l’esecuzione del metodo "standard per gli errori"), lasciandolo in esecuzione per il tempo rimanente (concessogli in precedenza)).
Il Server di Partenza gestisce la terza fase della Negoziazione. L’Agente chiama un metodo dell’Agent Server, ed è quest’ultimo che si occupa di gestire il tutto.
Questo metodo, inoltre è un try/catch per il contatore di time – out.
Arrivato dall'altra parte (nel nuovo place), dopo tutti i controlli è rimesso in esecuzione con un certo metodo stabilito dall’Agente prima della partenza.
Ci deve essere un metodo che viene eseguito in caso di problemi, passandogli il codice d'errore ( come nel caso precedente di time out )
Sul nuovo Place l'Agente potrebbe voler mandare un Agente su un Place insicuro:
prima si fa generare un valore casuale (Alias), e l’aggiunge al "pacchetto" con le credenziali, e si fa cifrare questo pacchetto con la chiave pubblica del Server stesso (servirà quando lo Slave vorrà "tornare" su questo Place per "mandare" i dati al Master, che l’ha generato), quindi inizia la negoziazione col Place insicuro, e se va a buon fine, chiede al server di farsi clonare ( genera uno Slave) e di mandare lo Slave al Place voluto, e di mettere in esecuzione lo Slave con un certo metodo.
( Ovviamente lo Slave deve avere in una variabile l’indirizzo del Place Sicuro di partenza)
Poi si fa decrittare il "pacchetto" e conserva il valore casuale, con il quale si fa creare un Alias di Mail dal Server.
(Uso la chiave simmetrica della negoziazione per crittare l’Agente)
Il Server ha un TTL associato ad ogni Alias, che il Thread ci controllo Risorse verifica periodicamente.
Quando ha finito di lavorare, o dopo aver esaurito i contatori di uso risorse (inizializzati dal Principal), rimane in attesa della risposta dallo Slave (clone), controllando la MailBox.
L’Agente ha vari contatori inizializzati dal Principal: spesa massima (pagamento risorse e servizi) e per il max mun di Place sui quali passare (ttl), quantità max di dati che può raccogliere su un Place (?).
Il server gli comunica il Time-Out (ovviamente un certo tempo prima) con un messaggio nella MailBox, e quindi l’Agente ripete la procedura di clonazione e di Copia su un altro place e attiva la copia.
Poi lascia nel log del Server un messaggio con il nuovo indirizzo (per il forward della Mail) ed il numero di Alias, e infine si suicida.
La Copia continuerà il lavoro nello stesso modo del primo Agente (quindi diventa il nuovo Master).
La comunicazione tra Server è Agente è realizzata tramite la MailBox dell’Agente.
E’ quindi compito dell’Agente controllare periodicamente la MailBox.
Quando lo Slave, alla fine del suo lavoro, vuole mandare dei dati al Master, apre la negoziazione col Place si Provenienza, e manda il pacchetto crittato in precedenza ( con le credenziali ), più un pacchetto con i dati da spedire al Master, crittato con la chiave Privata del Place di partenza.
Il pacchetto dati è composto da: URL, Oggetto(dati).
(l’URL ci servirà per decrittare i dati (con la chiave pubblica associata a quell’URL))
( in Realtà nell’Ottimizzazione finale, si manda solo il pacchetto di negoziazione con l’indirizzo (URL) dello slave, sarà il Server destinazione a fare la recv del pacchetto dati)
E quindi lo Slave si suicida.
Alla fine di tutto il suo lavoro( o alla fine delle risorse che poteva "spendere"), l'Agente Master (chiunque esso sia, a questo punto), torna sul server del Principal e gli consegna i dati.
NB: l’Agente in ogni istante sa quanto gli è rimasto da spendere, perché gli Slave non possono spendere niente ( o meglio sui Place Insicuri possono spendere quello che vogliono, tanto non pagano), ed in ogni istante, si assume che l’Agente Master sia unico, altrimenti prima della clonazione bisogna decrementare i contatori fino al valore che si vuol dare al Clone, poi clonarsi, e rimettere a posto i contatori scalando dai valori originari quelli dati al Clone (cioè si "spartiscono le risorse").
Il tempo può essere visto come una risorsa da gestire => controllo.
Associata ad ogni richiesta di una risorsa c’è anche il controllo sulla risorsa stessa.
Per la gestione del tempo si può usare il Timer del Server che alla scadenza lascia un messaggio nella mailbox.
Questa gestione del tempo è "a scalare", ed è molto imprecisa.
Si potrebbe anche implementare sul server la gestione del tempo con "beat" (il tempo unico di Internet, proposto da Negroponte). In questo modo il controllo sarebbe sull’orario, e non sul tempo rimanente.
In questa implementazione dell’Agente, comunque, si farà sempre riferimento al l’ora rispetto il GMT (+0), cioè il Server convertirà l’ora locale in ora del GMT.
Soluzione al Problema della consegna dei dati raccolti dallo Slave, al Master :
( nella negoziazione FLAG==0 indica negoziazione normale; gli altri valori sono disponibili per gli Alias) ( MailBox associata al numero ).
Un Metodo dell’Agent Server ci permette di creare un valore di Alias ed associarlo alla nostra MailBox
Quando arrivano dei dati per quell’Alias, questi vengono copiati sulla mailbox dell’Agente (se è presente, altrimenti si fa il forwarding).
( per passare i dati ad un altro Place, inizia la negoziazione col Place successivo passando lo stesso pacchetto, ma stavolta crittato con la chiave pubblica del Place destinatario )
E’ il Server che fa tutto il lavoro: alla richiesta di consegna mail, l’Agent Server, nel caso in cui l’Agente non sia presente sul Place, crea un nuovo Thread che si occupa della consegna del messaggio
C’è un max mun di Place che il Master attraversa lasciando nel log il riferimento di forward, oltre il max, non lascia più riferimenti, e quindi i pacchetti vengono persi.
Così il pacchetto con le credenziali può essere utilizzate Solo per mandare un messaggio ( e non per spostarsi), e solo una volta.
( Anche se il sistema così potrebbe essere soggetto ad attacchi a forza bruta, provando tutti i possibili valori del campo numerico, fino a trovare lo zero (crittato) ).
Due tipi di credenziali => due coppie diverse di chiavi pubbliche – private. (Place Sicuri e Non)
Tutto questo Overhead potrebbe sembrare molto pesante, in realtà è proporzionato al numero di Place Insicuri che vogliamo visitare, e quindi è più che giustificato.
( l’Overhead compare solo nel momento in cui mandiamo uno Slave su un Place Insicuro)
Ottimizzazione:
Solo il pacchetto di negoziazione arriva fino al Place del Master. Da questo si estrae indirizzo e porta del Place mittente (cioè dello Slave) e si richiede direttamente da questo il pacchetto dati.
( cioè si risponde alla richiesta, mandando la porta (tre interi) del nuovo thread in attesa dei dati)
Il Master, quando si sposta su un nuovo Place deve mandare al Place precedente un Pacchetto di tipo nextAlias, coiè dice al vecchio Place qual è il suo Alias sul nuovo Place.
Questione aperta :
Nuovi Obiettivi:
Invece di Autenticarsi (nella Negoziazione) con la Propria Chiave Pubblica (firmata con la Privata), si potrebbe Autenticare con la chiave pubblica (firmata dalla privata) di un Ente Certificatore che così funge da Principal (Sicuro).
In questo caso però, l’Agente si deve portare dietro la propria chiave pubblica (firmata con la privata), per la crittazione dei dati raccolti.
Modifiche ed Adattamenti Finali
Quello che in questa relazione è stato chiamato AgentID diventerà UniqueID: un valore (int) che identifica univocamente un Agente su un Place.
C’è una tabella di corrispondenze UniqueID – AgentID.
Nell’implementazione sono state trascurate alcune delle cose presenti nel progetto come esposto in questa relazione:
Possiamo scomporre l’implementazione, in vari moduli:
Primitive e Classi.
- byte[] cypher (byte[] Packet, Key key)
- byte[] decypher (byte[] Packet, Key key)
- byte[] sign (byte[] Packet, Key key)
- boolean verify( byte[] Packet, byte[] Sign, Key ) - Key createKey() // chiave simmetrica
Con Key == NULL si usa la chiave del Place corrente.
- UniqueID Clone( Key key, byte[] sign)
- void kill (int UniqueID, Key key, sign)
- int Alias(Key key, byte[] sign)
- void setNextPlace(Alias, byte[4] Address, Key, byte[] sign)
Scrive nel file di log il nuovo Alias ( o l’indirizzo del NextPlace), che il Thread di Negoziazione andrà a Gestire.
- int Send (byte[] Packet, InetAddr To, int Port, int localPort, Key key, byte[] sign)
- byte[] Recv( int port, int TOut, Key key, sign)
- int getPort(Key key, byte[] sign)
- int SendMbox( byte[] Packet, InetAddr To, int Alias, int localPort, int TOut, key, byte[] sign, Key simmKey, myAlias)
Send Sincrona. Receive Bloccante, con TimeOut (secondi).
La SendMBox (Bloccante con TimeOut) manda il pacchetto in due fasi diverse: prima fase Negoziazione, poi aspetta un numero di porta e vi manda il resto.
- time_t Time()
byte[3] time_t {
byte hours; // 0-24 time[0]
byte minutes; // time[1]
byte seconds; // time[2]
}
Tutte le primitive ritornano –1 in caso di permesso negato (SecurityExcpt).
Lato Server:
Creazione Thread in ascolto sulla porta predefinita (per la negoziazione) che processa le richiesta sequenzialmente secondo il protocollo.
Gestisce anche i messaggi verso le MailBox interne, e l’eventuale forwarding verso altri Place.
(1) Invio del
Pacchetto di Negoziazione al Thread Negoziatore.(2) Ricezione del
Pacchetto di Risposta dal Thread Negoziatore.(3a) Richiesta di Caricamento (Caso Flag == 0).
(3b) Invio del Messaggio relativo all’Alias di Mail ( Caso Flag <> 0 ).
Il Pacchetto di Negoziazione ha questo formato:
Next contiene il numero di pacchetti da 1k che arriveranno per l’Alias.
From contiene l’indirizzo del mittente il pacchetto per l’Alias.
Il Pacchetto di Risposta ha questo formato:
( Vedi Codice Negoziatore.java )
Lato Agent:
Semplici Send – Receive (Primitive Server).
( La Negoziazione è "abilitata" solo se c’è il thread in ascolto. Sta quindi all’Agente, in caso di non risposta da un Server, tentare con il caricamento delle versioni precedenti dell’Agente, che restano comunque valide).
Lato Agente:
Contatori:
time_t ReturnTime;
int MaxMoney; // Dollars or Euro ? (contatore a scalare)
int MaxPlaces; // che può attraversare (cont. a scalare)
Lato Server:
Valori Max dei contatori letti dal file
Agent.res e Agent.res.Default .Controllo "Dinamico" :
Thread dedicato al controllo periodico dell’impegno Risorse.
Controllo "Statico" :
Primitive controllano ( usando i valori max di Agent.res) se continuare o fallire.
Access Controller per gestire l’I/O sul file system.
Per l’accesso alle altre risorse bisogna passare attraverso le primitive del Server.
Il Log:
I campi del Log valgono 24 ore (circa).
Il Thread di gestione risorse, periodicamente elimina i campi "Out of Date".
I file Agent.res e Agentr.res.default
Il file Agent.res contiene i valori (istantanei) delle risorse rimaste agli Agenti identificati dalla Public key.
I contatori vengono decrementati dal Thread gestore risorse (minuti in memoria), dal Thread Negoziatore (all’arrivo di un Agente: minuti in memoria, numero Agenti), e dalle primitive di Alias (numero alias) e getPort (numero porte).
Tutti gli accessi al file Agent.res sono escusivi ( risorsa critica).
Il file Agent.res.default contiene i valori iniziali per un Agente sconosciuto al Place, ed ovviamente vengono inizializzato dal gestore del Place.
Invece il file Agent.res.sturtup contiene i valori di inizializzazione per Agent.res, anche in caso il Server cada.
Il Sistema è composto dai seguenti file:
- Negoziatore.java : classe del Thread che gestisce la Negoziazione e l’Alias (lato Server). Gestisce inoltre varie tabelle per uso interno.
- AliasManager.java: classe del Thread che gestisce la ricezione del pacchetto dati per un Alias interno. (classe di uso interno (Negoziatore))
( anche questa è una classe di uso interno) (avviata da Negoziatore).
- logManager.java: classe per la gestione del Log. (ad uso interno).
- AgentresManager.java: classe per la gestione dei file Agent.res e Agent.res.default. (ad uso interno)
- cryptoPrimitive.java: primitive crittografiche a disposizione degli Agenti.
- commPrimitive.java: primitive di comunicazione per gli Agenti.
- aliasPrimitive.java: primitive per la gestione di un Indirizzo di Alias.
- agentPrimitive.java: primitive per la gestione degli Agenti (creazione, distruzione e migrazione).
- timePrimitive.java: primitiva per avere il tempo del sistema. (GMT +0)
Overhead introdotto dai Meccanismi di Sicurezza
I benchmark per le primitive crittografiche possono essere riassunti in questa tabella:
Ci sono dei risultati anomali, come nel caso della decrittazione RSA, o nei valori troppo elevati mel caso TriploDes.
Infatti nell’implementazione finale delle primitive si è preferito usare il DES ECB (la versione più semplice), principalmente per questioni di velocità, ma anche perché nel nostro caso il triploDES non è Indispensabile.
Nei vari casi (ad eccezione della Decrittazione RSA, che rimane un mistero), si nota un "effetto soglia", ovvero un valore di partenza (del tempo) che anche con un pacchetto piccolo (1K) non è trascurabile.
Ovviamente i risultati dipendono dall’implementazione dell’IAIK.
Nel caso della Negoziazione, ad esempio, l’overhead totale introdotto dalla crittazione dei pacchetti sarebbe:
( tenendo conto che il DES è ALMENO tre volte più veloce del 3DES)
( bisogna sempre tener conto della "soglia" )
( anche nel caso di 100K l’RSA non va oltre i 660 msec, quindi il DES sarà sicuramente al di sotto di quel valore)
Quindi il tempo totale nella Negoziazione, speso per crittare/decrittare può variare da mezzo secondo ad un secondo, al variare delle dimensioni dell’Agente.
Il che può essere non trascurabile, visto anche che a questo va sommato anche l’overhead di comunicazione e di scheduling che può raggiungere vari secondi.
C’è da chiedersi se valga la pena usare questi meccanismi, nonostante l’overhead.
Tenuto conto che un Agente potrebbe "restare in giro" per dei tempi superiori alle decine di minuti, questo overhead sembra ACCETTABILE.