IDL-Techniken für bessere Schnittstellen- und Methodenentwürfe
Erwägen Sie die Verwendung der folgenden IDL-spezifischen Techniken, um die Sicherheit und Leistung zu verbessern, wenn Sie RPC-Schnittstellen und -Methoden entwickeln, die sowohl Conformant- als auch Variant-Daten verarbeiten können. Die Attribute in diesem Thema sind die IDL-Attribute, die für Methodenparameter festgelegt werden, die entweder Conformant-Daten (z. B. die Attribute [size_is] und [max_is]) oder Variant-Daten (z. B. die Attribute [length_is] und [string]) verarbeiten können.
Verwenden des [range]-Attributs mit Parametern für Conformant-Daten
Das [range]-Attribut weist die RPC-Runtime an, während des Unmarshalingprozesses eine zusätzliche Größenüberprüfung durchzuführen. Insbesondere wird überprüft, ob die Größe der als zugeordneter Parameter übergebenen Daten innerhalb des angegebenen Bereichs liegt.
Das [range]-Attribut wirkt sich nicht auf das Verbindungsformat aus.
Wenn sich der Wert für die Verbindung außerhalb des zulässigen Bereichs befindet, löst RPC eine RPC_X_INVALID_BOUND- oder RPC_X_BAD_STUB_DATA-Ausnahme aus. Dies bietet eine zusätzliche Ebene der Datenüberprüfung und kann häufige Sicherheitsfehler wie Pufferüberläufe verhindern. Ebenso kann die Verwendung von [range] die Anwendungsleistung verbessern, weil damit gekennzeichnete Conformant-Daten über klar definierte Einschränkungen für die Prüfung durch den RPC-Dienst verfügen.
Speicherverwaltungsregeln für den RPC-Serverstub
Beim Erstellen der IDL-Dateien für eine RPC-fähige Anwendung ist es wichtig, die Regeln für die Verwaltung des Arbeitsspeichers des RPC-Serverstubs zu verstehen. Anwendungen können die Serverressourcenauslastung verbessern, indem [range] in Verbindung mit Conformant-Daten verwendet wird – wie oben erläutert – und indem die Anwendung von IDL-Attributen für Daten mit variabler Länge wie [length_is] auf Conformant-Daten bewusst vermieden wird.
Die Anwendung von [length_is] auf Datenstrukturfelder, die in einer IDL-Datei definiert sind, wird nicht empfohlen.
Best Practices für Parameter für Daten mit variabler Länge
Im Folgenden werden verschiedene Best Practices beim Definieren der IDL-Attribute für Datenstrukturen, Methodenparameter und Felder mit variabler Größe beschrieben.
Verwenden Sie eine frühe Korrelation. Es ist in der Regel besser, den Parameter oder das Feld variabler Größe so zu definieren, dass er/es unmittelbar nach dem steuernden integralen Typ vorkommt.
Ein auf ein Objekt angewendeter
earlyCorr ( [in, range(MIN_COUNT, MAX_COUNT)] long size, [in,size_is(size)] char *pv );
besser als
lateCorr ( [in,size_is(size)] char *pv, [in, range(MIN_COUNT, MAX_COUNT)] long size) );
Hierbei deklariert earlyCorr den Größenparameter unmittelbar vor dem Datenparameter mit variabler Länge, und lateCorr deklariert den Größenparameter danach. Die Verwendung einer frühzeitigen Korrespondenz verbessert die Leistung insgesamt, insbesondere in Fällen, in denen die Methode häufig aufgerufen wird.
Bei Parametern, die mit dem Attributtupel [out, size_is] gekennzeichnet sind und deren Datenlänge auf der Clientseite bekannt ist, oder bei angemessener Obergrenze auf dem Client sollte die Methodendefinition in Bezug auf die Parameterzuordnung und -reihenfolge in etwa wie folgt lauten:
outKnownSize ( [in,range(MIN_COUNT, MAX_COUNT)] long lSize, [out,size_is(lSize)] UserDataType * pArr );
In diesem Fall stellt der Client einen Puffer mit fester Größe für pArr bereit, sodass der serverseitige RPC-Dienst einen ausreichend großen Puffer mit einem guten Maß an Sicherheit zuweist. Beachten Sie, dass im Beispiel die Daten vom Server empfangen werden ([out]). Die Definition ist ähnlich für Daten, die an den Server übergeben werden ([in]).
In Situationen, in denen die serverseitige Komponente einer RPC-Anwendung über die Datenlänge entscheidet, sollte die Methodendefinition wie folgt aussehen:
typedef [range(MIN_COUNT,MAX_COUNT)] long RANGED_LONG; outUnknownSize ( [out] RANGED_LONG *pSize, [out,size_is(,*pSize)] UserDataType **ppArr );
RANGED_LONG ist ein Typ, der sowohl für Client- als auch für Serverstubs definiert ist und eine bestimmte Größe aufweist, die der Client ordnungsgemäß antizipieren kann. Im Beispiel übergibt der Client ppArr als NULL, und die RPC-Serveranwendungskomponente weist die richtige Speichermenge zu. Bei der Rückgabe weist der RPC-Dienst auf Clientseite den Speicher für die zurückgegebenen Daten zu.
Wenn der Client eine Teilmenge eines großen Conformant-Arrays an den Server senden möchte, kann die Anwendung die Größe der Teilmenge angeben, wie im folgenden Beispiel gezeigt:
inConformantVaryingArray ( [in,range(MIN_COUNT,MAX_COUNT)] long lSize, [in] long lLength, [in,size_is(lSize), length_is(lLength)] UserDataType *pArr );
Auf diese Weise überträgt RPC nur lLength-Elemente des Arrays über die Verbindung. Diese Definition zwingt jedoch den RPC-Dienst, auf Serverseite Arbeitsspeicher der Größe lSize zuzuweisen.
Wenn die Clientanwendungskomponente die maximale Größe eines Arrays bestimmt, das der Server zurückgeben kann, aber dem Server die Übertragung einer Teilmenge dieses Arrays erlaubt, kann die Anwendung ein solches Verhalten festlegen, indem der IDL-Wert ähnlich dem folgenden Beispiel definiert wird:
inMaxSizeOutLength ( [in, range(MIN_COUNT, MAX_COUNT)] long lSize, [out] long *pLength, [out,size_is(lSize), length_is(*pLength)] UserDataType *pArr );
Die Clientanwendungskomponente gibt die maximale Größe des Arrays an, und der Server gibt an, wie viele Elemente an den Client zurück übertragen werden.
Wenn die Serveranwendungskomponente eine Zeichenfolge an die Clientanwendungskomponente zurückgeben muss und der Client die maximale Größe kennt, die vom Server zurückgegeben werden darf, kann die Anwendung einen Conformant-Zeichenfolgentyp verwenden, wie im folgenden Beispiel gezeigt:
outStringKnownSize ( [in,range(MIN_COUNT, MAX_STRING)] long lSize, [out,size_is(lSize),string] wchar_t *pString );
Wenn die Clientanwendungskomponente die Größe der Zeichenfolge nicht steuern soll, kann der RPC-Dienst den Speicher explizit zuweisen, wie im folgenden Beispiel gezeigt:
outStringUnknownSize ( [out] LPWSTR *ppStr );
Die Clientanwendungskomponente muss ppStr beim Aufrufen der RPC-Methode auf NULL festlegen.