La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Lez. 91 Reti di Calcolatori XDR - eXternal Data Representation Vedi: SunSoft, Network Interfaces Programmer's Guide, app. A e B, pagg. 291-352. RFC 1014,

Presentazioni simili


Presentazione sul tema: "Lez. 91 Reti di Calcolatori XDR - eXternal Data Representation Vedi: SunSoft, Network Interfaces Programmer's Guide, app. A e B, pagg. 291-352. RFC 1014,"— Transcript della presentazione:

1 Lez. 91 Reti di Calcolatori XDR - eXternal Data Representation Vedi: SunSoft, Network Interfaces Programmer's Guide, app. A e B, pagg RFC 1014, External Data Representation Standard, RFC 1057, RPC: Remote Procedure Call Protocol Specification – Version 2, Copyright © by Claudio Salati. Alma Mater Studiorum - Universita' di Bologna Sede di Cesena II Facolta' di Ingegneria

2 2 XDR is a standard for the description and encoding of information. Description Abstract Syntax, equivalente di ASN.1 OSI Encoding Transfer Syntax, equivalente di BER OSI Quindi XDR definisce Sia una notazione per la definizione di sintassi astratte (ASN) cioe una notazione per la definizione delle strutture informative scambiate tra i moduli di una applicazioni distribuita cioe una notazione per la definizione di protocolli applicativi Sia un sintassi di trasferimento capace di codificare in una sequenza di byte le strutture informative definite utilizzando la notazione astratta XDR la rappresentazione concreta di rete puo quindi essere trasmessa al pari e da questo decodificata Che cosa e'?

3 3 Definito da Sun, vedi RFC 1014, External Data Representation Standard, Utilizzato da Sun per la definizione dellASE Sun RPC: vedi RFC 1057, RPC: Remote Procedure Call Protocol Specification – Version 2, per la definizione dellASE Sun NFS (Network File System): vedi RFC 1094, NFS: Network File System Protocol Specification, (poi aggiornato fino a RFC 3530, Network File System (NFS) version 4 Protocol, 2003) Riferimenti

4 4 In quanto ASN, XDR definisce un linguaggio per descrivere delle strutture informative. N.B. Il linguaggio serve solo per descrivere strutture dati (informazioni), non per definire operazioni (istruzioni): non e' un linguaggio di programmazione. L'alternativa di utilizzare mappe di byte, se si devono definire protocolli complessi, diventa velocemente impraticabile. Anche lalternativa di definire protocolli tramite stringhe di caratteri non e felice (vedi SMTP e HTTP). XDR, in quanto sintassi di trasferimento, si basa sulle seguenti ipotesi: I byte (gli ottetti) sono portabili e costituiti di una sequenza di 8 bit (hp.: ordine dei bit nel byte uniforme su tutte le macchine). I byte sono scambiati in modo comprensibile tra nodi della rete. Che cosa e'?

5 5 La sintassi di trasferimento definita da XDR non e' di tipo TLV. L'informazione di tipo non e' mai trasportata esplicitamente. Cio' implica che il ricevente deve conoscere a priori il tipo della struttura informativa che sta ricevendo (come accade ad esempio anche per i protocolli IP, TCP e UDP!). L'informazione di lunghezza e' trasportata esplicitamente solo quando cio e necessario. Per rendere possibile tutto cio' si evitano campi opzionali o default e strutture dati disordinate (presenti in ASN.1). Campi opzionali sono comunque possibili utilizzando il costruttore union e il tipo void. E evidente che e sempre possibile fare finta che una struttura dati ordinata (e.g. un array) rappresenti un valore di tipo non- ordinato (e.g. un insieme). XDR TRANSFER SYNTAX.1

6 6 La sintassi di trasferimento e' descritta attraverso mappe di byte. Ogni encodifica ha lunghezza multipla di 4 byte. Se una encodifica non e' fisiologicamente di lunghezza multipla di 4, XDR prescrive che essa venga paddata a destra con dei byte nulli. Il padding con un valore ben definito consente il confronto corretto di informazioni tramite confronto tra i byte corrispondenti delle loro rappresentazioni | byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | BLOCK | | | | >| XDR TRANSFER SYNTAX.2

7 7 L'approccio XDR si basa sulla definizione di una rappresentazione canonica (di rete) per ogni tipo di dato da trasmettere. Ad esempio: Viene definito un ordinamento canonico dei byte (big-endian). Viene definita una rappresentazione canonica per i numeri interi (quella binaria, complemento a due). Viene definita una rappresentazione canonica dei numeri reali (quella IEEE).... In questa maniera qualunque trasmettitore che utilizza XDR puo' inviare una stessa informazione a qualunque ricevitore XDR trasmettendo la stessa stringa di byte. Esiste un caso in cui questo modo di procedere e' inefficiente: quando sia il trasmettitore che il ricevitore sono little-endian. XDR TRANSFER SYNTAX.3

8 8 Non e specificata da XDR CORBA specifica invece la rappresentazione locale dellinformazione in C++ per il suo IDL Specificata dal singolo sistema di programmazione XDR, e.g. rpcgen di Sun per C: Specifico sistema di programmazione XDR-C Specifico sistema di programmazione XDR-Java Specifico sistema di programmazione XDR-... Definisce le strutture dati locali (specifiche dellambiente di programmazione) tramite le quali i tipi di dato XDR sono (devono essere) rappresentati concretamente in un modulo del programma distribuito Rappresentazione concreta locale dellinformazione

9 9 Tipi semplici: [unsigned] int e hyper int float, double e quadruple enum (enumerazioni, e in particolare bool ) opaque string void Tipi composti: array struct union Tipi di dato XDR

10 10 Il tipo int implementa (sintassi astratta) la nozione di intero con segno nel range La rappresentazione canonica (sintassi di trasferimento) di un int e' In notazione complemento a due. Su 4 byte. Big-endian. Una variabile di tipo int e' dichiarata come in C: int identifier; Il tipo unsigned int implementa (sintassi astratta) la nozione di intero senza segno nel range La rappresentazione canonica (sintassi di trasferimento) di un valore di tipo unsigned int e' In notazione binaria. Su 4 byte. Big-endian. Una variabile di tipo unsigned int e' dichiarata come in C: unsigned int identifier; Tipi XDR semplici: int e unsigned int

11 11 XDR definisce anche tipi interi (con e senza segno) con range di valori piu esteso e che sono rappresentabili su 8 byte, chiamandoli [ unsigned ] hyper int. La rappresentazione canonica di un [unsigned] hyper int e' l'ovvia estensione di quella del corrispondente tipo intero In notazione complemento a due o binaria a seconda che l'intero sia con o senza segno. Su 8 byte. Big-endian. Una variabile di tipo [unsigned] hyper int e' dichiarata come in C: hyper int identifier; unsigned hyper int identifier; N.B.: XDR non definisce interi con sizeof di 1 o 2 byte! Tipi XDR semplici: hyper int e unsigned hyper int

