/* * 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 #include #include #include #include #include #include #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): * * * * * * * * * * * * */ 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; }