Работа с ошибками в 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 {
// обрабатываем транспортную ошибку
}