12 12 Tipi XDR semplici: tipi interi (MSB) (LSB) |byte 0 |byte 1 |byte 2 |byte 3 | INTEGER (MSB) (LSB) |byte 0 |byte 1 |byte 2 |byte 3 | UNSIGNED INTEGER (MSB) (LSB) |byte 0 |byte 1 |byte 2 |byte 3 |byte 4 |byte 5 |byte 6 |byte 7 | HYPER INTEGER UNSIGNED HYPER INTEGER

13 13 Sono definiti due tipi che rappresentano sottoinsiemi di numeri reali, basati sulle seguenti sintassi di trasferimento: float, basato sulla rappresentazione IEEE a 32 bit. double, basato sulla rappresentazione IEEE a 64 bit. quadruple, basato sulla rappresentazione IEEE double extended precision. Una variabile di tipo reale e' dichiarata come in C, e.g.: float identifier; double identifier; Notare che le notazioni IEEE per i numeri floating-point consentono anche di esprimere i seguenti "valori": infinito con segno (overflow) numero denormalizzato (underflow) NaN (not a number), che pero' e' definito come system dependent e non puo' quindi essere utilizzato tra sistemi diversi. Tipi XDR semplici: float e double

14 14 E' possibile definire enumerazioni di valori simbolici. Sintassi astratta: Le enumerazioni rappresentano effettivamente sottoinsiemi di numeri interi con segno ( int ), e ogni valore simbolico dell'enumerazione e' associato ad un valore intero univoco. Una variabile di tipo enumerato ( enum ) e' definita nel modo seguente (come in C): enum { symbolName = constant,... } identifier; Esempio: enum { RED = 2, BLUE = 3, GREEN = 5 } colours; La variabile colours puo' assumere solo uno dei valori interi listati nell'enumerazione. Sintassi di trasferimento: la rappresentazione canonica (o encodifica) di un valore enumerato e' identica a quella di un intero con segno. Tipi XDR semplici: enumerati

15 15 Un particolare tipo di enumerazione e' rappresentato dal tipo booleano ( bool ). Sintassi astratta: Il tipo booleano ammette due soli valori: FALSE e TRUE. Una variabile di tipo bool e' definita nel modo seguente: bool identifier; Questa definizione e' equivalente alla seguente enum { FALSE = 0, TRUE = 1 } identifier; Sintassi di trasferimento: La rappresentazione canonica di un valore booleano e' identica a quella di un enumerato (un booleano e uno specifico enumerato) e quindi a quella di un intero con segno. N.B.: la rappresentazione canonica di rete XDR di un bool e diversa dalla rappresentazione concreta locale C di un booleano. Tipi XDR semplici: booleani

16 16 A volte due programmi devono scambiarsi dei dati (byte) non- interpretati. Si e' gia' visto come questo sia tipico delle architetture di comunicazione layerizzate (ln+1PDU, cioe lnSDU, e un dato non interpretato per il layer n, e quindi compare come tale nellnPDU). In ASN.1 questo tipo di dati e' rappresentato attraverso il metatipo ANY o attraverso il tipo EXTERNAL. Sintassi astratta: Questo tipo di dati in XDR e' chiamato opaco ( opaque ), ed e' costituito da una sequenza ordinata di byte. XDR consente di definire sia dati opachi di lunghezza fissa che dati opachi di lunghezza variabile. Una variabile che rappresenta un dato opaco di lunghezza fissa n (byte) e' definita nel modo seguente: opaque identifier [ n ]; // lunghezza fissa Tipi XDR semplici: dati opachi.1

17 17 Sintassi astratta (continua): Una variabile che rappresenta un dato opaco di lunghezza indefinita e' definito nel modo seguente: opaque identifier ; // di lunghezza // indefinita ma // limitata a n o opaque identifier ; // di lunghezza // indefinita // (limitata a ) Nel primo caso n rappresenta la dimensione massima (upper bound della lunghezza) del dato opaco. Anche nel secondo caso il dato opaco ha comunque una dimensione massima, pari a Ogni istanza (valore) di questo tipo ha comunque lunghezza definita. Tipi XDR semplici: dati opachi.2

18 18 Sintassi di trasferimento: L'encodifica di un dato opaco di lunghezza fissa n e' costituita dalla sequenza degli n ottetti (byte). Se n non e' multiplo di 4 la sequenza di ottetti e' paddata con un epilogo di allineamento di byte nulli di lunghezza L'encodifica di un dato opaco di lunghezza variabile e' costituita di due parti: dall'encodifica dell'intero senza segno (4 byte) che ne indica la lunghezza (non paddata), secondo le regole di encodifica XDR del tipo unsigned int, seguita dalla sequenza di ottetti non interpretati, eventualmente paddata con byte nulli. Tipi XDR semplici: dati opachi.3

19 19 Tipi XDR semplici: dati opachi | byte 0 | byte 1 |...|byte n-1| 0 |...| 0 | | | | | | FIXED-LENGTH OPAQUE | length n |byte0|byte1|...| n-1 | 0 |...| 0 | | | | | | | VARIABLE-LENGTH OPAQUE

20 20 E' possibile definire stringhe di caratteri ASCII di lunghezza indefinita (tipo string ). Queste stringhe non sono null-terminated come in C (ma, naturalmente, se le stringhe utilizzate nel programma sono quelle normali del C, non conterranno alcun carattere '\0' ): la loro lunghezza dovra quindi essere indicata esplicitamente. Una variabile che rappresenta una stringa di caratteri ASCII e' definita in uno dei modi seguenti (sintassi astratta): string identifier ; // di lunghezza indefinita // ma limitata a n string identifier ; // di lunghezza indefinita // (limitata a ) Tipi XDR semplici: stringhe di caratteri ASCII

21 21 Tipi XDR semplici: : stringhe di caratteri ASCII Sintassi di trasferimento: l'encodifica di una stringa di caratteri ASCII e' uguale a quella di una sequenza di dati opachi di lunghezza indefinita | length n |byte0|byte1|...| n-1 | 0 |...| 0 | | | | | | | STRING

22 22 E' possibile definire vettori omogenei di qualunque tipo di elementi, sia di lunghezza definita che di lunghezza indefinita. Il tipo degli elementi del vettore puo' essere sia semplice che composto. Anche se tutti gli elementi del vettore sono dello stesso tipo, non necessariamente devono avere la medesima dimensione (e.g., vettori di stringhe ASCII di lunghezza indefinita) Una variabile che rappresenta un vettore e' definita in uno dei modi seguenti (sintassi astratta): base-type identifier [n]; // lunghezza fissa base-type identifier ; // lunghezza indefinita // ma limitata a n base-type identifier ; // lunghezza indefinita // (limitata a ) Tipi XDR composti: array

23 23 Tipi XDR composti: array Sintassi di trasferimento: L'encodifica di un vettore e' simile a quella di una analoga sequenza di dati opachi. In caso di lunghezza indefinita l'intero iniziale indica il numero di elementi del vettore | element 0 | element 1 |...| element n-1 | | | FIXED-LENGTH ARRAY | n | element 0 | element 1 |...|element n-1| | | | COUNTED ARRAY

