Isolated Processing Tasks
The next step to developing an IoT system using CACIc-DevKit is programming the processing tasks. Each publication request type can have its own processing task, which defines what kind of processing will be applied once the publication message is received. The developer can program C/C++ codes with the following structure:
server_error_t task_name
(char* time,
char* pk,
char* payload,
uint32_t payload_size,
uint8_t* client_key,
uint8_t* storage_key,
uint8_t* result,
uint32_t* p_result_size);
The parameters are the following:
time: date and time at which the publication request was sent.pk: identification of the sending client.payload: buffer containing the publication request itself. It can be a sensor data or metadatas concerning the processing task. The developer is free to choose the payload format of each publication request type.payload_size: in number of bytes in the array.client_key: 16 bytes array containing the AES communication key used to encrypt messages exchanged between client and server. See About CACIC section for more details.storage_key: 16 bytes array containing the AES storage key used to encrypt stored data. see About CACIC section for more details.result: buffer containing the processing result, that will be encrypted and written in the database accordingly to thepublish_db()function. See Pluggable Database section for more details.result_size: in number of bytes in the array.
The return value is an enum type defined in core/utils/errors.h file.
In the smart grid use case, we have defined a task called aggregation(), which is
called when the server receives a publication request of type aggregate (type code 555555).
The payload is an SQLite statement for querying the result of
smart-meter-sample (type code 123456) requests, that were previously published and
aggregating the numeric data. The publication request of type smart-meter-sample (type code 123456)
does not have an associated processing task.
For associating data types with processing tasks, the developer must access the file
programmable_calls/server_tasks_calls.cpp and modify the following line:
std::vector<task_function_t> tasks{NULL, &aggregation};
The first i-th vector represents a pointer to a function that implements the processing task
corresponding to the i-th publication request type in the types vector, defined in the
section Publication Requests Types. You can use NULL when you do not want
to associate the publication request type with a processing task. In that case, the received
payload will just be internally copied to the result buffer.
The aggregation() function is implemented in the file programmable_calls/server_tasks_calls.cpp.
The file core/server/server_enclave/server_enclave_auxiliary.h defines some functions
that can be used in the processing tasks. As an example, we may use the following function in
aggregation():
server_error_t enclave_multi_query_db(
char* pk,
uint8_t* key,
char* command,
char** datas,
uint32_t* datas_sizes,
uint32_t* p_data_count);
This function exits the enclave, executes the multi_query_db() function to query some data
from the database, decrypt the data, verify access permissions, perform some security checks
behind the scenes, and returns the decrypted data to the enclave.