1 RPC-Protokoll-Definitionssprache (Protocol Definition Language ) RPCL ist die Protokoll-Definitionssprache, die vom ONC-RPCGEN verwendet wird. Diese Sprache wird in dem Quellprogramm application.x verwendet. Die Sprache ist sehr ähnlich wie C und daher relativ leicht zu erlernen. 1.1 Definitionen (Definitions) Eine RPCL Protocol Specification besteht aus einer Serie von Definitionen: definition-list: definition ";" definition ";" definition-list Es gibt 6 Definitionstypen: definition: const-definition enum-definition struct-definition union-definition typedef-definition program-definition Jeder Definitionstyp ( enum, struct, union, typedef, const, and program ) hat seine eigene Syntax. Obwohl es nicht zwingend erforderlich ist, sollten Typen und Variablen vor ihrer Verwendung definiert werden. Definitionen können in einer application.x Datei in beliebiger Reihenfolge stehen. Innerhalb einer Definition sind 4 Deklarations-Typen zulässig, die im Anschluß an die Beschreibung der 6 Definitionen erläutert werden. 1.2 Symbolische Konstanten ( Symbolic Constants ) Symbolische Konstanten in der XDR- oder RPCL Sprache können dort verwendet werden, wo eine Integer-Konstante auftritt, z.b. bei der Dimensionierung eines Arrays. const-definition: "const" const-ident "=" integer Soll z.b. ein Array mit 8 K Komponenten definiert werden, so lautet die RPCL-Anweisung: const MAX_SIZE = 8192; RPCGEN übersetzt diese Anweisung und fügt das Ergebnis in die Datei application.h ein: #define MAX_SIZE 8192 MAX_SIZE kann daher sowohl in der RPCL-Definition als auch in den Server- und Client- Quellprogrammen verwendet werden ( application.x, application_svc_proc.c und application.c ). Seiten 1+2 RPCL01 03.11.04
1.3 Aufzählungstyp (Enumerations) Der RPCL-Aufzählungstyp entpricht dem enum-typ in C: enum-definition: "enum" enum-ident "{" " enum-value-list "}" enum-value-list: enum-value enum-value "," enum-value-list enum-value: enum-value-ident enum-value-ident "=" value Beispiel: Definition eines Datentyps color, mit einem Wertevorrat von 3 Farben in der RPCL-Datei: enum color { RED = 0, GREEN = 1, BLUE = 2 RPCGEN übersetzt diese Anweisung und fügt das Ergebnis in application.h ein: enum color { RED = 0, GREEN = 1, BLUE = 2 typedef enum color color; bool_t xdr_color(); Es ist zu beachten, dass RPCGEN durch Verwendung der typedef-anweisung dafür sorgt, dass ein Datentyp color zur Verfügung steht. Weiterhin erstellt RPCGEN eine Filter- Funktion zur Codierung/Decodierung des Datentyps color mit dem Namen xdr_color(). Dieses Unterprogramm wird von RPCGEN in das Programm xdr.c und als Prototyp die Header-Datei application.h eingefügt. Seiten 3+4 RPCL01 03.11.04
1.4 Strukturen (Structures) Die Struktur-Definition entspricht der C-Syntax: struct-definition: "struct" struct-ident "{ declaration-list } declaration-list: declaration ";" declaration ";" declaration-list Beispiel: Definition eines Datentyps für X/Y-Koordinaten: struct point { int x; int y; } ; Die folgenden C-Anweisungen werden in die Header-Datei geschrieben: struct point { int x; int y; typedef struct point point; bool_t xdr_point(); 1.5 Unions XDR unions sind sehr ähnlich den variablen Records bei Pascal. Sie unterscheiden sich stark von C-unions: union-definition: "union" union-ident "switch" "("declaration")" "{ "case-list } case-list: "case" value ":" declaration ";" "default":" :" declaration ";" "case" value ":" declaration";" case-list XDR-unions erleichtern die alternative Rückgabe verschieden strukturierter Ergebnisse. Als Beispiel ist nachfolgend der häufige Fall dargestellt, dass der Server im Fehlerfall nur einen Fehlercode als Ergebnis liefert. Im Normalfall ( kein Fehler ) werden Daten ( in diesem Beispiel 8K ) geliefert. Seiten 5+6 RPCL01 03.11.04
union result switch (int error) { case 0: opaque data[max_size]; default: void; RPCGEN übersetzt diese Anweisung und fügt das Ergebnis in application.h ein: struct result { int error; union { char data[max_size]; } result_u; typedef struct result result; bool_t xdr_result(); Der Name der C-union entsteht durch das Anhängen von _u an den XDR-Namen. Die Kenntnis dieses Namens ist wichtig bei der Erstellung der Programme application.c und application_svc_proc.c. Weiterhin erstellt RPCGEN eine Filter-Funktion zur Codierung/Decodierung des Datentyps result mit dem Namen xdr_result(). 1.6 Typdefinition (typedef) RPCGEN erzeugt für jede enum-, struct- und union-definition mittels der typedef-anweisung einen Datentyp in der Header-Datei application.h und generiert zusätzlich eine Filter- Funktion zur Codierung / Decodierung des Datentyps. Mit Hilfe der typedef-anweisung in der Datei application.x ist es aber auch möglich eigene Datentypen zu deklarieren, die von RPCGEN unverändert in die Header-Datei übernommen werden. "typedef" declaration; Beispiel: typedef point poly[4]; erscheint unverändert in der Header-Datei. 1.7 Programme (Programs) Die program-anweisung erlaubt die Definition folgender wichtiger Attribute: Programmname Programmnummer Programmversion Prozedur-Informationen über den Server Seiten 7+8 RPCL01 03.11.04
program-definition: "program" program-ident "{" version-list "}" "=" value version-list: version ";" version ";" version-list version: "version" version-ident "{" procedure-list "}" "=" value procedure-list: procedure ";" procedure ";" procedure-list procedure: type-ident procedure-ident "("type-ident")" "=" value Beispiel: Ein Programm mit dem Namen EXAMPLE: program EXAMPLE_PROGRAM { version EXAMPLE_VERSION { void EXAMPLE_PROCEDURE(void) = l; } = l; } = 0x2000000; RPCGEN trägt in die Header-Datei folgende Zeilen ein: #define EXAMPLE_PROGRAM ((u_long)0x2000000) #define EXAMPLE_VERSION ((u_long) 1 ) #define EXAMPLE_PROCEDURE ((u_long) 1 ) extern void *example_procedure_1(); Seiten 9+10 RPCL01 03.11.04
Grundsätzlich ist für jedes RPC-Programm die Versionsnummer und Prozedurnummer zu definieren. Es ist möglich, mehrere RPC-Server-Programme innerhalb eines RPCL-Quellprogramms zu definieren. Für jedes Programm ist ein Programm-Definitionsblock erforderlich. Hinweise: Es ist zu beachten, dass die Programmnummer Null reseviert ist und daher nicht vergeben werden darf. Der Name für die Procedure besteht aus Kleinbuchstaben und dem angehängten _1(). Der Name wird automatisch generiert. Die XDR-Filter-Funktionen arbeiten mit Pointern auf die zu codierenden bzw. zu decodierenden Objekte. Die Client- und Server-Unterprogramme müssen daher ebenfalls mit Pointern für die Parameter und den Returnwert arbeiten. 1.8 NULLPROC ONC-RPC verwendet automatisch eine Prozedur mit der Nummer Null. Mit dieser Prozedur wird eine Ping-Funktion ausgeführt, d.h., es wird vor dem Aufruf einer Anwenderfunktion ermittelt, ob der Server erreichbar und aktiv ist. Eine Prozedur mit der Nummer 0 darf daher vom Anwender nicht definiert werden. 1.9 Deklarationen (Declarations) RPCL erlaubt vier Deklarations-Typen: declaration: simple-declaration fixed-array-declaration variable-array-declaration pointer-declaration Es gibt einfache Deklarationen wie in C: simple-declaration: type-ident variable-ident Zum Beispiel: color c; erscheint identisch in der Header-Datei. Array mit fester Länge werden wie in C deklariert: fixed-array-declaration: type-ident variable-ident "["value"]" Seiten 11+12 RPCL01 03.11.04
Zum Beispiel: color palette[8]; erscheint identisch in der Header-Datei. Es gibt keine Unterstützung für mehrdimensionale Arrays der Anwender muss daher ggf. mehrdimensionale Arrays in eindimensionale Arrays überführen. Eine Alternative ist durch die Verwendung von Baumstrukturen und verkettete Listen gegeben. Während Arrays mit variabler Länge von C nicht unterstützt werden, ermöglicht XDR diese Möglichkeit: variable-array-declaration: type-ident variable-ident "<"value">" type-ident variable-ident "<" ">" Durch value wird die maximale Größe des Arrays definiert. Wenn die Längendefinition fehlt, ist die Größe des Arrays undefiniert. int x<max_size>; /* maximal MAX_SIZE Arraykomponenten */ int y<>; /* beliebige Anzahl von Arraykomponenten */ Da es keine entsprechende Syntax für C gibt, wird ein Array mit variabler Länge in eine Struktur überführt. Zum Beispiel wird ein o.g. deklariertes Array x wie folgt übersetzt: struct { u_int x_len; /* # der Arraykomponenten */ int *x_val; /* pointer auf das array */ } x; Die Anzahl der Arraykomponenten wird in der _len-komponente gespeichert, der Pointer auf das eigentliche Array wird in die _val-komponente eingetragen. Der erste Teil des Namens ist identisch mit dem Variablennamen in RPCL. XDR-Pointer werden auf die gleiche Weise definiert wie C-Pointer: pointer-declaration: type-ident "*" variable-ident Zum Beispiel wird ein Pointer auf eine Struktur pt zum Aufbau einer verketteten Liste wie folgt definiert: pt *pnext; Seiten 13+14 RPCL01 03.11.04
Weiteres Beispiel: Die folgende Struktur kann zum Aufbau einer verketteten Liste für die Punkte eines Polygons verwendet werden: struct point { int x; int y; struct poly { point *p; point *pnext; Für jeden Variablentyp wird von RPCGEN eine XDR-Filterfunktion erzeugt. In application_xdr.c erscheint folgender C-Code: application_xdr.c: struct point { int x; int y; typedef struct point point; bool_t xdr_point(); bool_t xdr_pt(); struct poly{ point *p; point *pnext; typedef struct poly poly; bool_t xdr_poly(); Auf diese Weise kann eine Hierarchie von XDR-Filtern erzeugt werden, die jede denkbare Struktur handhaben kann. 1.10 Sonderfälle Es gibt einige Ausnahmen von den vorher beschriebenen Regel. 1.10.1 Logische Variablen (Booleans) C kennt keinen Datentyp boolean. XDR und RPC-Bibliotheken verwenden den Datentyp bool_t mit dem Wertevorrat TRUE und FALSE. Beispiel: bool busyflag; wird übersetzt in: bool_t busyflag; Seiten 15+16 RPCL01 03.11.04
1.10.2 Zeichenketten (Strings) C verfügt nicht über einen Datentyp string, es besteht jedoch eine Konvention zur Speicherung von Zeichenketten in char-arrays. Diese Zeichenketten werden auch als Z-strings bezeichnet, da das Ende einer Zeichenkette durch Zero ( Null ) gekennzeichnet ist. In RPCL wird ein string durch das Schlüsselwort string deklariert. Die maximale Länge des string wird in die Zeichen < und > eingeschlossen. Die abschließende Null wird dabei nicht mitgezählt. Fehlt die Längenangabe, so wird ein string undefinierter Länge deklariert. Beispiele: string buffer<32>; string longbuff<>; werden übersetzt in: char *buffer ; char *longbuff; 1.10.3 Typlose Daten (Opaque Data) XDR und RPC verwenden "opaque data" zur Beschreibung von Byte-Sequenzen ohne zugeordneten Datentyp. Es können sowohl Arrays mit fester Länge als auch mit variabler Länge deklariert werden. Beispiele: opaque fixdata[512]; opaque vardata<1024>; werden übersetzt in: char fixdata[512]; struct u_int vardata_len; char *vardata_val; } vardata; Die Verwendung von Arrays variabler Länge ist in dem Abschnitt über variable-arraydeclaration beschrieben. 1.10.4 Void Die void-deklaration wird nur für union- und program-definitionen verwendet. Durch das Schlüsselwort void wird keine Variable definiert. Als XDR-Wandlungsfunktion kommt xdr_void() zum Einsatz. Seiten 17+18 RPCL01 03.11.04