24 24 Una variabile che rappresenta una struttura ( struct, sequenza ordinata eterogenea di componenti, semplici o composti) e' dichiarata nel modo seguente (sintassi astratta): struct { component-declaration-1; component-declaration-2;... } identifier; dove ogni component-declaration assume la forma di una dichiarazione di variabile. Sintassi di trasferimento: L'encodifica di una struttura e' formata dalla sequenza delle encodifiche dei suoi componenti, nello stesso ordine in cui essi compaiono nella dichiarazione. L'encodifica di ogni componente e' di lunghezza multipla di 4 byte, ma diversi componenti possono ovviamente avere diversa lunghezza. Tipi XDR composti: strutture (record)

25 25 La variabile punto1 rappresenta un punto del piano attraverso le sue coordinate cartesiane: struct { double x;double y; } punto1; La variabile punto2 rappresenta un punto del piano attraverso le sue coordinate polari: struct { double ro;double teta; } punto2; La variabile complex1 rappresenta un numero complesso attraverso il valore delle sue parti reale e immaginaria: struct { double re;double im; } complex1; Tipi XDR composti: esempi di struttura (record)

26 26 Esercizio 1: Quale e la sintassi di trasferimento di valori di questi tipi/variabili? Esercizio 2: E possibile distinguere tra loro sintassi di trasferimento di questi diversi tipi? Esercizio 3: E possibile distinguere la sintassi di trasferimento di questi tipi da quella di un array di double di lunghezza fissa di 2 elementi? Tipi XDR composti: esercizi

27 27 Una unione discriminata ( union ) e' un tipo composto da un campo discriminante seguito da un secondo campo di un tipo scelto tra un insieme predefinito di possibilita' in base al valore del campo discriminante. Il tipo del campo discriminante deve essere int, unsigned int o un enumerato (compreso bool ). Ogni opzione relativa al secondo campo, detta arm, e' preceduta dal valore del discriminante che la seleziona. Una variabile che rappresenta una unione discriminata e' dichiarata nel modo seguente: union switch (discriminant-decl) { case discriminant-value-1 : arm-declaration-1; case discriminant-value-2 : arm-declaration-2;... default : default-arm-decl; } identifier; Tipi XDR composti: unioni discriminate.1

28 28 La keyword case e' seguita da un valore legale del discriminante. La dichiarazione del discriminante e degli arm ha la forma di una dichiarazione di variabile. L'arm default e' opzionale: esso e significativo quando il valore del discriminante e diverso da quello che identifica gli altri arm. Se l'arm default non e' presente, il campo discriminante di un valore legale deve avere uno dei valori listati come selettori degli arm. Sintassi di trasferimento: L'encodifica di una unione discriminata e' formata dalla sequenza della encodifica del discriminante e di quella dell'arm selezionato dal valore del discriminante. L'encodifica di ogni arm e quella del discriminante sono di lunghezza multipla di 4 byte, ma diversi arm possono ovviamente avere diversa lunghezza. Tipi XDR composti: unioni discriminate.2

29 29 La variabile saldoContabile fornisce il valore del saldo del conto corrente in diverse valute: union switch (int valuta) { case 0 : double euro; case 1 : double dollar; case 2 : double yen; default : struct { string valuta<>; double ammontare; } altraValuta; } saldoContabile; Esercizio: definire saldoContabile utilizzando un enumerato come campo discriminante. Esercizio: quale e la rappresentazione canonica (sintassi di trasferimento) del valore della variabile saldoContabile ? Se saldoContabile vale 5 euro? Se saldoContabile vale 5 dollari? Se saldoContabile vale 5 lire sterline? Tipi XDR composti: esempio di unione discriminata

30 30 Tipi XDR composti: strutture e unioni | component A | component B |... STRUCTURE | discriminant | implied arm | DISCRIMINATED UNION | |

31 31 XDR supporta una notazione per indicare assenza di un valore. L'assenza di un valore e' indicata dal tipo void, che ha un range di valori ammessi vuoto. Il tipo void e' utile per specificare funzioni che non hanno alcun parametro in ingresso o che non ritornano alcun risultato (nelle RPC, come in C standard). void puo' essere anche usato in una unione discriminata per indicare la non disponibilita' di un valore significativo come secondo campo, o per estendere il range di un altro tipo con il valore "non- definito". La dichiarazione di un void ha la seguente forma: void; L'encodifica (sintassi di trasferimento) di un void e' nulla (0 byte). Tipi XDR semplici: void

32 32 La variabile saldoContabile fornisce il valore in euro del saldo del conto corrente se il dato e' disponibile: union switch (bool disponibile) { case TRUE : double euro; case FALSE : void; } saldoContabile; Esercizio: quale e la rappresentazione canonica (sintassi di trasferimento) della variabile se il saldo non e disponibile? Esercizio: ci sono altri tipi XDR oltre a void la cui sintassi di trasferimento e nulla (ha cioe lunghezza 0 byte)? Tipi XDR semplici: esempio d'uso di void

33 33 ASN.1 definisce una notazione per specificare non solo tipi di dati ma anche i relativi valori. XDR non fornisce strumenti per esprimere valori a livello di sintassi astratta! In XDR e possibile esprimere dei valori solo in termini di sintassi di trasferimento. Notare che una volta noto a priori il tipo del valore ricevuto, la lunghezza della sua codifica e anchessa o nota a priori o indicata esplicitamente nella sintassi di trasferimento. Meglio: a livello di sintassi astratta XDR offre possibilita molto limitate per esprimere valori. XDR value notation e costanti simboliche

34 34 A livello di sintassi astratta lunica sintassi dei valori prevista consente di esprimere solo numeri interi. E anche possibile assegnare un nome simbolico ad un valore intero attraverso la seguente dichiarazione const constant-identifier = n; // n e la sintassi dei valori XDR per gli interi, // e.g. 5 Dove n deve essere un numero (literal) intero (eventualmente con segno) espresso in notazione decimale. Una costante simbolica puo essere utilizzata in un testo XDR ovunque potrebbe essere utilizzato il corrispondente valore numerico (e.g. dimensione di vettore o valore discriminante in un arm) const dozzina = 12; uomo quella_sporca[dozzina]; XDR value notation e costanti simboliche

35 35 Si e parlato di come dichiarare variabili in XDR, ma in effetti la dichiarazione di variabili in XDR non ha alcun significato! XDR serve per definire una interfaccia (il protocollo tra due pari) e, come negli header file C, in un file di interfaccia non ha senso definire delle variabili, ma solo dei tipi! (btw, attenzione alla distinzione in C tra dichiarazione e definizione!) E tanto piu in quanto due processi remoti non possono condividere variabili! (in realta nei sistemi distribuiti per lautomazione industriale …) Caso mai interesserebbe avere a disposizione una adeguata sintassi dei valori. Lo statement typedef, del tutto analogo a quello del C, anche dal punto di vista della sintassi, consente di associare un identificatore ad una definizione di tipo. Definizione di tipi utente: typedef

36 36 Considerando la definizione typedef declaration; (dove declaration ha la sintassi di una dichiarazione di variabile) essa associa al tipo descritto nella declaration lidentificatore dichiarato nella declaration stessa. typedef egg eggbox[6];// esempio 1 definisce eggbox come sinonimo di un vettore di 6 egg. eggbox non e in alcun modo distinguibile da qualunque altro vettore di 6 egg. typedef struct {// esempio 2 double x; double y; } punto; N.B.: dal punto di vista della sintassi di trasferimento un eggbox non e nemmeno distinguibile da una struct composta da 6 egg. Definizione di tipi utente: typedef

