From 7d3b116417cf7f8125a2dd93e4dfc423b9c50aa0 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 16 Mar 2022 22:56:05 -0500 Subject: [PATCH] Progress: Controller and Control sockets. --- level_3/control/c/control.c | 10 +- level_3/control/c/private-control.c | 184 +++++++++++++++++++++++++++++------- level_3/control/c/private-control.h | 43 +++++++-- level_3/control/c/private-print.c | 64 +++++++++++-- level_3/control/c/private-print.h | 41 +++++++- 5 files changed, 288 insertions(+), 54 deletions(-) diff --git a/level_3/control/c/control.c b/level_3/control/c/control.c index bc1ae53..36c5549 100644 --- a/level_3/control/c/control.c +++ b/level_3/control/c/control.c @@ -224,8 +224,6 @@ extern "C" { else { fll_error_print(main->error, F_status_set_fine(status), "control_packet_build", F_true); } - - fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } } @@ -234,7 +232,6 @@ extern "C" { if (F_status_is_error(status)) { fll_error_print(main->error, F_status_set_fine(status), "control_packet_send", F_true); - fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } } @@ -250,8 +247,13 @@ extern "C" { else { fll_error_print(main->error, F_status_set_fine(status), "control_packet_receive", F_true); } + } + else { + status = control_packet_process(main, &data, header); - fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "control_packet_process", F_true); + } } } diff --git a/level_3/control/c/private-control.c b/level_3/control/c/private-control.c index 533265f..4f441a5 100644 --- a/level_3/control/c/private-control.c +++ b/level_3/control/c/private-control.c @@ -62,6 +62,51 @@ extern "C" { } #endif // _di_control_action_identify_ +#ifndef _di_control_action_type_name_ + f_string_static_t control_action_type_name(const uint8_t type) { + + switch (type) { + case control_action_type_freeze_e: + return control_freeze_s; + + case control_action_type_kill_e: + return control_kill_s; + + case control_action_type_pause_e: + return control_pause_s; + + case control_action_type_reboot_e: + return control_reboot_s; + + case control_action_type_reload_e: + return control_reload_s; + + case control_action_type_rerun_e: + return control_rerun_s; + + case control_action_type_restart_e: + return control_restart_s; + + case control_action_type_resume_e: + return control_resume_s; + + case control_action_type_shutdown_e: + return control_shutdown_s; + + case control_action_type_start_e: + return control_start_s; + + case control_action_type_stop_e: + return control_stop_s; + + case control_action_type_thaw_e: + return control_thaw_s; + } + + return f_string_empty_s; + } +#endif // _di_control_action_type_name_ + #ifndef _di_control_action_verify_ f_status_t control_action_verify(fll_program_data_t * const main, control_data_t * const data) { @@ -315,10 +360,24 @@ extern "C" { f_string_range_t range_packet = macro_f_string_range_t_initialize2(data->cache.large.used); status = fll_fss_basic_list_read(data->cache.large, state, &range_packet, &data->cache.packet_objects, &data->cache.packet_contents, &data->cache.delimits, 0, 0); - if (F_status_is_error(status)) return status; + + if (F_status_is_error(status)) { + control_print_debug_packet_message(main, "Failure while reading FSS Basic List in the response packet", 0, 0, &status); + + if (F_status_set_fine(status) == F_memory_not) { + return status; + } + + return F_status_set_error(F_header); + } status = fl_fss_apply_delimit(data->cache.delimits, &data->cache.large); - if (F_status_is_error(status)) return status; + + if (F_status_is_error(status)) { + control_print_debug_packet_message(main, "Failure while processing delimits for the FSS Basic List in the response packet", 0, 0, &status); + + return F_status_set_error(F_header); + } data->cache.delimits.used = 0; @@ -332,7 +391,9 @@ extern "C" { // The FSS-000E (Payload) standard does not prohibit multiple "header", but such cases are not supported by the controller and the control programs. if (content_header) { - return F_status_set_error(F_packet_not); + control_print_debug_packet_message(main, "Multiple %[" F_fss_string_header_s "%] found in response packet", 0, 0, 0); + + return F_status_set_error(F_payload_not); } content_header = &data->cache.packet_contents.array[i]; @@ -341,15 +402,31 @@ extern "C" { // Only a single "payload" is supported by the FSS-000E (Payload) standard. if (content_payload) { - return F_status_set_error(F_packet_not); + control_print_debug_packet_message(main, "Multiple %[" F_fss_string_payload_s "%] found in response packet", 0, 0, 0); + + return F_status_set_error(F_payload_not); + } + + if (i + 1 < data->cache.packet_contents.used) { + control_print_debug_packet_message(main, "Invalid FSS Payload format, the %[" F_fss_string_payload_s "%] is required to be the last FSS Basic List Object", 0, 0, 0); + + return F_status_set_error(F_payload_not); } content_payload = &data->cache.packet_contents.array[i]; } } // for - if (!content_header || !content_payload) { - return F_status_set_error(F_packet_not); + if (!content_header) { + control_print_debug_packet_message(main, "Did not find a %[" F_fss_string_header_s "%] in the response packet", 0, 0, 0); + + return F_status_set_error(F_payload_not); + } + + if (!content_payload) { + control_print_debug_packet_message(main, "Did not find a %[" F_fss_string_payload_s "%] in the response packet", 0, 0, 0); + + return F_status_set_error(F_payload_not); } range_header = content_header->array[0]; @@ -362,21 +439,31 @@ extern "C" { f_number_unsigned_t number = 0; f_string_range_t range = range_header; - status = fll_fss_basic_list_read(data->cache.large, state, &range, &data->cache.header_objects, &data->cache.header_contents, &data->cache.delimits, 0, 0); - if (F_status_is_error(status)) return F_status_set_error(status); + status = fll_fss_extended_read(data->cache.large, state, &range, &data->cache.header_objects, &data->cache.header_contents, 0, 0, &data->cache.delimits, 0); + + if (F_status_is_error(status)) { + control_print_debug_packet_message(main, "Failure while reading FSS Extended in the response packet", 0, 0, &status); + + if (F_status_set_fine(status) == F_memory_not) { + return status; + } + + return F_status_set_error(F_header_not); + } status = fl_fss_apply_delimit(data->cache.delimits, &data->cache.large); - if (F_status_is_error(status)) return status; - if (!data->cache.header_contents.used) { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_header); + if (F_status_is_error(status)) { + control_print_debug_packet_message(main, "Failure while processing delimits for the FSS Basic List in the response packet", 0, 0, &status); + + return F_status_set_error(F_header_not); } - // @todo walk through each range in header_objects, match the first "header" object, get the range from header_contents.array[0], reset the header_objects and header_contents and then pass the retrieved range to the fll_fss_extended_read() function below. + if (!data->cache.header_contents.used) { + control_print_debug_packet_message(main, "Did not find any Content within the %[" F_fss_string_header_s "%]", 0, 0, 0); - //status = fll_fss_extended_read(data->cache.large, state, &range, &data->cache.header_objects, &data->cache.header_contents, &data->cache.delimits, 0, 0); - if (F_status_is_error(status)) return F_status_set_error(status); + return F_status_set_error(F_header_not); + } for (i = 0; i < data->cache.header_objects.used; ++i) { @@ -396,8 +483,9 @@ extern "C" { header->action = control_action_identify(main, data, action); if (!header->action) { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_header); + control_print_debug_packet_message(main, "Failed to identify %[" CONTROL_action_s "%] from: ", &data->cache.large, &data->cache.header_contents.array[i].array[0], 0); + + return F_status_set_error(F_header_not); } } else { @@ -411,17 +499,18 @@ extern "C" { control_print_debug_packet_header_object_and_content(main, control_length_s, data->cache.large, data->cache.header_contents.array[i].array[0]); - // First attempt to get status as a number. status = fl_conversion_dynamic_partial_to_number_unsigned(data->cache.large, data->cache.header_contents.array[i].array[0], &number); if (F_status_is_error(status)) { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_status); + control_print_debug_packet_message(main, "Failed to process number for %[" CONTROL_length_s "%] in the response packet, number is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], &status); + + return F_status_set_error(F_header_not); } - if (number > F_status_size_max_with_bits_d) { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_status); + if (number > F_type_size_max_32_unsigned_d) { + control_print_debug_packet_message(main, "Processed number for %[" CONTROL_length_s "%] exceeds allowed size in the response packet, number is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], &status); + + return F_status_set_error(F_header_not); } header->length = (uint16_t) number; @@ -437,10 +526,12 @@ extern "C" { control_print_debug_packet_header_object_and_content(main, control_status_s, data->cache.large, data->cache.header_contents.array[i].array[0]); - // First attempt to get status as a number. + // Attempt to get status as a number. status = fl_conversion_dynamic_partial_to_number_unsigned(data->cache.large, data->cache.header_contents.array[i].array[0], &number); if (F_status_set_fine(status) == F_number) { + + // Not a number, so attempt get by status string name. const f_array_length_t name_length = (data->cache.header_contents.array[i].array[0].stop - data->cache.header_contents.array[i].array[0].start) + 1; char name_string[name_length + 1]; const f_string_static_t name = macro_f_string_static_t_initialize(name_string, 0, name_length); @@ -451,13 +542,26 @@ extern "C" { status = fll_status_string_from(name, &header->status); if (F_status_is_error(status)) { - // @todo if debug print the reason for the failure. - return status; + control_print_debug_packet_message(main, "Failed to process %[" CONTROL_status_s "%] in the response packet, Content is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], &status); + + return F_status_set_error(F_header_not); } } else if (F_status_is_error(status)) { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_status); + control_print_debug_packet_message(main, "Failed to process number for %[" CONTROL_status_s "%] in the response packet, number is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], &status); + + if (F_status_set_fine(status) == F_memory_not) { + return status; + } + + return F_status_set_error(F_header_not); + } + else { + if (number > F_status_size_max_with_bits_d) { + control_print_debug_packet_message(main, "Processed number for %[" CONTROL_status_s "%] exceeds allowed size in the response packet, number is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], 0); + + return F_status_set_error(F_header_not); + } } } else { @@ -477,8 +581,9 @@ extern "C" { header->type = control_payload_type_error_e; } else { - // @todo if debug print the reason for the failure. - return F_status_set_error(F_header); + control_print_debug_packet_message(main, "Unknown %[" CONTROL_type_s "%] in response packet, Content is:", &data->cache.large, &data->cache.header_contents.array[i].array[0], 0); + + return F_status_set_error(F_header_not); } } else { @@ -487,16 +592,27 @@ extern "C" { } } } - - // @todo based on header->type, handle the data. if type is control_payload_type_error_e, then check the header->length and conditionally get the message from the payload content. - // @todo this handling may likely be moved outside of this function. } - // @todo return F_none; } #endif // _di_control_packet_receive_ +#ifndef _di_control_packet_process_ + f_status_t control_packet_process(fll_program_data_t * const main, control_data_t * const data, const control_payload_header_t header) { + + if (header.type == control_payload_type_error_e) { + control_print_error_packet_response(main, data, header); + + return F_none; + } + + // @todo based on header->type, handle the data. + + return F_none; + } +#endif // _di_control_packet_process_ + #ifndef _di_control_packet_send_ f_status_t control_packet_send(fll_program_data_t * const main, control_data_t * const data) { diff --git a/level_3/control/c/private-control.h b/level_3/control/c/private-control.h index 89b7bf3..3ac9d5c 100644 --- a/level_3/control/c/private-control.h +++ b/level_3/control/c/private-control.h @@ -32,6 +32,19 @@ extern "C" { #endif // _di_control_action_identify_ /** + * Get the name of the action type. + * + * @param type + * The action type id. + * + * @return + * The string associated with the action type. + */ +#ifndef _di_control_action_type_name_ + extern f_string_static_t control_action_type_name(const uint8_t type) F_attribute_visibility_internal_d; +#endif // _di_control_action_type_name_ + +/** * Verify that the additional parameters are reasonably correct for the identified action. * * @param main @@ -83,32 +96,46 @@ extern "C" { * @return * F_none on success. * - * F_header (with error bit) If there is a problem processing the packet header. + * F_header_not (with error bit) If there is a problem processing the packet header. + * F_memory_not (with error bit) On out of memory issues (this is passed through from called functions). * F_packet_not (with error bit) If the received packet is not a valid packet or not a supported packet structure. + * F_payload_not (with error bit) If there is a problem processing the packet payload. * F_too_large (with error bit) If the received packet specifies a size that is too large or the actual size is larger than the specified size. * F_too_small (with error bit) If the received packet actual size is smaller than the specified size. * * Errors (with error bit) from: f_socket_read(). - * Errors (with error bit) from: f_string_dynamic_append(). * Errors (with error bit) from: f_string_dynamic_increase_by(). - * Errors (with error bit) from: f_string_dynamic_resize(). - * Errors (with error bit) from: fl_fss_apply_delimit(). - * Errors (with error bit) from: fll_fss_basic_list_read(). + * Errors (with error bit) from: fl_conversion_dynamic_partial_to_number_unsigned(). * Errors (with error bit) from: fll_fss_extended_read(). + * Errors (with error bit) from: fll_fss_basic_list_read(). * * @see f_socket_read() - * @see f_string_dynamic_append() * @see f_string_dynamic_increase_by() - * @see f_string_dynamic_resize() + * @see fl_conversion_dynamic_partial_to_number_unsigned() * @see fl_fss_apply_delimit() - * @see fll_fss_basic_list_read() * @see fll_fss_extended_read() + * @see fll_fss_basic_list_read() + * @see fll_status_string_from() */ #ifndef _di_control_packet_receive_ extern f_status_t control_packet_receive(fll_program_data_t * const main, control_data_t * const data, control_payload_header_t * const header) F_attribute_visibility_internal_d; #endif // _di_control_packet_receive_ /** + * Process the received and loaded packet. + * + * @param main + * The main program data. + * @param data + * The control data. + * @param header + * The control payload packet header data. + */ +#ifndef _di_control_packet_process_ + extern f_status_t control_packet_process(fll_program_data_t * const main, control_data_t * const data, const control_payload_header_t header) F_attribute_visibility_internal_d; +#endif // _di_control_packet_process_ + +/** * Send the payload to the remote socket, getting the payload from the large cache. * * @param main diff --git a/level_3/control/c/private-print.c b/level_3/control/c/private-print.c index e218a7f..5a31503 100644 --- a/level_3/control/c/private-print.c +++ b/level_3/control/c/private-print.c @@ -1,5 +1,6 @@ #include "control.h" #include "private-common.h" +#include "private-control.h" #include "private-print.h" #ifdef __cplusplus @@ -7,19 +8,70 @@ extern "C" { #endif #ifndef _di_control_print_debug_packet_header_object_and_content_ - void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t range_content) { + void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t content_range) { if (main->output.verbosity == f_console_verbosity_debug_e) return; - flockfile(main->error.to.stream); + flockfile(main->output.to.stream); fl_print_format("%rPacket header Object '%[%Q%]", main->output.to.stream, f_string_eol_s, main->context.set.notable, object, main->context.set.notable); - fl_print_format("' has value '%[%/Q%]'.%r", main->output.to.stream, main->context.set.notable, content, range_content, main->context.set.notable, f_string_eol_s); + fl_print_format("' has value '%[%/Q%]'.%r", main->output.to.stream, main->context.set.notable, content, content_range, main->context.set.notable, f_string_eol_s); - funlockfile(main->error.to.stream); + funlockfile(main->output.to.stream); } #endif // _di_control_print_debug_packet_header_object_and_content_ +#ifndef _di_control_print_debug_packet_message_ + void control_print_debug_packet_message(fll_program_data_t * const main, const f_string_t message, const f_string_static_t *buffer, const f_string_range_t *range, const f_status_t *status) { + + if (main->output.verbosity == f_console_verbosity_debug_e) return; + + flockfile(main->output.to.stream); + + fl_print_format("%r%s", main->output.to.stream, f_string_eol_s, message, main->context.set.notable, main->context.set.notable); + + if (buffer) { + if (range) { + fl_print_format("'%[%/Q%]'", main->output.to.stream, main->context.set.notable, *buffer, *range, main->context.set.notable); + } + else { + fl_print_format("'%[%/Q%]'", main->output.to.stream, main->context.set.notable, *buffer, main->context.set.notable); + } + } + + if (status) { + fl_print_format(", with status code %[%ui%]'", main->output.to.stream, main->context.set.notable, *status, main->context.set.notable); + } + + fl_print_format(".%r", main->output.to.stream, f_string_eol_s); + + funlockfile(main->output.to.stream); + } +#endif // _di_control_print_debug_packet_message_ + +#ifndef _di_control_print_error_packet_response_ + void control_print_error_packet_response(fll_program_data_t * const main, control_data_t * const data, const control_payload_header_t header) { + + if (main->error.verbosity == f_console_verbosity_quiet_e) return; + + flockfile(main->error.to.stream); + + fl_print_format("%r%[%QReceived error response for " CONTROL_action_s " '%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error); + fl_print_format("%[%Q%]", main->error.to.stream, main->context.set.notable, control_action_type_name(header.action), main->context.set.notable); + fl_print_format("%[' (with status %[", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s); + fl_print_format("%[%ui%]", main->error.to.stream, main->context.set.notable, header.status, main->context.set.notable); + + if (header.length) { + fl_print_format("%[): %/Q%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, data->cache.large, data->cache.header_contents.array[0].array[0], f_string_eol_s); + } + else { + fl_print_format("%[).%]%r", main->error.to.stream, main->context.set.error, main->context.set.error, f_string_eol_s); + } + + funlockfile(main->error.to.stream); + } +#endif // _di_control_print_error_packet_response_ + #ifndef _di_control_print_error_parameter_actions_none_ void control_print_error_parameter_actions_none(fll_program_data_t * const main) { @@ -163,7 +215,7 @@ extern "C" { if (main->error.verbosity == f_console_verbosity_quiet_e) return; - fll_print_format("%r%[%QThe received response is not a valid or supported packet.'%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error); + fll_print_format("%r%[%QThe received response is not a valid or supported packet.%]%r", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s); } #endif // _di_control_print_error_response_packet_valid_not_ @@ -172,7 +224,7 @@ extern "C" { if (main->error.verbosity == f_console_verbosity_quiet_e) return; - fll_print_format("%r%[%QThe generated packet is too large, cannot send packet.'%]", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error); + fll_print_format("%r%[%QThe generated packet is too large, cannot send packet.%]%r", main->error.to.stream, f_string_eol_s, main->context.set.error, main->error.prefix, main->context.set.error, f_string_eol_s); } #endif // _di_control_print_error_request_packet_too_large_ diff --git a/level_3/control/c/private-print.h b/level_3/control/c/private-print.h index 78396b8..4c0cc1e 100644 --- a/level_3/control/c/private-print.h +++ b/level_3/control/c/private-print.h @@ -21,14 +21,51 @@ extern "C" { * The object string. * @param content * The content string. - * @param range_content + * @param content_range * The range representing the content where the content is found within the content string. */ #ifndef _di_control_print_debug_packet_header_object_and_content_ - extern void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t range_content) F_attribute_visibility_internal_d; + extern void control_print_debug_packet_header_object_and_content(fll_program_data_t * const main, const f_string_static_t object, const f_string_static_t content, const f_string_range_t content_range) F_attribute_visibility_internal_d; #endif // _di_control_print_debug_packet_header_object_and_content_ /** + * Print a debug message regarding some packet. + * + * @param main + * The main program data. + * @param message + * The message to print. + * + * A single "%[" followed by a single "%]" is supported in the message and is replaced with "notable" context. + * @param buffer + * (optional) An additonal message to print (this is syntax highlighted). + * Set to NULL to not use. + * @param range + * (optional) The range within the buffer to print rather than printing the entire buffer. + * Set to NULL to not use. + * This is ignored when buffer is NULL. + * @param status + * (optional) A status code that triggered the failure (this is syntax highlighted). + * Set to NULL to not use. + */ +#ifndef _di_control_print_debug_packet_message_ + extern void control_print_debug_packet_message(fll_program_data_t * const main, const f_string_t message, const f_string_static_t *buffer, const f_string_range_t *range, const f_status_t *status) F_attribute_visibility_internal_d; +#endif // _di_control_print_debug_packet_message_ + +/** + * Print an error from the packet response. + * + * @param main + * The main program data. + * @param data + * The control data. + * @param header + * The control payload packet header data. + */ +#ifndef _di_control_print_error_packet_response_ + extern void control_print_error_packet_response(fll_program_data_t * const main, control_data_t * const data, const control_payload_header_t header) F_attribute_visibility_internal_d; +#endif // _di_control_print_error_packet_response_ +/** * Print an error message about no actions being provided. * * @param main -- 1.8.3.1