Поделиться через


Методы IDL для улучшения интерфейса и проектирования методов

Для повышения безопасности и производительности при разработке интерфейсов RPC и методов, обрабатывающих как соответствующие, так и вариантные данные, рассмотрите возможность использования следующих методов IDL. Атрибуты, упоминаемые в этом разделе, — это атрибуты IDL, заданные в параметрах метода, которые обрабатывают либо соответствующие данные (например, атрибуты [size_is] и [max_is], либо данные варианта (например, атрибуты [length_is] и [string]).

Использование атрибута [range] с соответствующими параметрами данных

Атрибут [range] указывает среде выполнения RPC выполнить дополнительную проверку размера в процессе размежевывания данных. В частности, он проверяет, что предоставленный размер данных, переданных в качестве связанного параметра, находится в указанном диапазоне.

Атрибут [range] не влияет на формат провода.

Если значение в проводе выходит за пределы допустимого диапазона, RPC вызовет RPC_X_INVALID_BOUND или RPC_X_BAD_STUB_DATA исключение. Это обеспечивает дополнительный уровень проверки данных и помогает предотвратить распространенные ошибки безопасности, такие как переполнение буфера. Аналогичным образом использование [диапазона] может повысить производительность приложения, так как соответствующие данные, помеченные им, имеют четко определенные ограничения, доступные для рассмотрения службой RPC.

Правила управления памятью заглушки сервера RPC

Важно понимать правила управления памятью заглушки сервера RPC при создании IDL-файлов для приложения с поддержкой RPC. Приложения могут улучшить использование ресурсов сервера, используя [диапазон] в сочетании с соответствующими данными, как указано выше, а также намеренно избегая применения атрибутов IDL переменной длины, таких как [length_is], к соответствующим данным.

Применение [length_is] к полям структуры данных, определенным в IDL-файле, не рекомендуется.

Рекомендации по использованию параметров данных переменной длины

Ниже приведено несколько рекомендаций, которые следует учитывать при определении атрибутов IDL для структур данных переменной величины, параметров методов и полей.

  • Используйте раннюю корреляцию. Как правило, лучше определить параметр размера переменной или поле таким образом, чтобы они возникали сразу после управляющего целочисленного типа.

    Например,

    earlyCorr
    (
    [in, range(MIN_COUNT, MAX_COUNT)] long size, 
    [in,size_is(size)] char *pv
    );
    

    лучше, чем

    lateCorr
    (
    [in,size_is(size)] char *pv, 
    [in, range(MIN_COUNT, MAX_COUNT)] long size)
    );
    

    где earlyCorr объявляет параметр size непосредственно перед параметром данных переменной длины, а lateCorr объявляет параметр size после него. Использование раннего соответствия повышает общую производительность, особенно в тех случаях, когда метод вызывается часто.

  • Для параметров, помеченных кортежем атрибута [out, size_is], и где длина данных известна на стороне клиента или где клиент имеет разумную верхнюю границу, определение метода должно быть аналогично следующему с точки зрения присвоения параметров и последовательности:

    outKnownSize
    (
    [in,range(MIN_COUNT, MAX_COUNT)] long lSize,
    [out,size_is(lSize)] UserDataType * pArr
    );
    

    В этом случае клиент предоставляет буфер фиксированного размера для pArr, что позволяет службе RPC на стороне сервера выделить буфер достаточного размера с хорошей степенью надежности. Обратите внимание, что в этом примере данные получены с сервера ([out]). Определение аналогично для данных, передаваемых на сервер ([in]).

  • В ситуациях, когда серверный компонент приложения RPC определяет длину данных, определение метода должно выглядеть следующим образом:

    typedef [range(MIN_COUNT,MAX_COUNT)] long RANGED_LONG;
    
    outUnknownSize
    (
    [out] RANGED_LONG *pSize,
    [out,size_is(,*pSize)] UserDataType **ppArr
    );
    

    RANGED_LONG — это тип, определенный как для заглушки клиента, так и для заглушки сервера, и указанного размера, который клиент может правильно ожидать. В этом примере клиент передает ppArr как NULL, а компонент серверного приложения RPC выделяет правильный объем памяти. По возвращении служба RPC на стороне клиента выделяет память для возвращаемых данных.

  • Если клиент хочет отправить на сервер подмножество большого массива соответствия, приложение может указать размер подмножества, как показано в следующем примере:

    inConformantVaryingArray
    (
    [in,range(MIN_COUNT,MAX_COUNT)] long lSize,
    [in] long lLength, 
    [in,size_is(lSize), length_is(lLength)] UserDataType *pArr
    );
    

    Таким образом RPC будет передавать только элементы lLength массива по сети. Однако это определение заставляет службу RPC выделять память размера lSize на стороне сервера.

  • Если компонент клиентского приложения определяет максимальный размер массива, который может возвращать сервер, но позволяет серверу передавать подмножество этого массива, приложение может указать такое поведение, определив IDL, как в следующем примере:

    inMaxSizeOutLength
    (
    [in, range(MIN_COUNT, MAX_COUNT)] long lSize,
    [out] long *pLength,
    [out,size_is(lSize), length_is(*pLength)] UserDataType *pArr
    );
    

    Компонент клиентского приложения задает максимальный размер массива, а сервер — количество элементов, передаваемых клиенту.

  • Если компонент серверного приложения должен вернуть строку компоненту клиентского приложения и клиент знает максимальный размер, возвращаемый с сервера, приложение может использовать соответствующий строковый тип, как показано в следующем примере:

    outStringKnownSize
    (
    [in,range(MIN_COUNT, MAX_STRING)] long lSize,
    [out,size_is(lSize),string] wchar_t *pString
    );
    
  • Если компонент клиентского приложения не должен управлять размером строки, служба RPC может выделить память, как показано в следующем примере:

    outStringUnknownSize
    (
    [out] LPWSTR *ppStr
    );
    

    Компонент клиентского приложения должен задать для параметра ppStrзначение NULL при вызове метода RPC.