37 37 Nella definizione di tipi struct union enum esiste una sintassi alternativa alluso di typedef, analoga a quella utilizzata per la definizione dei nomi-tag del C. In questo caso pero, non ce alcuna differenza semantica tra un nome-tag e un nome-typedef. Le due seguenti definizioni di tipo sono quindi completamente analoghe: typedef enum { FALSE = 0, TRUE = 1 } bool; enum bool { FALSE = 0, TRUE = 1 }; La seconda sintassi e pero considerata preferibile (tradizione). Definizione di tipi utente: typedef

38 38 Optional-data is one kind of union that occurs so frequently that we give it a special syntax of its own for declaring it. It is declared as follows: type-name *identifier; This is equivalent to the following union: union switch (bool opted) { case TRUE: type-name element; case FALSE: void; } identifier; It is also equivalent to the following variable-length array declaration, since the boolean opted can be interpreted as the length of the array (le due encodifiche sono indistinguibili!): type-name identifier ; Dati opzionali.1

39 39 Optional-data is not so interesting in itself, but it is very useful for describing recursive data-structures such as linked-lists and trees. For example, the following defines a type stringlist that encodes lists of arbitrary length strings: struct *stringlist { string item<>; stringlist next; }; The optional-data type also has a close correlation to how recursive data structures are represented in languages such as C by use of pointers. In fact, the syntax is the same as that of the C language for pointers. Dati opzionali.2

40 40 stringlist could have been equivalently declared as the following union: union stringlist switch (bool opted) { case TRUE: struct { string item<>; stringlist next; } element; case FALSE: void; }; or as a variable-length array: struct stringlist { string item<>; stringlist next; }; Dati opzionali.3

41 41 Anche se dal punto di vista della sintassi di trasferimento puo non esserci differenza tra luso di strutture dati ricorsive e quello di dati opzionali, dal punto di vista della rappresentazione concreta una grossa differenza ce. Luso di dati opzionali, come indicato anche dalla notazione sintattica, si traduce in strutture dati locali linkate. Utilizzando dati opzionali e possibile rappresentare in XDR e trasferire sulla rete strutture dati come liste linkate, alberi, grafi. Dati opzionali.4

42 Applicazioni distribuite RPC-based RPC-based specific application protocol RPC protocol entity Transport Service User application RPC-based specific application protocol RPC protocol entity Transport Service User application RPC Layer RPC protocol

43 43 Esempi di protocolli specifici RPC-based: RFC 1094: NFS (Network File System) NIS / YP RFC 1057: Port Mapper RPC protocol: Binding (collegamento) dellinterfaccia remota Implementazione delle istruzioni di call e return RPC-based specific application protocol: Binding dellinterfaccia remota (tramite RPC protocol entity) Binding della singola procedura remota Un/marshaling dei parametri di input/output della singola procedura remota Invocazione della procedura remota XDR e utilizzato per definire sia il protocollo RPC che i singoli protocolli applicativi specifici RPC-based. Applicazioni distribuite RPC-based

