KasperskyOS Community Edition 1.0

Работа с ошибками в IDL

Out-аргументы в IDL-описании не рекомендуется использовать для возврата сущности-клиенту кодов логических ошибок, возникающих в результате обработки запроса сущностью-сервером. Вместо этого рекомендуется использовать error-аргументы.

Логическая ошибка – это ошибка, которая возникла при обработке запроса сущностью-сервером и должна быть возвращена сущности-клиенту. Например, если сущность-клиент пытается открыть несуществующий файл, сервер файловой системы возвращает логическую ошибку. Внутренние ошибки сущности-сервера, такие как нехватка памяти или выполнение недопустимой инструкции, не являются логическими ошибками.

Использование error-аргументов позволяет:

  • не пересылать все out-аргументы методов в сообщении-ответе от сущности-сервера к сущности-клиенту в случае возврата ошибки. Вместо этого, при необходимости вернуть код ошибки, сообщение-ответ будет содержать только error-аргументы.
  • связывать методы моделей безопасности не только с событиями отправки ответов, но также с событиями возврата ошибок.

Язык IDL и компилятор NK предоставляют два способа использования error-аргументов:

  • Упрощенная обработка ошибок

    Этот способ используется компилятором NK по умолчанию.

    При использовании этого способа методы интерфейсов могут иметь не более одного error-аргумента типа UInt16. Значения возвращаемого error-аргумента метода упаковываются в код возврата соответствующего клиентского интерфейсного метода.

  • Расширенная обработка ошибок

    Для использования этого способа необходимо использовать параметр --extended-errors компилятора NK.

    При использовании этого способа методы интерфейса могут иметь несколько error-аргументов любого типа. Значения возвращаемых error-аргументов метода содержатся во внутренних полях структуры сообщения-ответа.

Типы и макросы для работы с ошибками содержатся в файле /opt/KasperskyOS-Community-Edition-<version>/toolchain/include/nk/types.h

Упрощенная обработка ошибок

При использовании упрощенной обработки ошибок методы интерфейсов могут иметь не более одного error-аргумента типа UInt16 с именем status.

В случае ошибки:

  • Реализации методов на стороне серверной сущности должны использовать макрос NK_ELOGIC_MAKE() для упаковки кода ошибки и возвращать результат его работы.
  • Соответствующие клиентские интерфейсные методы возвращают код ошибки (логической или транспортной), упакованный в значение типа nk_err_t. Для проверки на наличие в нем логических и транспортных ошибок используются макросы NK_ELOGIC_CHECK() и NK_ETRANSPORT_CHECK() соответственно.

В случае успешной обработки запроса:

  • Реализации методов на стороне серверной сущности должны поместить результаты в соответствующие out-аргументам поля сообщения-ответа и вернуть NK_EOK.
  • Соответствующие клиентские интерфейсные методы также возвращают NK_EOK.

Например, рассмотрим IDL-описание интерфейса, содержащего один метод:

Connection.idl

typedef UInt16 ErrorCode

// пример кода ошибки

const ErrorCode ESendFailed = 10;

interface {

Send(in Handle handle,

in Packet packet,

out UInt32 sentLen,

// метод Send имеет один error-аргумент status типа UInt16

error ErrorCode status

);

}

Реализация серверной сущности:

server.c

...

// реализация метода Send

nk_err_t Send_impl(struct Connection *self,

const struct Connection_Send_req *req,

const struct nk_arena* req_arena,

struct Connection_Send_res* res,

struct nk_arena* res_arena)

{

if (...) {

// в случае успешной обработки запроса помещаем результат в out-аргумент и возвращаем NK_EOK

res->sentLen = value;

return NK_EOK;

} else {

// в случае ошибки возвращаем результат работы макроса NK_ELOGIC_MAKE

return NK_ELOGIC_MAKE(Connection_ESendFailed);

}

Реализация клиентской сущности:

client.c

// значения возвращаемого error-аргумента метода упаковываются в код возврата соответствующего клиентского интерфейсного метода

nk_err_t ret = Connection_Send(ctx,

&req, &req_arena,

&res, NK_NULL);

if (ret == NK_EOK) {

// если ошибок нет, res содержит значения out-аргументов

return res.sentLen;

} else {

if (NK_ELOGIC_CHECK(ret)) {

// обрабатываем логическую ошибку

} else {

// обрабатываем транспортную ошибку

}

}

Расширенная обработка ошибок

При использовании расширенной обработки ошибок методы интерфейсов могут иметь более одного error аргумента любого типа.

В случае ошибки:

  • Реализации методов на стороне серверной сущности должны:
    • использовать макрос nk_err_reset(), чтобы выставить в сообщении-ответе флаг ошибки;
    • поместить коды ошибок в соответствующие error-аргументам поля сообщения-ответа;
    • вернуть NK_EOK.
  • Соответствующие клиентские интерфейсные методы возвращают код транспортной ошибки или NK_EOK, если транспортной ошибки нет. Для проверки наличия в сообщении-ответе логических ошибок используется макрос nk_msg_check_err(). При этом значения возвращаемых error-аргументов метода содержатся во внутренних полях структуры сообщения-ответа.

В случае успешной обработки запроса:

  • Реализации методов на стороне серверной сущности должны поместить результаты в соответствующие out-аргументам поля сообщения-ответа и вернуть NK_EOK.
  • Соответствующие клиентские интерфейсные методы также возвращают NK_EOK.

Например, рассмотрим IDL-описание интерфейса, содержащего один метод:

Connection.idl

typedef UInt16 ErrorCode

interface {

Send(in Handle handle,

in Packet packet,

out UInt32 sentLen,

// метод Send имеет один error-аргумент status типа UInt16

error ErrorCode status

);

}

При этом union-тип, сгенерированный компилятором NK для фиксированной части сообщения-ответа для этого метода, содержит как out-аргументы, так и error-аргументы:

Connection.idl.h

...

struct Connection_Send_res {

union {

struct {

struct nk_message base_;

nk_uint32_t sentLen;

};

struct {

struct nk_message base_;

nk_uint32_t sentLen;

} res_;

struct kl_Connection_Send_err {

struct nk_message base_;

nk_uint16_t status

} err_;

};

};

...

Реализация серверной сущности:

server.c

...

// реализация метода Send

nk_err_t Send_impl(struct Connection *self,

const struct Connection_Send_req *req,

const struct nk_arena* req_arena,

struct Connection_Send_res* res,

struct nk_arena* res_arena)

{

if (...) {

// в случае успешной обработки запроса помещаем результат в out-аргумент и возвращаем NK_EOK

res->sentLen = value;

return NK_EOK;

} else {

// в случае ошибки вызываем макрос nk_err_reset(), чтобы выставить флаг ошибки в сообщении-ответе

nk_err_reset(res)

// заполняем поля err-аргументов в структуре res->err_

res->err_.status = 10;

// возвращаем NK_EOK

return NK_EOK;

}

Реализация клиентской сущности:

client.c

nk_err_t ret = Connection_Send(ctx,

&req, &req_arena,

&res, NK_NULL);

if (ret == NK_EOK) {

if (nk_msg_check_err(res)) {

// обрабатываем логическую ошибку

// значения возвращаемых error-аргументов метода содержится во внутренних полях структуры сообщения-ответа

return res.err_.status;

} else {

// если ошибок нет, res содержит значения out-аргументов

return res.sentLen;

}

} else {

// обрабатываем транспортную ошибку

}