dey-examples/cccs-data-request-example/main.c

220 lines
6.0 KiB
C

/*
* Copyright 2023, Digi International Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include <cccs_services.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#if !(defined UNUSED_ARGUMENT)
#define UNUSED_ARGUMENT(a) (void)(a)
#endif
#define TARGET_GET_TIME "get_time"
/*
* sigaction_handler() - Handler to execute after receiving a signal
*
* @signum: Received signal.
*/
static void sigaction_handler(int signum)
{
log_debug("%s: received signal %d", __func__, signum);
exit(0);
}
/*
* cleanup() - Frees all the allocated memory before exiting
*/
static void cleanup(void)
{
cccs_resp_t resp;
cccs_comm_error_t ret;
ret = cccs_remove_request_target(TARGET_GET_TIME, &resp);
if (ret != CCCS_SEND_ERROR_NONE) {
log_error("%s: Cannot unregister target '%s': CCCSD error %d",
__func__, TARGET_GET_TIME, ret);
} else if (resp.code != 0) {
if (resp.hint)
log_error("%s: Cannot unregister target '%s': CCCSD error, %s (%d)",
__func__, TARGET_GET_TIME, resp.hint, resp.code);
else
log_error("%s: Cannot unregister target '%s': CCCSD error, %d",
__func__, TARGET_GET_TIME, resp.code);
}
free(resp.hint);
deinit_logger();
}
/*
* register_signals() - Registers program signals
*/
static void register_signals(void)
{
struct sigaction new_action;
struct sigaction old_action;
atexit(cleanup);
new_action.sa_handler = sigaction_handler;
new_action.sa_flags = 0;
sigemptyset(&new_action.sa_mask);
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGINT, &new_action, NULL);
sigaction(SIGHUP, &old_action, NULL);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGHUP, &new_action, NULL);
sigaction(SIGTERM, &old_action, NULL);
if (old_action.sa_handler != SIG_IGN)
sigaction(SIGTERM, &new_action, NULL);
}
/*
* get_time_cb() - Data callback for 'get_time' data requests
*
* @target: Target ID of the data request (get_time).
* @req_buf_info: Buffer containing the data request.
* @resp_buf_info: Buffer to store the answer of the request.
*
* Logs information about the received request and executes the corresponding
* command.
*
* Return: 'CCCS_RECEIVE_ERROR_NONE' if success, any other value on failure.
*/
static cccs_receive_error_t get_time_cb(char const *const target,
cccs_buffer_info_t const *const req_buf_info,
cccs_buffer_info_t *const resp_buf_info)
{
time_t t = time(NULL);
char *time_str = ctime(&t);
UNUSED_ARGUMENT(req_buf_info);
log_debug("%s: target='%s'", __func__, target);
resp_buf_info->length = snprintf(NULL, 0, "Time: %s", time_str);
resp_buf_info->buffer = calloc(resp_buf_info->length + 1, sizeof(char));
if (resp_buf_info->buffer == NULL) {
log_error("%s: resp_buf_info calloc error", __func__);
return CCCS_RECEIVE_ERROR_INSUFFICIENT_MEMORY;
}
resp_buf_info->length = sprintf(resp_buf_info->buffer, "Time: %s", time_str);
return CCCS_RECEIVE_ERROR_NONE;
}
/*
* get_time_status_cb() - Status callback for 'get_time' data requests
*
* @target: Target ID of the data request (get_time)
* @resp_buf_info: Buffer containing the response data.
* @receive_error: The error status of the receive process.
* @receive_error_hint: The error hint from the connector service.
*
* This callback is executed when the response process has finished. It doesn't
* matter if everything worked or there was an error during the process.
*
* Cleans and frees the response buffer.
*/
static void get_time_status_cb(char const *const target,
cccs_buffer_info_t *const resp_buf_info,
int receive_error,
const char *const receive_error_hint)
{
log_debug("%s: target='%s' - error='%d' - error-hint='%s'",
__func__, target, receive_error, receive_error_hint);
/* Free the response buffer */
if (resp_buf_info != NULL)
free(resp_buf_info->buffer);
}
/*
* Use the following SCI request to test this example (insert your Device ID):
*
* <sci_request version="1.0">
* <data_service>
* <targets>
* <device id="00000000-00000000-XXXXXXXX-XXXXXXXX"/>
* </targets>
* <requests>
* <device_request target_name="get_time"/>
* </requests>
* </data_service>
* </sci_request>
*
*/
int main(int argc, char *argv[])
{
cccs_comm_error_t ret;
char *name = basename(argv[0]);
cccs_resp_t resp;
int read_char;
init_logger(LOG_DEBUG, LOG_CONS | LOG_NDELAY | LOG_PID | LOG_PERROR, name);
register_signals();
if (!cccs_is_daemon_ready(CCCSD_NO_WAIT)) {
log_error("%s: CCCS daemon not ready... exiting", __func__);
return EXIT_FAILURE;
}
ret = cccs_add_request_target(TARGET_GET_TIME, get_time_cb,
get_time_status_cb, &resp);
if (ret != CCCS_SEND_ERROR_NONE) {
log_error("%s: Cannot register target '%s': CCCSD error %d",
__func__, TARGET_GET_TIME, ret);
return EXIT_FAILURE;
} else if (resp.code != 0) {
if (resp.hint) {
log_error("%s: Cannot register target '%s': CCCSD error, %s (%d)",
__func__, TARGET_GET_TIME, resp.hint, resp.code);
free(resp.hint);
} else {
log_error("%s: Cannot register target '%s': CCCSD error, %d",
__func__, TARGET_GET_TIME, resp.code);
}
return EXIT_FAILURE;
}
free(resp.hint);
printf("Waiting for Remote Manager request...\n");
printf("Press 'q' and 'Enter' to exit\n");
do {
read_char = getchar();
} while (read_char != 'q');
return EXIT_SUCCESS;
}