44 44 struct rpc_msg { unsigned int xid; // transaction identifier union switch (msg_type mtype) { case CALL: call_body cbody; case REPLY: reply_body rbody; } body; }; The xid of a REPLY message always matches that of the initiating CALL message. NB: The xid field is only used for clients matching reply messages with call messages or for servers detecting retransmissions; the service side (il chiamato) cannot treat this id as any type of sequence number. enum msg_type { CALL = 0, REPLY = 1 }; Protocollo Sun RPC versione 2(RFC 1057).1

45 45 struct call_body { unsigned int rpcvers; // must be ==2 unsigned int prog; // binding info unsigned int vers; // binding info unsigned int proc; // binding info opaque_auth cred; // authen. info opaque_auth verf; // authen. info // procedure specific parameters start here }; Cosa significa start here? Qui l rpc_msg e finito! Qui e alla fine dell rpc_msg ! A questo punto e chiaro che un messaggio di chiamata di RPC e in realta composto di 2 parti: 1.Un rpc_msg 2.Il parametro di ingresso in forma encodificata Discorso analogo varra ovviamente anche per il messaggio di ritorno da RPC. Protocollo Sun RPC versione 2(RFC 1057).2

46 46 Il call_body sarebbe stato definito meglio come struct call_body { unsigned int rpcvers; // must be ==2 unsigned int prog; // binding info unsigned int vers; // binding info unsigned int proc; // binding info opaque_auth cred; // authen. info opaque_auth verf; // authen. info opaque arg<>;// input parameter }; I parametri di ingresso della procedura sarebbero cioe descritti meglio come opaque arg<>; In questo modo il messaggio di chiamata di RPC coinciderebbe con l rpc_msg. Esercizio: Si, ma cosa significa implementativamente start here dal punto di vista dellinterazione chiamante-chiamato? Protocollo Sun RPC versione 2(RFC 1057).2

47 47 Perche questa strana definizione del messaggio di chiamata di RPC e dell rpc_msg ? Per ragioni di efficienza (siamo negli anni 80 dello scorso secolo e i byte e il tempo di calcolo sono sono ancora preziosi). La definizione opaque arg<>; implica che vengano trasmessi in rete (e processati) comunque almeno 4 byte (perche?) anche se il parametro di ingresso dellRPC e assente. Non solo: la definizione opaque arg<>; avrebbe implicato in ricezione una doppia decodifica del campo parametro, con una ricopiatura e conseguente necessita di allocazione di memoria (Esercizio: spiegare cosa succederebbe). Tutto cio e evitato dalla definizione del parametro di ingresso come semplice place holder. Almeno, si sarebbe potuto scrivere, come in reply_body, opaque arg[0]; (questa notazione evita i problemi di cui sopra, ma rimane comunque solo un place holder) Protocollo Sun RPC versione 2(RFC 1057).2

48 48 enum auth_flavor { AUTH_NULL = 0, AUTH_UNIX = 1, AUTH_SHORT = 2, AUTH_DES = 3 /* and more to be defined */ }; struct opaque_auth { auth_flavor flavor; opaque body ; }; Protocollo Sun RPC versione 2(RFC 1057).2

49 49 union reply_body switch (reply_stat stat) { case MSG_ACCEPTED: accepted_reply areply; case MSG_DENIED: rejected_reply rreply; } reply; enum reply_stat { MSG_ACCEPTED = 0, MSG_DENIED = 1 }; union rejected_reply switch (reject_stat stat) { case RPC_MISMATCH: struct { unsigned int low; unsigned int high; } mismatch_info; case AUTH_ERROR: auth_stat stat; }; Protocollo Sun RPC versione 2(RFC 1057).3

50 50 enum reject_stat { RPC_MISMATCH = 0, // RPC version number != 2 AUTH_ERROR = 1 // can't authenticate caller }; enum auth_stat { AUTH_BADCRED = 1, // bad credentials (seal broken) AUTH_REJECTEDCRED = 2, // client must begin new session AUTH_BADVERF = 3, // bad verifier (seal broken) AUTH_REJECTEDVERF = 4, // verifier expired or replayed AUTH_TOOWEAK = 5 // rejected for security reasons }; Protocollo Sun RPC versione 2(RFC 1057).4

51 51 struct accepted_reply { opaque_auth verf; union switch (accept_stat stat) { case SUCCESS: opaque results[0]; // proc-specific results start here // (N.B. qui e la fine dellrpc_msg) case PROG_MISMATCH: struct { unsigned int low; unsigned int high; } mismatch_info; default: void; // Void. Cases include PROG_UNAVAIL, // PROC_UNAVAIL, and GARBAGE_ARGS. } reply_data; }; Protocollo Sun RPC versione 2(RFC 1057).5

52 52 enum accept_stat { SUCCESS = 0, /* RPC executed successfully */ PROG_UNAVAIL = 1, /* remote hasn't exported program */ PROG_MISMATCH = 2, /* remote can't support version # */ PROC_UNAVAIL = 3, /* program can't support procedure */ GARBAGE_ARGS = 4 /* procedure can't decode params */ }; Protocollo Sun RPC versione 2(RFC 1057).5'

53 53 XDR definisce: Un linguaggio per specificare sintassi astratte. Una sintassi di trasferimento. XDR non definisce: Una sintassi dei valori. Una regola per la rappresentazione concreta locale (e.g. in linguaggio C) di una sintassi astratta. Piu in generale, XDR non definisce alcuna API standard che consenta di accedere alla funzionalita di syntax matching. N.B.: Corba IDL definisce una API standard (cioe anche la rappresentazione concreta locale dellinformazione e standardizzata) ma non una sintassi dei valori ASN.1 non definisce una API standard ma definisce una sintassi dei valori In XML Schema sintassi dei valori e sintassi di trasferimento coincidono Rappresentazione concreta locale e supporti XDR

54 54 Esistono diversi sistemi di programmazione XDR: XDR-C XDR-Java Sistema di programmazione standard XDR-C: Una libreria di base: XDR library per la de/codifica dei tipi base e dei costruttori di tipo e per laccesso a strutture dati di de/serializzazione. Un compilatore (rpcgen, orientato al linguaggio C) per generare automaticamente le procedure di de/codifica per una qualunque sintassi astratta user defined specificata in XDR. basato sulluso della libreria di base. Un sistemi di programmazione XDR-C definisce le rappresentazioni concrete C dei tipi base e dei costruttori di tipo definiti da XDR. Perche sarebbe importante la standardizzazione della rappresentazione concreta locale? Perche consentirebbe la portabilita dellapplicazione tra diversi sistemi di programmazione XDR per uno stesso linguaggio target. Rappresentazione concreta locale e supporti XDR

55 55 The XDR library enables you to write and read arbitrary C constructs consistently. The XDR library can do this because it has filter routines for strings (null-terminated arrays of bytes), structures, unions, and arrays. Using more primitive routines, you can write your own specific XDR routines to describe arbitrary data structures, including elements of arrays, arms of unions, or objects pointed at from other structures. The structures themselves may contain arrays of arbitrary elements, or pointers to other structures. Ma in realta le procedure di de/codifica per i tipi user defined di una sintassi astratta sono generate dal compilatore rpcgen. Il supporto XDR di base: la XDR library

56 56 La XDR library si compone di due parti: Un insieme di funzioni filtro per eseguire la codifica fra un valore tipizzato in rappresentazione concreta locale C e lo stesso valore in rappresentazione canonica di rete XDR decodifica fra un valore tipizzato in rappresentazione canonica di rete XDR e lo stesso valore in rappresentazione concreta locale C N.B.: le funzioni filtro si occupano anche della deallocazione di memoria dinamica utilizzata nelle rappresentazioni locali per tutti i tipi primitivi e i costruttori di tipo definiti dal linguaggio XDR. Un insieme di funzioni per manipolare degli XDR stream, cioe' delle strutture dati di interfaccia verso strutture di memoria o di I/O a stream di byte da cui leggere o su cui scrivere i dati serializzati in formato canonico di rete XDR. Il supporto XDR di base: la XDR library

57 57 XDRstream, funzioni filtro, de/codifica encodifica Rappresentazione concreta locale dellinformazione decodifica XDR stream Funzioni filtro

58 58 XDRstream in memoria centrale XDR stream buffer len pos Parte del buffer gia utilizzata pos x_op

59 59 La maggior parte delle funzioni filtro della libreria, e tutte le funzioni di filtro eventualmente aggiunte, offrono uno stesso tipo di interfaccia. Se il tipo XDR ha nome xxx, la relativa funzione filtro ha il seguente prototipo: #define bool_t int #define TRUE 1 #define FALSE 0 bool_t xdr_xxx(XDR *xdrs, xxx *xp); Dove xdrs e' un puntatore ad uno XDR stream, e xp e' un puntatore ad una variabile che contiene o e' destinata a contenere la rappresentazione locale di un valore di tipo xxx. La funzione ritorna FALSE in caso di fallimento, TRUE in caso di successo. Le funzioni filtro sono direction-independent, la stessa funzione e' cioe' utilizzata sia per serializzare che per deserializzare un dato ( il secondo parametro deve essere un puntatore ad una variabile!) La XDR library: funzioni di filtro

60 60 XDR definisce il seguente tipo puntatore a funzione filtro standard: typedef bool_t (*xdrproc_t)(XDR *xdrs, void *localRep); Questo tipo e' utilizzato ad esempio per definire una funzione generica di liberazione di memoria, basata sulle regole di utilizzo della memoria dinamica da parte delle rappresentazioni locali dei tipi XDR: void xdr_free(xdrproc_t proc, char *objp); The first argument is the XDR filter routine for the object being freed. The second argument is a pointer to the object itself. Note: if a pointer is passed to this routine the pointer is not freed, but what it points to is freed (recursively, depending on the XDR routine). Non e la variabile *objp che viene liberata dalla chiamata a xdr_free(), ma tutte le variabili (assunte dinamiche) riferite direttamente o indirettamente da *objp. La XDR library: funzioni di filtro

61 61 Il funzionamento della funzione xdr_free() e basato sui seguenti fatti/ipotesi: Una funzione filtro si occupa, oltre che di encodifica e decodifica, anche della liberazione di memoria della rappresentazione concreta locale di un valore XDR. La politica di dis/allocazione della memoria da parte del programma utente deve essere ben disciplinata, e le regole per farlo sono specificate dal sistema di programmazione XDR (vedi seguito). La funzione xdr_free() assume che tutti gli oggetti riferiti direttamente o indirettamente da *objp siano stati allocati dinamicamente (tramite funzione malloc() ). E il programmatore che quando utilizza la funzione xdr_free() deve garantire che questo sia vero. Allocazione e liberazione della memoria

62 62 The first parameter, xdrs, is an XDR stream handle. The second parameter is the address of the number that provides data to the stream or receives data from it. All routines return TRUE if they complete successfully, and FALSE otherwise (N.B.: alcune funzioni non sono in eccesso?). bool_t xdr_hyper(XDR *xdrs, longlong_t *hp); bool_t xdr_u_hyper(XDR *xdrs, u_longlong_t *uhp); bool_t xdr_int(XDR *xdrs, int *ip); bool_t xdr_u_int(XDR *xdrs, unsigned *up); bool_t xdr_long(XDR *xdrs, long *lip); bool_t xdr_u_long(XDR *xdrs, u_long *lup); bool_t xdr_longlong_t(XDR *xdrs, longlong_t *hp); bool_t xdr_u_longlong_t(XDR *xdrs, u_long *uhp); bool_t xdr_short(XDR *xdrs, short *sip); bool_t xdr_u_short(XDR *xdrs, u_short *sup); bool_t xdr_char(XDR *xdrs, char *cp); bool_t xdr_u_char(XDR *xdrs, unsigned char *ucp); La XDR library: funzioni di filtro sugli interi C

63 63 Basandosi sulle funzioni filtro della libreria di base e' possibile scrivere le funzioni filtro per le proprie strutture dati. Supponiamo che nel nostro programma C sia definita la struttura dati struct gnumbers {// tipedef C int g_assets; int g_liabilities; }; Questa corrisponderebbe al tipo XDR gnumbers, ma questo e irrilevante se non per il fatto che abbiamo deciso di encodificare la struttura dati C nello stesso modo in cui sarebbe encodificato il tipo XDR. struct gnumbers {// definizione XDR int g_assets; int g_liabilities; }; La funzione filtro del tipo gnumbers dovrebbe quindi essere definita cosi': bool_t xdr_gnumbers(XDR *xdrs, struct gnumbers *gp) { return(xdr_int(xdrs, &gp->g_assets) && xdr_int(xdrs, &gp->g_liabilities)? TRUE : FALSE); } La XDR library: funzioni filtro user defined

64 64 In realta e il sistema di programmazione XDR-C rpcgen che, a partire dalla definizione del tipo XDR struct gnumbers { int g_assets; int g_liabilities; }; genera automaticamente: La rappresentazione concreta locale da utilizzare per rappresentare valori di questo tipo XDR typedef struct gnumbers { int g_assets; int g_liabilities; } gnumbers; La funzione filtro del tipo gnumbers: bool_t xdr_gnumbers(XDR *xdrs, gnumbers *gp); La XDR library: funzioni di filtro generate dal sistema

65 65 Il significato dei parametri di input/output e' analogo a quello delle funzioni filtro per i numeri interi. bool_t xdr_float(XDR *xdrs, float *cp); bool_t xdr_double(XDR *xdrs, double *ucp); La XDR library: funzioni di filtro sui reali C

66 66 Il tipo C float viene mappato sul tipo XDR float. Il tipo C double viene mappato sul tipo XDR double. Per i tipi interi il mappaggio tipo C tipo (sintassi astratta di trasferimento) XDR e' il seguente: La XDR library: rappresentazione concreta Tipo CTipo XDR char, short, intint u_char, u_short, u_intunsigned int longint u_longunsigned int longlonghyper int u_longlongunsigned hyper int N.B.: char, short, long, longlong (e i corrispondenti tipi unsigned ) non sono propriamente tipi XDR, ma sono comunque supportati dal sitema di programmazione XDR-C della Sun.

67 67 La XDR library mette a disposizione una funzione filtro generica per tutti i tipi enumerati. Il tipo booleano e' un caso particolarmente rilevante di enumerato. Per esso e definita una funzione filtro ad hoc. Sia la funzione filtro generica che quella specifica per i booleani assumono che la rappresentazione concreta C di un enum XDR sia identica alla rappresentazione concreta C di un int XDR, cioe' un int C. #define bool_tint // concrete local syntax #define FALSE0 #define TRUE1 #define enum_t int // concrete local syntax bool_t xdr_enum(XDR *xdrs, enum_t *ep); bool_t xdr_bool(XDR *xdrs, bool_t *bp); La XDR library: funzioni di filtro su enumerati (e bool )

68 68 Implementare la funzione filtro xdr_bool(). bool_t xdr_bool(XDR *xdrs, bool_t *bp) { return xdr_enum(xdrs, (enum_t *) bp); } Ma in realta si puo fare di meglio perche noi sappiamo quali sono tutti e soli i valori ammissibili per lenumerato bool (o per qualunque altro enumerato usere defined). bool_t xdr_bool(XDR *xdrs, bool_t *bp) { bool_t b; b = xdr_enum(xdrs, (enum_t *) bp); if(!b) return FALSE; switch (*bp) { case TRUE: case FALSE: return TRUE; default: return FALSE; } La XDR library: esercizio (enumerati e bool )

69 69 Occasionally, an XDR routine must be supplied to the RPC system, even when no data is passed or required. The following routine does this: bool_t xdr_void(void); /* always returns TRUE */ Esercizio: implementare la funzione xdr_void(). La XDR library: Possibility of No Data

70 70 In C, una stringa di caratteri e' rappresentata tramite una sequenza di caratteri ASCII terminata da un carattere '\0', che non e' considerato parte della stringa ma solo la sua marca di terminazione. Quando si vuole elaborare una stringa o passarla come parametro, quello che si considera e' in realta' un puntatore alla (all'indirizzo della) stringa ( NULL -terminata), e non la stringa stessa. Di conseguenza la XDR library considera che la rappresentazione concreta locale C di una string<> XDR sia un puntatore alla stringa, e non la sequenza dei caratteri contenuti nella stringa. Si assume anche che la stringa non contenga alcun carattere '\0'. La rappresentazione locale C del tipo XDR string<> e' inadeguata a rappresentare tutti i possibili valori del tipo XDR. Un caso analogo (duale) si era gia' presentato anche per gli interi: la XDR library fornisce funzioni filtro anche per char, short, long e longlong C (e per i corrispondenti tipi unsigned ), anche se questi tipi non corrispondono ad alcun tipo XDR. La XDR library: stringhe ASCII.1

71 71 La XDR library: stringhe ASCII.1 stringVar... \0 Rappresentazione concreta locale di una stringa di caratteri secondo rpcgen:

72 72 Le rappresentazioni interna ed esterna di una stringa sono diverse. Esternamente (sintassi di trasferimento XDR) le stringhe sono rappresentate come sequenze di caratteri ASCII. Internamente esse sono rappresentate tramite puntatori. La funzione filtro xdr_string() converte tra queste due rappresentazioni. bool_t xdr_string(XDR *xdrs, char **sp, u_int maxlength); Il parametro sp e' un puntatore ad una stringa, e quindi e' di tipo char ** (un puntatore a un puntatore ad array di caratteri). Il parametro maxlength specifica il numero massimo di caratteri che possono essere contenuti nella stringa (e ovviamente ignorato nelloperazione di serializzazione). La funzione ritorna FALSE se il numero di caratteri eccede maxlength, altrimenti ritorna TRUE. La XDR library: stringhe ASCII.2

73 73 L'operazione di deserializzazione ha il seguente comportamento: Per prima cosa si verifica che la lunghezza della stringa ricevuta non ecceda maxlength. Quindi si dereferenzia sp : Se *sp==NULL, allora viene allocata una stringa della lunghezza appropriata e *sp e' fatto puntare a questa stringa. Se *sp!=NULL, allora XDR assume che l'area di memoria destinata a contenere la rappresentazione locale della stringa sia gia' stata allocata (quest'area deve poter contenere una stringa di lunghezza massima maxlength ). In ogni caso, la stringa XDR e' decodificata nell'area target (l'area in cui e registrato il contenuto della stringa nella rappresentazione locale) e le viene suffissato il carattere '\0'. Nel caso delloperazione XDR_FREE, si dereferenzia sp. Se *sp!=NULL, allora XDR disalloca l'area di memoria di indirizzo * sp e setta *sp a NULL (il valore maxlength e' ignorato). Se *sp==NULL, non si fa nulla. La XDR library: stringhe ASCII.3

74 74 La XDR library: deserializzazione di una stringa ASCII xdr_string(xdrs, stringVar, maxlength); Il filtro in decodifica alloca una variaile dinamica di dimensione tale da contenere esattamente la stringa ricevuta piu il carattere di terminazione \0. stringVar NULL prima stringVar... \0 dopo allocato dinamicamente

75 75 La XDR library: deserializzazione di una stringa ASCII xdr_string(xdrs, stringVar, maxlength); Il filtro in decodifica utilizza (per quello che gli serve) il buffer ricevuto dal chiamante, che assume essere di dimensione >= maxlength+1. prima dopo stringVar... \0 maxlength+1 stringVar... maxlength+1

76 76 La funzione filtro xdr_string() e' generica e applicabile a stringhe di qualunque lunghezza. Essa pero' non e' conforme al prototipo standard delle funzioni filtro: Ha un parametro in piu', maxlength, lunghezza massima della stringa. Nel momento in cui definisco un tipo XDR stringa specifico, ne definisco comunque una dimensione massima (alla peggio, quella di default). Posso quindi associare al tipo stringa XDR specifico una funzione filtro con prototipo standard, implementata tramite l'invocazione della funzione filtro generica. typedef string filename ; bool_t xdr_filename(XDR *xdrs, char **sp,) { return(xdr_string(xdrs, sp, 255)); } Lo stesso ragionamento si applica anche a stringhe definite direttamente in C. La XDR library: stringhe ASCII.4

77 77 La XDR library: disallocazione di una stringa ASCII stringVar... \0 xdr_free(xdr_filename, &stringVar) Si assume che il buffer riferito da stringVar sia stato allocato dinamicamente. La variabile stringVar non viene liberata, e solo il buffer riferito da lei che viene liberato. Se si volesse disallocare la variabile stringVar (se fosse dinamica) bisognerebbe chiamare direttamente la funzione free() del C (cosi come, in questo caso, era stata chiamata la funzione malloc() del C per allocarla). Si presuppone allocato dinamicamente. E la parte disallocata della rappresentazione concreta locale.

78 78 La XDR library fornisce un funzione filtro ( xdr_array() ) per trattare in modo generico array di qualunque tipo di elementi, e di dimensione (numero di elementi) indefinita (ovvio che ogni singolo array ha tipo e numero di elementi ben definiti). Questa funzione richiede i seguenti parametri: Il puntatore ad un array ( ap ), che si assume rappresentato concretamente come un puntatore alla sequenza dei suoi elementi. Il puntatore alla variabile che indica la lunghezza (numero di elementi) effettiva dell'array ( lp ). Il numero massimo di elementi che possono essere contenuti nell'array. La dimensione in byte della rappresentazione concreta locale di un elemento dell'array, che e' (deve essere) uguale per tutti gli elementi! (Ad esempio, una stringa di lunghezza variabile e' rappresentata tramite un puntatore, cosi che le rappresentazioni locali di tutte le stringhe hanno uguali dimensioni!) Il puntatore alla funzione filtro relativa al tipo degli elementi dell'array. La XDR library: array di lunghezza variabile.1

79 79 typedef bool_t (*xdrproc_t)(XDR *xdrs, void *localRep); bool_t xdr_array(XDR *xdrs, char **ap, // rif. ad array u_int *lp, // lung. effett. u_int maxlength, // lung. max u_int elementsize, xdrproc_t xdr_element // il prototipo di xdr_element() // deve essere quello standard ); Durante la deserializzazione, se *ap e' NULL XDR alloca un array della dimesione appropriata e setta *ap a riferire l'array. In ogni caso, setta *lp al numero degli elementi effettivamente contenuti nell'array. Durante la serializzazione il numero degli elementi dell'array e' ottenuto dal valore di *lp. La XDR library: array di lunghezza variabile.2

80 80 xdr_array() invoca la funzione xdr_element() per processare ciascuno dei suoi elementi. Anche la funzione xdr_array() non e' conforme al prototipo standard. Anche in questo caso, dalla definizione di uno specifico tipo array XDR puo' essere derivata la definizione di una funzione filtro con prototipo standard. Che si limita a invocare la funzione filtro generica xdr_array() passandole tutti i parametri aggiuntivi necessari. Vedi esempio nelle pagine seguenti, dove si vede anche come le informazioni sui parametri aggiuntivi sono deducibili dalla definizone dello specifico tipo di array. La XDR library: array di lunghezza variabile.3

81 81 Vedi il riferimento SunSoft, Network Interfaces Programmer's Guide, app. B per la definizione delle altre funzioni filtro della libreria XDR di base. Ma e' veramente necessario conoscere la libreria XDR di base e scriversi a mano le funzioni per la codifica e decodifica delle proprie strutture dati (della propria sintassi astratta)? Non esiste un sistema di programmazione XDR completo analogo ai sistemi di programmazione ASN.1? Certo che esiste! Basta descrivere in XDR la propria sintassi astratta e farla processare (compilare) al compilatore rpcgen rpcgen generera' automaticamente le relative funzioni filtro oltre a fornirci la rappresentazione concreta locale in C dei tipi di dato della sintassi astratta. XDR library e rpcgen

82 82 XDR library e rpcgen Protocol.x (sintassi astratta XDR) rpcgen Protocol_xdr.c (funzioni di de/codifica per i tipi definiti nella sintassi astratta) Protocol.h (rappresentazione concreta locale di valori della sintassi astratta) XDR Library chiama produce User program (C) chiama include chiama

83 83 XDR library e rpcgen RPC_protocol.x (sintassi astratta XDR del protocollo Sun RPC v2) rpcgen RPC_protocol_xdr.c (funzioni di de/codifica per rpc_msg e tipi riferiti) RPC_protocol.h (rappresentazione concreta locale di PDU del protocollo Sun RPC v2) XDR Library chiama produce Sun RPC v2 Protocol Entity (C) chiama include chiama

84 84 Definizione XDR: typedef int VarIntegerList ; Struttura dati C per la rappresentazione concreta locale del tipo XDR: typedef struct { u_int VarIntegerList_len; int *VarIntegerList_val; } VarIntegerList; Funzione filtro di de/codifica generata da rpcgen: bool_t xdr_VarIntegerList(register XDR *xdrs, VarIntegerList *objp) { register int *buf; if (!xdr_array(xdrs, (char **)&objp->VarIntegerList_val, (u_int *)&objp->VarIntegerList_len, 1000, sizeof (int), (xdrproc_t)xdr_int)) return (FALSE); } return (TRUE); } Uso di rpcgen: array di lunghezza variabile

85 85 Rappresentazione concreta locale C del tipo XDR: typedef int VarIntegerList ; Definizione della variabile: VarIntegerList arrayVar; Uso di rpcgen: array di lunghezza variabile arrayVar... VarIntegerList_len VarIntegerList_val VarIntegerList_len

86 86 Definizione XDR: typedef int IntegerList[1000]; Struttura dati C per la rappresentazione concreta locale del tipo XDR: typedef int IntegerList[1000]; Funzione di de/codifica: bool_t xdr_IntegerList(register XDR *xdrs, IntegerList objp) { register int *buf; if (!xdr_vector(xdrs, (char *)objp, 1000, sizeof (int), (xdrproc_t) xdr_int)) return (FALSE); } return (TRUE); } Uso di rpcgen: array di lunghezza fissa

87 87 In generale, ogni variabile definita in un programma dovrebbe essere correttamente inizializzata (infatti nei linguaggi object-oriented gli oggetti sono creati da costruttori che provvedono anche ad inizializzarli). Quando si utilizza XDR linizializzazione della variabile target e necessaria prima di poter effettuare una operazione di decodifica su di essa. Infatti, se non fosse inizializzata correttamente, date le regole del decoder XDR un campo puntatore con valore diverso da NULL verrebbe interpretato come puntare al buffer su cui effettuare la decodifica. Di conseguenza la maniera corretta di inizializzare una rappresentazione locale e di settare tutti i suoi byte a 0. Questo assicura che qualunque campo puntatore presente nella struttura sia interpretato come avere valore NULL. Una rappresentazione locale deve essere azzerata ogni volta che vogliamo effettuarci sopra una operazione di decodifica. Inizializzazione della rappresentazione locale

88 88 La XDR library contiene un secondo insieme di funzioni dedicato alla gestione degli XDR stream da/su cui i dati vengono de/serializzati. Esistono diversi tipi di XDR stream che consentono di de/serializzare dati su File del file system (compresi device di I/O), Connessioni TCP/IP, Memoria centrale. Esistono operazioni per: creare (inizializzare) un XDR stream (di un tipo specifico), distruggere (terminare l'accesso a) un XDR stream. Ogni XDR stream definisce anche la direzionalita' delle operazioni che gli sono applicate: XDR_ENCODE, XDR_DECODE, XDR_FREE. In ogni caso occorre per prima cosa allocare una variabile per il descrittore dello stream: #include XDR xdrs; La XDR library: gestione degli XDR stream

89 89 Inizializzazione di un XDR stream su file. #include void xdrstdio_create(XDR *xdrs, FILE *fp, enum xdr_op x_op); dove x_op definisce la direzionalita' dello stream. Inizializzazione di un XDR stream su memoria centrale. #include void xdrmem_create(XDR *xdrs, char *addr, u_int len, enum xdr_op x_op); La XDR library: creazione di un XDR stream

90 90 Se si sta utilizzando un XDR stream su memoria e necessario poter sapere quanti byte sono stati scritti nel buffer. ad esempio per trasmettere questi byte in rete attraverso un socket (e quello che fa il supporto RPC Sun quando utilizza UDP come trasporto). La funzione xdr_getpos() fornisce questa informazione: #include u_int xdr_getpos(XDR *xdrs); dove, per uno stream su memoria in direzione XDR_ENCODE, il valore tornato rappresenta il numero di byte scritti nello stream. Non tutti gli XDR stream supportano il controllo della posizione, ma quelli su memoria si. E possibile anche, almeno per gli stream su memoria, settare il valore della posizione, ad esempio per iniziare la scrittura di un nuovo messaggio: bool_t xdr_setpos(XDR *xdrs, u_int pos); La XDR library: posizione in un XDR stream

91 91 XDRstream in memoria centrale XDR stream buffer len pos Parte del buffer gia utilizzata pos x_op N.B.: se si eseguono piu operazioni successive di encodifica su uno stream ciascuna di queste inizia a scrivere nel buffer a partire dalla posizione pos corrente (e di conseguenza la fa avanzare). N.B.: se si eseguono piu operazioni successive di decodifica su uno stream ciascuna di queste inizia a leggere il buffer a partire dalla posizione pos corrente (e di conseguenza la fa avanzare).

92 92 Uno XDR stream, di qualunque tipo, viene terminato attraverso la chiamata della funzione: #include void xdr_destroy(XDR *xdrs); L'utilizzo di un XDR stream dopo che su di esso e' stata eseguita l'operazione xdr_destroy() e' illegale. La XDR library: distruzione di un XDR stream

93 93 int xid = 0; XDR xdrEnc; char txBuff[8192];... xdrmem_create(&xdrEnc, txBuff, 8192, XDR_ENC);... void sendCallMsg(unsigned progN, unsigned versN, unsigned procN, XDR *xdrE, char txBuff[], int fd, struct sockaddr_in *dst) { rpc_msg m; m.xid = xid++; m.body.mtype = CALL; m.body.body_u.cbody.rpcvers = 2; m.body.body_u.cbody.prog = progN; m.body.body_u.cbody.vers = versN; m.body.body_u.cbody.proc = procN; m.body.body_u.cbody.cred.flavor = AUTH_NULL; m.body.body_u.cbody.verf.flavor = AUTH_NULL; xdr_setpos(xdrE, 0); xdr_rpc_msg(xdrE, &m); sendto(fd, txBuff, xdr_getpos(xdrE), 0, dst, sizeof(dst)); } Esempio: invio di un rpc_msg su UDP

94 94 Implementare la funzione della libreria XDR: void xdr_free(xdrproc_t proc, char *objp); dove: The first argument is the XDR routine for the object being freed. The second argument is a pointer to the object itself. Note: if a pointer is passed to this routine the pointer is not freed, but what it points to is freed (recursively, depending on the XDR routine). Esercizio 1

95 95 Esiste uno stream XDR per la serializzazione (e la trasmissione) di informazioni su una connessione TCP, ma non esiste uno stream analogo per operare su UDP. Per utilizzare XDR su UDP: Si utilizza uno stream XDR in memoria. Si utilizza il buffer di memoria dello stream per de/codificare il messaggio (il buffer serve a contenere il messaggio in rappresentazione canonica di rete). Si trasmette/riceve sul socket UDP il contenuto del buffer. Il buffer di memoria associato allo stream XDR deve essere abbastanza grande da contenere lintero datagram UDP. Come mai se luso di XDR su UDP e cosi semplice sono stati introdotti degli appositi stream XDR su TCP? Se volessimo utilizzare come layer di trasporto TCP ma non volessimo utilizzare gli stream XDR appositi, di cosa avremmo bisogno? Esercizio 2


Scaricare ppt "Lez. 91 Reti di Calcolatori XDR - eXternal Data Representation Vedi: SunSoft, Network Interfaces Programmer's Guide, app. A e B, pagg. 291-352. RFC 1014,"

Presentazioni simili


Annunci Google