From 538cf0c9d82fafd7be4e803ca6dded9bc5589cdf Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Sun, 6 Mar 2022 16:56:52 -0600 Subject: [PATCH] Progress: Implement controller to/from control networking. Continue implementing the contoller to control communication. I thought I described the packet structures in addition to the payload structure. It seems I have not. This begins adding the packet structure documentation. --- level_0/f_console/c/console.h | 2 +- level_0/f_fss/c/fss/common.h | 6 + level_3/control/c/control.c | 27 +- level_3/control/c/private-common.c | 8 +- level_3/control/c/private-common.h | 21 +- level_3/control/c/private-control.c | 180 +++++++++++--- level_3/control/c/private-control.h | 36 +++ level_3/controller/c/common/private-common.h | 2 +- level_3/controller/c/common/private-control.h | 51 ++-- level_3/controller/c/common/private-lock.c | 2 +- level_3/controller/c/common/private-lock.h | 2 +- level_3/controller/c/common/private-setting.c | 6 +- level_3/controller/c/common/private-setting.h | 63 +++-- level_3/controller/c/common/private-thread.h | 3 - level_3/controller/c/control/private-control.c | 44 ++-- level_3/controller/c/control/private-control.h | 14 +- level_3/controller/c/controller.c | 29 +-- .../controller/c/controller/private-controller.c | 272 +++++++++++---------- .../controller/c/controller/private-controller.h | 37 +++ level_3/controller/c/entry/private-entry.c | 13 +- level_3/controller/c/lock/private-lock.c | 10 +- level_3/controller/c/thread/private-thread.c | 6 - .../controller/c/thread/private-thread_control.c | 73 +++--- .../controller/c/thread/private-thread_control.h | 17 -- level_3/controller/c/thread/private-thread_entry.c | 9 +- .../controller/c/thread/private-thread_process.c | 7 + .../controller/c/thread/private-thread_signal.c | 2 +- level_3/controller/documents/packet.txt | 67 ++++- level_3/controller/specifications/packet.txt | 12 +- 29 files changed, 661 insertions(+), 360 deletions(-) diff --git a/level_0/f_console/c/console.h b/level_0/f_console/c/console.h index bf2cb95..f091d14 100644 --- a/level_0/f_console/c/console.h +++ b/level_0/f_console/c/console.h @@ -21,7 +21,7 @@ #include #include -// fll-0 console includes +// fll-0 console includes. #include #ifdef __cplusplus diff --git a/level_0/f_fss/c/fss/common.h b/level_0/f_fss/c/fss/common.h index 76a2b68..e8992ba 100644 --- a/level_0/f_fss/c/fss/common.h +++ b/level_0/f_fss/c/fss/common.h @@ -78,6 +78,12 @@ extern "C" { #define f_fss_embedded_list_open_end_s f_string_eol_s #define f_fss_embedded_list_close_s f_fss_brace_close_s #define f_fss_embedded_list_close_end_s f_string_eol_s + #define f_fss_payload_header_open_s f_fss_space_s + #define f_fss_payload_header_next_s f_fss_space_s + #define f_fss_payload_header_close_s f_string_eol_s + #define f_fss_payload_list_open_s f_fss_colon_s + #define f_fss_payload_list_open_end_s f_string_eol_s + #define f_fss_payload_list_close_s f_string_eol_s #define f_fss_type_header_open_s f_fss_pound_s #define f_fss_type_header_part1_s f_fss_space_s #define f_fss_type_header_part2_s f_fss_f_s diff --git a/level_3/control/c/control.c b/level_3/control/c/control.c index 7e6c8da..475b1c8 100644 --- a/level_3/control/c/control.c +++ b/level_3/control/c/control.c @@ -208,13 +208,36 @@ extern "C" { data.socket.address = (struct sockaddr *) &socket_address; data.socket.domain = f_socket_domain_file_d; - data.socket.type = f_socket_type_datagram_d; + data.socket.type = f_socket_type_stream_d; data.socket.length = sizeof(struct sockaddr_un); status = control_settings_load(main, &data); if (F_status_is_error_not(status)) { - // @todo construct the packet, send the packet to the controller, and process the response. + status = control_payload_build(main, &data); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "control_payload_build", F_true); + fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); + } + } + + if (F_status_is_error_not(status)) { + status = control_payload_send(main, &data); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "control_payload_send", F_true); + fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); + } + } + + if (F_status_is_error_not(status)) { + status = control_payload_receive(main, &data); + + if (F_status_is_error(status)) { + fll_error_print(main->error, F_status_set_fine(status), "control_payload_receive", F_true); + fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); + } } if (data.socket.id != -1) { diff --git a/level_3/control/c/private-common.c b/level_3/control/c/private-common.c index 97ecf47..505b213 100644 --- a/level_3/control/c/private-common.c +++ b/level_3/control/c/private-common.c @@ -16,12 +16,16 @@ extern "C" { #ifndef _di_control_strings_s_ const f_string_static_t control_path_settings_s = macro_f_string_static_t_initialize(CONTROL_path_settings_s, 0, CONTROL_path_settings_s_length); + const f_string_static_t control_action_s = macro_f_string_static_t_initialize(CONTROLLER_action_s, 0, CONTROLLER_action_s_length); const f_string_static_t control_command_s = macro_f_string_static_t_initialize(CONTROL_command_s, 0, CONTROL_command_s_length); const f_string_static_t control_default_s = macro_f_string_static_t_initialize(CONTROL_default_s, 0, CONTROL_default_s_length); + const f_string_static_t control_length_s = macro_f_string_static_t_initialize(CONTROLLER_length_s, 0, CONTROLLER_length_s_length); const f_string_static_t control_name_socket_s = macro_f_string_static_t_initialize(CONTROL_name_socket_s, 0, CONTROL_name_socket_s_length); const f_string_static_t control_path_socket_s = macro_f_string_static_t_initialize(CONTROL_path_socket_s, 0, CONTROL_path_socket_s_length); const f_string_static_t control_path_socket_prefix_s = macro_f_string_static_t_initialize(CONTROL_path_socket_prefix_s, 0, CONTROL_path_socket_prefix_s_length); const f_string_static_t control_path_socket_suffix_s = macro_f_string_static_t_initialize(CONTROL_path_socket_suffix_s, 0, CONTROL_path_socket_suffix_s_length); + const f_string_static_t control_status_s = macro_f_string_static_t_initialize(CONTROLLER_status_s, 0, CONTROLLER_status_s_length); + const f_string_static_t control_type_s = macro_f_string_static_t_initialize(CONTROLLER_type_s, 0, CONTROLLER_type_s_length); const f_string_static_t control_error_s = macro_f_string_static_t_initialize(CONTROL_error_s, 0, CONTROL_error_s_length); const f_string_static_t control_freeze_s = macro_f_string_static_t_initialize(CONTROL_freeze_s, 0, CONTROL_freeze_s_length); @@ -41,8 +45,8 @@ extern "C" { #ifndef _di_control_data_delete_ void control_data_delete(control_data_t * const data) { - f_string_dynamic_resize(0, &data->cache.buffer_large); - f_string_dynamic_resize(0, &data->cache.buffer_small); + f_string_dynamic_resize(0, &data->cache.large); + f_string_dynamic_resize(0, &data->cache.small); } #endif // _di_control_data_delete_ diff --git a/level_3/control/c/private-common.h b/level_3/control/c/private-common.h index 039994e..8888cc9 100644 --- a/level_3/control/c/private-common.h +++ b/level_3/control/c/private-common.h @@ -115,12 +115,16 @@ extern "C" { #define CONTROL_path_settings_s_length 21 #endif // defined(_override_control_path_settings_) && defined(_override_control_path_settings_length_) + #define CONTROL_action_s "action" #define CONTROL_command_s "command" #define CONTROL_default_s "default" + #define CONTROL_length_s "length" #define CONTROL_name_socket_s "name_socket" #define CONTROL_path_socket_s "path_socket" #define CONTROL_path_socket_prefix_s "path_socket_prefix" #define CONTROL_path_socket_suffix_s "path_socket_suffix" + #define CONTROL_status_s "status" + #define CONTROL_type_s "type" #define CONTROL_error_s "error" #define CONTROL_freeze_s "freeze" @@ -142,6 +146,10 @@ extern "C" { #define CONTROL_path_socket_s_length 11 #define CONTROL_path_socket_prefix_s_length 18 #define CONTROL_path_socket_suffix_s_length 18 + #define CONTROL_type_s_length 4 + #define CONTROL_status_s_length 6 + #define CONTROL_length_s_length 6 + #define CONTROL_action_s_length 6 #define CONTROL_error_s_length 5 #define CONTROL_freeze_s_length 6 @@ -159,12 +167,16 @@ extern "C" { extern const f_string_static_t control_path_settings_s; + extern const f_string_static_t control_action_s; extern const f_string_static_t control_command_s; extern const f_string_static_t control_default_s; + extern const f_string_static_t control_length_s; extern const f_string_static_t control_name_socket_s; extern const f_string_static_t control_path_socket_s; extern const f_string_static_t control_path_socket_prefix_s; extern const f_string_static_t control_path_socket_suffix_s; + extern const f_string_static_t control_status_s; + extern const f_string_static_t control_type_s; extern const f_string_static_t control_error_s; extern const f_string_static_t control_freeze_s; @@ -217,13 +229,13 @@ extern "C" { /** * The control cache. * - * buffer_large: A buffer for storing large sets of data. - * buffer_small: A buffer for storing small sets of data. + * large: A buffer for storing large sets of data. + * small: A buffer for storing small sets of data. */ #ifndef _di_control_cache_t_ typedef struct { - f_string_dynamic_t buffer_large; - f_string_dynamic_t buffer_small; + f_string_dynamic_t large; + f_string_dynamic_t small; } control_cache_t; #define control_cache_initialize \ @@ -257,6 +269,7 @@ extern "C" { 0, \ f_string_dynamic_t_initialize, \ f_socket_t_initialize, \ + /*f_string_dynamic_t_initialize,*/ \ 0, \ } #endif // _di_control_data_t_ diff --git a/level_3/control/c/private-control.c b/level_3/control/c/private-control.c index 5b6f8d6..96ff167 100644 --- a/level_3/control/c/private-control.c +++ b/level_3/control/c/private-control.c @@ -133,8 +133,9 @@ extern "C" { return F_none; } + // @todo the reboot and shutdown need to support date and time commands: "now", "in (a time)", and "at (a time)". if (data->command == control_command_type_reboot_e) { - // @todo + // @todo (also needs to support kexec calls or kexec needs its own command, which will likely be in the controller program.) } if (data->command == control_command_type_shutdown_e) { @@ -145,20 +146,123 @@ extern "C" { } #endif // _di_control_command_verify_ +#ifndef _di_control_payload_build_ + f_status_t control_payload_build(fll_program_data_t * const main, control_data_t * const data) { + + data->cache.large.used = 0; + data->cache.small.used = 0; + + f_array_length_t i = 0; + f_array_length_t length = f_fss_string_header_s.used + f_fss_string_payload_s.used + control_action_s.used + control_type_s.used; + length += f_fss_payload_list_open_s.used * 2; + length += f_fss_payload_list_close_s.used * 4 + length += f_string_ascii_0_s.used; + + for (; i < main->parameters.remaining.used; ++i) { + length += f_fss_payload_header_open_s.used + data->argv[main->parameters.remaining.array[i]].used + f_fss_payload_header_close_s.used; + } // for + + status = f_string_dynamic_resize(length + 11, &data->cache.large); + if (F_status_is_error(status)) return status; + + // @todo append the string bit and the length bits. + + // The "header:" line. + status = f_string_dynamic_append(f_fss_string_header_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_list_open_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_list_close_sa, &data->cache.large); + if (F_status_is_error(status)) return status; + + // The "type ..." line. + status = f_string_dynamic_append(control_type_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_open_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(data->argv[main->parameters.remaining.array[0]], &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_close_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + // Each "action ..." line. + for (i = 1; i < main->parameters.remaining.used; ++i) { + + status = f_string_dynamic_append(control_action_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_open_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(data->argv[main->parameters.remaining.array[i]], &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_close_s, &data->cache.large); + if (F_status_is_error(status)) return status; + } // for + + // The "length 0" line. + status = f_string_dynamic_append(control_length_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_open_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_string_ascii_0_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_header_close_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + // The "payload:" line. + status = f_string_dynamic_append(f_fss_string_payload_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_list_open_s, &data->cache.large); + if (F_status_is_error(status)) return status; + + status = f_string_dynamic_append(f_fss_payload_list_close_sa, &data->cache.large); + if (F_status_is_error(status)) return status; + + return F_none; + } +#endif // _di_control_payload_build_ + +#ifndef _di_control_payload_receive_ + f_status_t control_payload_receive(fll_program_data_t * const main, control_data_t * const data) { + + // @todo + return F_none; + } +#endif // _di_control_payload_receive_ + +#ifndef _di_control_payload_send_ + f_status_t control_payload_send(fll_program_data_t * const main, control_data_t * const data) { + + // @todo + return F_none; + } +#endif // _di_control_payload_send_ + #ifndef _di_control_settings_load_ f_status_t control_settings_load(fll_program_data_t * const main, control_data_t * const data) { f_status_t status = F_none; - data->cache.buffer_small.used = 0; + data->cache.small.used = 0; if (main->parameters.array[control_parameter_settings_e].result == f_console_result_additional_e) { const f_array_length_t index = main->parameters.array[control_parameter_settings_e].values.array[main->parameters.array[control_parameter_settings_e].values.used - 1]; - status = f_string_dynamic_append(data->argv[index], &data->cache.buffer_small); + status = f_string_dynamic_append(data->argv[index], &data->cache.small); } else { - status = f_string_dynamic_append(control_path_settings_s, &data->cache.buffer_small); + status = f_string_dynamic_append(control_path_settings_s, &data->cache.small); } if (F_status_is_error(status)) { @@ -170,20 +274,20 @@ extern "C" { { f_file_t file = f_file_t_initialize; - status = f_file_stream_open(data->cache.buffer_small, f_file_open_mode_read_s, &file); + status = f_file_stream_open(data->cache.small, f_file_open_mode_read_s, &file); if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, data->cache.buffer_small, f_file_operation_open_s, fll_error_file_type_file_e); + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_open", F_true, data->cache.small, f_file_operation_open_s, fll_error_file_type_file_e); return status; } - status = f_file_stream_read(file, &data->cache.buffer_large); + status = f_file_stream_read(file, &data->cache.large); f_file_stream_close(F_true, &file); if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_read", F_true, data->cache.buffer_small, f_file_operation_read_s, fll_error_file_type_file_e); + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_stream_read", F_true, data->cache.small, f_file_operation_read_s, fll_error_file_type_file_e); return status; } @@ -195,16 +299,16 @@ extern "C" { f_fss_contents_t contents = f_fss_contents_t_initialize; f_fss_delimits_t delimits = f_fss_delimits_t_initialize; - status = fll_fss_extended_read(data->cache.buffer_large, state, &range, &objects, &contents, 0, 0, &delimits, 0); + status = fll_fss_extended_read(data->cache.large, state, &range, &objects, &contents, 0, 0, &delimits, 0); if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "fll_fss_extended_read", F_true, data->cache.buffer_small, f_file_operation_process_s, fll_error_file_type_file_e); + fll_error_file_print(main->error, F_status_set_fine(status), "fll_fss_extended_read", F_true, data->cache.small, f_file_operation_process_s, fll_error_file_type_file_e); } else { - status = fl_fss_apply_delimit(delimits, &data->cache.buffer_large); + status = fl_fss_apply_delimit(delimits, &data->cache.large); if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, data->cache.buffer_small, f_file_operation_process_s, fll_error_file_type_file_e); + fll_error_file_print(main->error, F_status_set_fine(status), "fl_fss_apply_delimit", F_true, data->cache.small, f_file_operation_process_s, fll_error_file_type_file_e); } } @@ -231,7 +335,7 @@ extern "C" { range.stop = parameter_names[j].used - 1; - if (fl_string_dynamic_partial_compare(parameter_names[j], data->cache.buffer_large, range, objects.array[i]) == F_equal_to) { + if (fl_string_dynamic_partial_compare(parameter_names[j], data->cache.large, range, objects.array[i]) == F_equal_to) { parameter_hass[j] = F_true; parameter_ats[j] = i; @@ -241,18 +345,18 @@ extern "C" { } // for } - data->cache.buffer_small.used = 0; + data->cache.small.used = 0; if (main->parameters.array[control_parameter_socket_e].result == f_console_result_additional_e) { const f_array_length_t index = main->parameters.array[control_parameter_socket_e].values.array[main->parameters.array[control_parameter_socket_e].values.used - 1]; - status = f_string_dynamic_append(data->argv[index], &data->cache.buffer_small); + status = f_string_dynamic_append(data->argv[index], &data->cache.small); } else if (parameter_hass[1]) { - status = f_string_dynamic_partial_append_nulless(data->cache.buffer_large, objects.array[parameter_ats[1]], &data->cache.buffer_small); + status = f_string_dynamic_partial_append_nulless(data->cache.large, objects.array[parameter_ats[1]], &data->cache.small); } else { - status = f_string_dynamic_append(controller_path_socket_s, &data->cache.buffer_small); + status = f_string_dynamic_append(controller_path_socket_s, &data->cache.small); } if (F_status_is_error(status)) { @@ -264,25 +368,25 @@ extern "C" { } } - status = f_file_exists(data->cache.buffer_small); + status = f_file_exists(data->cache.small); if (F_status_is_error(status) || status == F_false) { if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.buffer_small, f_file_operation_find_s, fll_error_file_type_directory_e); + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.small, f_file_operation_find_s, fll_error_file_type_directory_e); if (main->error.verbosity != f_console_verbosity_quiet_e) { fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } } - control_print_error_socket_file_missing(main, data->cache.buffer_small); + control_print_error_socket_file_missing(main, data->cache.small); status = F_status_set_error(F_socket_not); } // Construct the file name when the socket path is a directory. - else if (f_file_is(data->cache.buffer_small, F_file_type_directory_d, F_true) == F_true) { - status = f_string_dynamic_append_assure(f_path_separator_s, &data->cache.buffer_small); + else if (f_file_is(data->cache.small, F_file_type_directory_d, F_true) == F_true) { + status = f_string_dynamic_append_assure(f_path_separator_s, &data->cache.small); if (F_status_is_error(status)) { fll_error_print(main->error, F_status_set_fine(status), "f_string_dynamic_append_assure", F_true); @@ -311,13 +415,13 @@ extern "C" { if (append_ids[i] && main->parameters.array[append_ids[i]].result == f_console_result_additional_e) { const f_array_length_t index = main->parameters.array[append_ids[i]].values.array[main->parameters.array[append_ids[i]].values.used - 1]; - status = f_string_dynamic_append(data->argv[index], &data->cache.buffer_small); + status = f_string_dynamic_append(data->argv[index], &data->cache.small); } else if (append_hass[i]) { - status = f_string_dynamic_partial_append_nulless(data->cache.buffer_large, objects.array[append_hass[i]], &data->cache.buffer_small); + status = f_string_dynamic_partial_append_nulless(data->cache.large, objects.array[append_hass[i]], &data->cache.small); } else { - status = f_string_dynamic_append_nulless(append_defaults[i], &data->cache.buffer_small); + status = f_string_dynamic_append_nulless(append_defaults[i], &data->cache.small); } if (F_status_is_error(status)) { @@ -333,26 +437,26 @@ extern "C" { } // for if (F_status_is_error_not(status)) { - status = f_file_exists(data->cache.buffer_small); + status = f_file_exists(data->cache.small); if (F_status_is_error(status) || status == F_false) { if (F_status_is_error(status)) { - fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.buffer_small, f_file_operation_find_s, fll_error_file_type_directory_e); + fll_error_file_print(main->error, F_status_set_fine(status), "f_file_exists", F_true, data->cache.small, f_file_operation_find_s, fll_error_file_type_directory_e); if (main->error.verbosity != f_console_verbosity_quiet_e) { fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } } - control_print_error_socket_file_missing(main, data->cache.buffer_small); + control_print_error_socket_file_missing(main, data->cache.small); status = F_status_set_error(F_socket_not); } } if (F_status_is_error_not(status)) { - if (f_file_is(data->cache.buffer_small, F_file_type_socket_d, F_true) == F_false) { - control_print_error_socket_file_not(main, data->cache.buffer_small); + if (f_file_is(data->cache.small, F_file_type_socket_d, F_true) == F_false) { + control_print_error_socket_file_not(main, data->cache.small); status = F_status_set_error(F_socket_not); } @@ -368,7 +472,7 @@ extern "C" { fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } - control_print_error_socket_file_failed(main, data->cache.buffer_small); + control_print_error_socket_file_failed(main, data->cache.small); } } @@ -382,7 +486,7 @@ extern "C" { fll_print_dynamic_raw(f_string_eol_s, main->error.to.stream); } - control_print_error_socket_file_failed(main, data->cache.buffer_small); + control_print_error_socket_file_failed(main, data->cache.small); } } } @@ -393,17 +497,17 @@ extern "C" { f_string_rangess_resize(0, &contents); f_array_lengths_resize(0, &delimits); - data->cache.buffer_large.used = 0; - data->cache.buffer_small.used = 0; + data->cache.large.used = 0; + data->cache.small.used = 0; if (F_status_is_error_not(status)) { - if (data->cache.buffer_large.size > control_default_buffer_limit_soft_large_d) { - status = f_string_dynamic_resize(control_default_buffer_limit_soft_large_d, &data->cache.buffer_large); + if (data->cache.large.size > control_default_buffer_limit_soft_large_d) { + status = f_string_dynamic_resize(control_default_buffer_limit_soft_large_d, &data->cache.large); } if (F_status_is_error_not(status)) { - if (data->cache.buffer_small.size > control_default_buffer_limit_soft_small_d) { - status = f_string_dynamic_resize(control_default_buffer_limit_soft_small_d, &data->cache.buffer_small); + if (data->cache.small.size > control_default_buffer_limit_soft_small_d) { + status = f_string_dynamic_resize(control_default_buffer_limit_soft_small_d, &data->cache.small); } } } diff --git a/level_3/control/c/private-control.h b/level_3/control/c/private-control.h index cbcb94e..0ee4988 100644 --- a/level_3/control/c/private-control.h +++ b/level_3/control/c/private-control.h @@ -42,6 +42,42 @@ extern "C" { #ifndef _di_control_command_verify_ extern f_status_t control_command_verify(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d; #endif // _di_control_command_verify_ + +/** + * Build the payload, storing it in the large cache. + * + * @param main + * The main program data. + * @param data + * The control data. + */ +#ifndef _di_control_payload_build_ + extern f_status_t control_payload_build(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_control_payload_build_ + +/** + * Receive the response from the remote socket, storing it in the large cache. + * + * @param main + * The main program data. + * @param data + * The control data. + */ +#ifndef _di_control_payload_receive_ + extern f_status_t control_payload_receive(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_control_payload_receive_ + +/** + * Send the payload to the remote socket, getting the payload from the large cache. + * + * @param main + * The main program data. + * @param data + * The control data. + */ +#ifndef _di_control_payload_send_ + extern f_status_t control_payload_send(fll_program_data_t * const main, control_data_t * const data) F_attribute_visibility_internal_d; +#endif // _di_control_payload_send_ /** * Load and process the control settings file. * diff --git a/level_3/controller/c/common/private-common.h b/level_3/controller/c/common/private-common.h index 019ad32..6318fc3 100644 --- a/level_3/controller/c/common/private-common.h +++ b/level_3/controller/c/common/private-common.h @@ -20,10 +20,10 @@ extern "C" { #include "private-task.h" #include "private-process.h" #include "private-entry.h" +#include "private-control.h" #include "private-setting.h" #include "private-thread.h" #include "private-state.h" -#include "private-control.h" /** * All special strings used within this program. diff --git a/level_3/controller/c/common/private-control.h b/level_3/controller/c/common/private-control.h index 009b8fa..e083498 100644 --- a/level_3/controller/c/common/private-control.h +++ b/level_3/controller/c/common/private-control.h @@ -19,7 +19,7 @@ extern "C" { * - socket_backlog: The amount of waiting client connections to support while handling a socket connection. * - socket_buffer: The preferred max size of the buffer such that if the buffer exceeds this then it is reallocated to this size at the end of processing. * - socket_buffer_max: The max size allowed in the buffer (this value must not be set smaller than the packet headers). - * - socket_cache: The preferred max size of the contol cache such that if the cache exceeds this then it is reallocated to this size at the end of processing. + * - socket_cache: The preferred max size of the control cache such that if the cache exceeds this then it is reallocated to this size at the end of processing. * - socket_header: The minimum size in bytes of the packet header to read to be able to process the size information. * - socket_linger: The number of seconds to linger the connection before closing. * - socket_timeout: The number of microseconds to wait. @@ -36,20 +36,46 @@ extern "C" { #define controller_control_default_socket_payload_max_d 4294965248 #endif // _di_controller_defaults_ + /** - * A structure for control processing. + * The control data. + * + * controller_control_flag_*: + * - readonly: Control is set to read-only mode. + * - has_user: A user is manually specified. + * - has_group: A group is manually specified. + * - has_mode: A file mode is manually specified. * + * flag: Flags from controller_control_flag_*. + * user: The user ID, if specified. + * group: The group ID, if specified. + * mode: The file mode, if specified. * server: The server socket connection. * client: The client socket connection. * cache_1: A generic buffer used for caching control related data. * cache_2: A generic buffer used for caching control related data. + * cache_3: A generic buffer used for caching control related data. * input: A buffer used for receiving data from the client. * output: A buffer used for transmitting data to the client. + * address: The socket address structure. */ #ifndef _di_controller_control_t_ + enum { + controller_control_flag_readonly_e = 0x1, + controller_control_flag_has_user_e = 0x2, + controller_control_flag_has_group_e = 0x4, + controller_control_flag_has_mode_e = 0x8, + }; + typedef struct { - f_socket_t *server; - f_socket_t *client; + uint8_t flag; + + uid_t user; + gid_t group; + mode_t mode; + + f_socket_t server; + f_socket_t client; f_string_dynamic_t cache_1; f_string_dynamic_t cache_2; @@ -57,26 +83,23 @@ extern "C" { f_string_dynamic_t input; f_string_dynamic_t output; + + struct sockaddr_un address; } controller_control_t; #define controller_control_t_initialize { \ 0, \ + -1, \ + -1, \ 0, \ + f_socket_t_initialize, \ + f_socket_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ - } - - #define macro_controller_control_t_initialize(server, client) { \ - 0, \ - 0, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ - f_string_dynamic_t_initialize, \ + { }, \ } #endif // _di_controller_control_t_ diff --git a/level_3/controller/c/common/private-lock.c b/level_3/controller/c/common/private-lock.c index 050b94a..84cc685 100644 --- a/level_3/controller/c/common/private-lock.c +++ b/level_3/controller/c/common/private-lock.c @@ -44,8 +44,8 @@ extern "C" { #ifndef _di_controller_lock_delete_simple_ void controller_lock_delete_simple(controller_lock_t * const lock) { - controller_lock_delete_mutex(&lock->print); controller_lock_delete_mutex(&lock->alert); + controller_lock_delete_mutex(&lock->print); controller_lock_delete_rw(&lock->process); controller_lock_delete_rw(&lock->rule); diff --git a/level_3/controller/c/common/private-lock.h b/level_3/controller/c/common/private-lock.h index 98af3d6..3132d3a 100644 --- a/level_3/controller/c/common/private-lock.h +++ b/level_3/controller/c/common/private-lock.h @@ -51,7 +51,7 @@ extern "C" { * * @param mutex * The mutex lock to delete. - * Will be set to NULLif delete succeeded. + * Will be set to NULL if delete succeeded. */ #ifndef _di_controller_lock_delete_mutex_ extern void controller_lock_delete_mutex(f_thread_mutex_t *mutex) F_attribute_visibility_internal_d; diff --git a/level_3/controller/c/common/private-setting.c b/level_3/controller/c/common/private-setting.c index 2ffb1e2..71723de 100644 --- a/level_3/controller/c/common/private-setting.c +++ b/level_3/controller/c/common/private-setting.c @@ -8,13 +8,15 @@ extern "C" { #ifndef _di_controller_setting_delete_simple_ void controller_setting_delete_simple(controller_setting_t * const setting) { - f_string_dynamic_resize(0, &setting->path_control); + f_string_dynamic_resize(0, &setting->name_entry); + f_string_dynamic_resize(0, &setting->path_cgroup); + f_string_dynamic_resize(0, &setting->path_control); f_string_dynamic_resize(0, &setting->path_current); f_string_dynamic_resize(0, &setting->path_pid); f_string_dynamic_resize(0, &setting->path_setting); - f_string_dynamic_resize(0, &setting->name_entry); + controller_control_delete_simple(&setting->control); controller_entry_items_delete_simple(&setting->entry.items); controller_entry_items_delete_simple(&setting->exit.items); diff --git a/level_3/controller/c/common/private-setting.h b/level_3/controller/c/common/private-setting.h index e62f277..72dd25c 100644 --- a/level_3/controller/c/common/private-setting.h +++ b/level_3/controller/c/common/private-setting.h @@ -27,25 +27,24 @@ extern "C" { * - program: Run as a program, exiting when finished prrocess entry (and any respective exit). * - service: Run as a service, listening for requests after processing entry. * - * interruptible: TRUE if the program responds to interrupt signals, FALSE to block/ignore interrupt signals. - * pid_created: TRUE if the PID file has been created. - * ready: State representing if the settings are all loaded and is ready to run program operations. - * mode: Controller setting mode based on the setting mode enumerator. - * control_group: Group role of the control socket. - * control_moode: Mode role of the control socket. - * control_readonly: TRUE if the control is set to readonly, FALSE otherwise. - * control_socket: The control socket data. - * control_user: User role of the control socket. - * failsafe_enabled: TRUE if failsafe execution is enabled, FALSE otherwise. - * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled. - * path_cgroup: Directory path to the cgroup directory. - * path_control: File path to the control socket. - * path_pid: File path to the PID file. - * path_setting: File path to the setting directory. - * entry: The Entry settings. - * rules: All rules and their respective settings. + * controller_setting_flag_*: + * - interruptible: When specified, program responds to interrupt signals, otherwise block/ignore interrupt signals. + * - pid_created: When specified, the program responds to interrupt signals, otherwise block/ignore interrupt signals. + * - failsafe: When specified, failsafe mode is enabled, otherwise failsafe mode is disabled. + * + * flag: Flags from controller_setting_flag_*. + * ready: State representing if the settings are all loaded and is ready to run program operations. + * mode: Controller setting mode based on the setting mode enumerator. + * control: The control socket data. + * failsafe_item_id: The Entry Item ID to execute when failsafe execution is enabled. + * path_cgroup: Directory path to the cgroup directory. + * path_control: File path to the control socket (used for printing the path). + * path_pid: File path to the PID file. + * path_setting: File path to the setting directory. + * entry: The Entry settings. + * rules: All rules and their respective settings. */ -#ifndef _di_controller_setting_t +#ifndef _di_controller_setting_t_ enum { controller_setting_ready_no_e = 0, controller_setting_ready_wait_e, @@ -60,21 +59,21 @@ extern "C" { controller_setting_mode_program_e, }; + enum { + controller_setting_flag_interruptible_e = 0x1, + controller_setting_flag_pid_created_e = 0x2, + controller_setting_flag_failsafe_e = 0x4, + }; + typedef struct { - bool interruptible; - bool pid_created; + uint8_t flag; uint8_t ready; uint8_t mode; - gid_t control_group; - mode_t control_mode; - bool control_readonly; - f_socket_t control_socket; - uid_t control_user; - - bool failsafe_enabled; f_array_length_t failsafe_item_id; + controller_control_t control; + f_string_dynamic_t path_cgroup; f_string_dynamic_t path_control; f_string_dynamic_t path_current; @@ -89,17 +88,11 @@ extern "C" { } controller_setting_t; #define controller_setting_t_initialize { \ - F_false, \ - F_false, \ - 0, \ - 0, \ 0, \ 0, \ - F_false, \ - f_socket_t_initialize, \ 0, \ - F_false, \ 0, \ + controller_control_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ f_string_dynamic_t_initialize, \ @@ -110,7 +103,7 @@ extern "C" { controller_entry_t_initialize, \ controller_rules_t_initialize, \ } -#endif // _di_controller_setting_t +#endif // _di_controller_setting_t_ /** * Fully deallocate all memory for the given setting without caring about return status. diff --git a/level_3/controller/c/common/private-thread.h b/level_3/controller/c/common/private-thread.h index 68da869..01af260 100644 --- a/level_3/controller/c/common/private-thread.h +++ b/level_3/controller/c/common/private-thread.h @@ -25,7 +25,6 @@ extern "C" { * id_cleanup: The thread ID representing the Cleanup Process. * id_control: The thread ID representing the Control Process. * id_entry: The thread ID representing the Entry or Exit Process. - * id_listen: The thread ID representing the Control Process Listener. * id_rule: The thread ID representing the Rule Process. * id_signal: The thread ID representing the Signal Process. * lock: A r/w lock for operating on this structure. @@ -106,7 +105,6 @@ extern "C" { f_thread_id_t id_cleanup; f_thread_id_t id_control; f_thread_id_t id_entry; - f_thread_id_t id_listen; f_thread_id_t id_rule; f_thread_id_t id_signal; @@ -124,7 +122,6 @@ extern "C" { f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ f_thread_id_t_initialize, \ - f_thread_id_t_initialize, \ controller_lock_t_initialize, \ controller_processs_t_initialize, \ controller_cache_t_initialize, \ diff --git a/level_3/controller/c/control/private-control.c b/level_3/controller/c/control/private-control.c index dee5356..080d614 100644 --- a/level_3/controller/c/control/private-control.c +++ b/level_3/controller/c/control/private-control.c @@ -10,21 +10,23 @@ extern "C" { #ifndef _di_controller_control_accept_ f_status_t controller_control_accept(const controller_global_t * const global, controller_control_t * const control) { - f_socket_t client = f_socket_t_initialize; + /*if (control->client.id != -1) { + f_socket_disconnect(&control->client, f_socket_close_fast_e); - control->client = &client; + control->client.id = -1; + }*/ - f_status_t status = f_socket_accept(&client, control->server->id); + f_status_t status = f_socket_accept(&control->client, control->server.id); if (F_status_is_error(status)) { - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_accept", F_true); return status; } - controller_control_configure_client(global, &client); + controller_control_configure_client(global, &control->client); control->input.used = 0; control->output.used = 0; @@ -35,11 +37,11 @@ extern "C" { memset(buffer, 0, controller_control_default_socket_buffer_d + 1); // Pre-process the packet header. - client.size_read = controller_control_default_socket_header_d; - status = f_socket_read(&client, f_socket_flag_peek_d, buffer, &length); + control->client.size_read = controller_control_default_socket_header_d; + status = f_socket_read(&control->client, f_socket_flag_peek_d, buffer, &length); if (F_status_is_error(status)) { - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_read", F_true); @@ -49,7 +51,7 @@ extern "C" { if (!length) { status = controller_control_respond_error_string(global, control, F_empty, "Received packet is empty."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); if (F_status_is_error(status)) return status; @@ -59,7 +61,7 @@ extern "C" { if (length < controller_control_default_socket_header_d) { status = controller_control_respond_error_string(global, control, F_too_large, "Received packet is too small."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); if (F_status_is_error(status)) return status; @@ -69,7 +71,7 @@ extern "C" { if (length > controller_control_default_socket_buffer_max_d) { status = controller_control_respond_error_string(global, control, F_too_large, "Received packet is too large."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); if (F_status_is_error(status)) return status; @@ -82,14 +84,14 @@ extern "C" { if (packet_flag & controller_control_packet_flag_binary_d) { status = controller_control_respond_error_string(global, control, F_supported_not, "Binary is not a currently supported packet mode."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); if (F_status_is_error(status)) return status; return F_supported_not; } - client.size_read = controller_control_default_socket_buffer_d; + control->client.size_read = controller_control_default_socket_buffer_d; // Pre-allocate the input buffer. status = f_string_dynamic_increase_by(packet_length, &control->input); @@ -97,7 +99,7 @@ extern "C" { if (F_status_is_error(status)) { controller_control_respond_error_string(global, control, F_memory_not, "Failure allocating memory."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_string_dynamic_increase_by", F_true); @@ -108,23 +110,23 @@ extern "C" { size_t total = 0; do { - status = f_socket_read(&client, 0, &control->input, &total); + status = f_socket_read(&control->client, 0, &control->input, &total); if (F_status_is_error(status)) { - controller_control_respond_error_string(global, control, F_status_set_fine(status), "Failure while reading from client socket."); + controller_control_respond_error_string(global, control, F_status_set_fine(status), "Failure while reading from control->client socket."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); return F_status_set_fine(status); } - } while (total == client.size_read); + } while (total == control->client.size_read); } if (control->input.used != length) { controller_control_respond_error_string(global, control, F_valid_not, "Received packet header length did not match actual received packet length."); - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); return F_valid_not; } @@ -133,7 +135,7 @@ extern "C" { // @todo send any responses. - f_socket_disconnect(&client, f_socket_close_fast_e); + f_socket_disconnect(&control->client, f_socket_close_fast_e); // Resize memory when the allocated size is greate than the maximum preferred size. // Resizing could potentially copy memory to a new address, so it is assumed to be cheaper to just delete the memory entirely. @@ -308,7 +310,7 @@ extern "C" { if (F_status_is_error(status2)) return status2; } - return f_socket_write(control->client, 0, control->output.string, 0); + return f_socket_write(&control->client, 0, control->output.string, 0); } #endif // _di_controller_control_respond_error_ diff --git a/level_3/controller/c/control/private-control.h b/level_3/controller/c/control/private-control.h index b9c34d0..5158763 100644 --- a/level_3/controller/c/control/private-control.h +++ b/level_3/controller/c/control/private-control.h @@ -20,7 +20,7 @@ extern "C" { * @param global * The global data. * @param control - * The control data structure. + * The control data. * * @return * F_none on success. @@ -121,10 +121,8 @@ extern "C" { * * @param global * The global data. - * @param server - * The server socket structure. - * @param packet - * The control packet data structure. + * @param control + * The control data. * * @return * F_none on success. @@ -152,7 +150,7 @@ extern "C" { * @param global * The global data. * @param control - * The control structure. + * The control data. * @param type * The packet type. * Set type.used to 0 to not add to the header. @@ -198,7 +196,7 @@ extern "C" { * @param global * The global data. * @param control - * The control structure. + * The control data. * @param status * The status code. * @param message @@ -223,7 +221,7 @@ extern "C" { * @param global * The global data. * @param control - * The control structure. + * The control data. * @param status * The status code. * @param message diff --git a/level_3/controller/c/controller.c b/level_3/controller/c/controller.c index 1c81e7b..583e33a 100644 --- a/level_3/controller/c/controller.c +++ b/level_3/controller/c/controller.c @@ -172,13 +172,12 @@ extern "C" { controller_setting_t setting = controller_setting_t_initialize; - struct sockaddr_un address; - setting.control_socket.address = (struct sockaddr *) &address; - setting.control_socket.domain = f_socket_domain_file_d; - setting.control_socket.type = f_socket_type_datagram_d; - setting.control_socket.length = sizeof(struct sockaddr_un); + setting.control.server.address = (struct sockaddr *) &setting.control.address; + setting.control.server.domain = f_socket_domain_file_d; + setting.control.server.type = f_socket_type_stream_d; + setting.control.server.length = sizeof(struct sockaddr_un); - memset(&address, 0, setting.control_socket.length); + memset(setting.control.server.address, 0, setting.control.server.length); if (main->parameters.remaining.used) { status = f_string_dynamic_append(argv[main->parameters.remaining.array[0]], &setting.name_entry); @@ -375,18 +374,20 @@ extern "C" { setting.entry.show = controller_entry_show_init_e; if (main->parameters.array[controller_parameter_interruptible_e].result == f_console_result_found_e) { - setting.interruptible = F_true; + setting.flag |= controller_setting_flag_interruptible_e; } - else { - setting.interruptible = F_false; + else if (setting.flag & controller_setting_flag_interruptible_e) { + setting.flag -= controller_setting_flag_interruptible_e; } } else { if (main->parameters.array[controller_parameter_uninterruptible_e].result == f_console_result_found_e) { - setting.interruptible = F_false; + if (setting.flag & controller_setting_flag_interruptible_e) { + setting.flag -= controller_setting_flag_interruptible_e; + } } else { - setting.interruptible = F_true; + setting.flag |= controller_setting_flag_interruptible_e; } } @@ -439,7 +440,7 @@ extern "C" { fll_print_dynamic_raw(f_string_eol_s, main->output.to.stream); } - if (status != F_child && setting.pid_created) { + if (status != F_child && (setting.flag & controller_setting_flag_pid_created_e)) { const f_status_t status_delete = controller_file_pid_delete(main->pid, setting.path_pid); if (F_status_is_error(status_delete) && main->warning.verbosity == f_console_verbosity_debug_e) { @@ -461,9 +462,9 @@ extern "C" { } if (status != F_child && setting.path_control.used) { - f_socket_disconnect(&setting.control_socket, f_socket_close_read_write_e); + f_socket_disconnect(&setting.control.server, f_socket_close_read_write_e); - if (!setting.control_readonly) { + if (!(setting.control.flag & controller_control_flag_readonly_e)) { f_file_remove(setting.path_control); } } diff --git a/level_3/controller/c/controller/private-controller.c b/level_3/controller/c/controller/private-controller.c index 2867e22..a826a22 100644 --- a/level_3/controller/c/controller/private-controller.c +++ b/level_3/controller/c/controller/private-controller.c @@ -458,7 +458,7 @@ extern "C" { status = F_none; } else { - global->setting->pid_created = F_true; + global->setting->flag |= controller_setting_flag_pid_created_e; if (global->main->output.verbosity == f_console_verbosity_debug_e) { controller_lock_print(global->main->output.to, global->thread); @@ -472,178 +472,196 @@ extern "C" { } if (global->setting->path_control.used) { - if (global->setting->control_readonly) { - if (f_file_exists(global->setting->path_control) != F_true) { - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + status = controller_perform_ready_socket(global, cache, is_entry); - fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("' .%r", global->main->output.to.stream, f_string_eol_s); - fl_print_format("%[' cannot be found while read only mode is enabled and so the Control socket is unavailable.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + // Do not fail on non-memory errors related to creating the control socket. + if (F_status_is_error(status) && F_status_set_fine(status) != F_memory) { + status = F_none; + } + } - controller_unlock_print_flush(global->main->output.to, global->thread); - } + return status; + } +#endif // _di_controller_perform_ready_ - return status; +#ifndef _di_controller_perform_ready_socket_ + f_status_t controller_perform_ready_socket(const controller_global_t * const global, controller_cache_t * const cache, const bool is_entry) { + + f_status_t status = F_none; + + if (global->setting->control.flag & controller_control_flag_readonly_e) { + if (f_file_exists(global->setting->path_control) != F_true) { + if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); + + fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("' .%r", global->main->output.to.stream, f_string_eol_s); + fl_print_format("%[' cannot be found while read only mode is enabled and so the Control socket is unavailable.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + + controller_unlock_print_flush(global->main->output.to, global->thread); } + + return F_data_not; } - else { - status = f_socket_create(&global->setting->control_socket); + } - if (F_status_is_error(status)) { - if (F_status_set_fine(status) == F_memory_not) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_create", F_true); + status = f_socket_create(&global->setting->control.server); - return status; - } + if (F_status_is_error(status)) { + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_create", F_true); + } + else if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("%[' could not be created, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); + fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); + fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); - fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("%[' could not be created, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); - fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); - fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + controller_unlock_print_flush(global->main->output.to, global->thread); + } - controller_unlock_print_flush(global->main->output.to, global->thread); - } - } - else { - status = f_file_remove(global->setting->path_control); + return status; + } - if (F_status_set_fine(status) == F_memory_not) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_remove", F_true); + if (!(global->setting->control.flag & controller_control_flag_readonly_e)) { + status = f_file_remove(global->setting->path_control); - return status; - } + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_remove", F_true); - global->setting->control_socket.name = global->setting->path_control.string; + return status; + } + } - status = f_socket_bind_file(global->setting->control_socket); + global->setting->control.server.name = global->setting->path_control.string; - if (F_status_is_error(status)) { - f_socket_disconnect(&global->setting->control_socket, f_socket_close_fast_e); + status = f_socket_bind_local(&global->setting->control.server); - if (F_status_set_fine(status) == F_memory_not) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_bind_file", F_true); + if (F_status_is_error(status)) { + f_socket_disconnect(&global->setting->control.server, f_socket_close_fast_e); - return status; - } + if (!(global->setting->control.flag & controller_control_flag_readonly_e)) { + f_file_remove(global->setting->path_control); + } - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_bind_local", F_true); + } + else if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); - fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("%[' could not be bound, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); - fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); - fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("%[' could not be bound, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); + fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); + fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); - controller_unlock_print_flush(global->main->output.to, global->thread); - } - } - else { - status = f_file_role_change(global->setting->path_control, global->setting->control_user, global->setting->control_group, F_true); + controller_unlock_print_flush(global->main->output.to, global->thread); + } - if (F_status_is_error(status)) { - f_socket_disconnect(&global->setting->control_socket, f_socket_close_fast_e); + return status; + } - if (F_status_set_fine(status) == F_memory_not) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_role_change", F_true); + if (global->setting->control.flag & (controller_control_flag_has_user_e | controller_control_flag_has_group_e)) { + status = f_file_role_change(global->setting->path_control, global->setting->control.user, global->setting->control.group, F_true); - return status; - } + if (F_status_is_error(status)) { + f_socket_disconnect(&global->setting->control.server, f_socket_close_fast_e); - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + if (!(global->setting->control.flag & controller_control_flag_readonly_e)) { + f_file_remove(global->setting->path_control); + } - fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("%[' failed to set file roles, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); - fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); - fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_role_change", F_true); + } + else if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); - controller_unlock_print_flush(global->main->output.to, global->thread); - } - } - else { - status = f_file_mode_set(global->setting->path_control, global->setting->control_mode); + fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("%[' failed to set file roles, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); + fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); + fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); - if (F_status_is_error(status)) { - f_socket_disconnect(&global->setting->control_socket, f_socket_close_fast_e); + controller_unlock_print_flush(global->main->output.to, global->thread); + } - if (F_status_set_fine(status) == F_memory_not) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_role_change", F_true); + return status; + } + } - return status; - } + if (global->setting->control.flag & controller_control_flag_has_mode_e) { + status = f_file_mode_set(global->setting->path_control, global->setting->control.mode); - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + if (F_status_is_error(status)) { + f_socket_disconnect(&global->setting->control.server, f_socket_close_fast_e); - fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("%[' failed to set file mode, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); - fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); - fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); + if (!(global->setting->control.flag & controller_control_flag_readonly_e)) { + f_file_remove(global->setting->path_control); + } - controller_unlock_print_flush(global->main->output.to, global->thread); - } - } - else { - if (global->main->output.verbosity == f_console_verbosity_debug_e) { - controller_lock_print(global->main->output.to, global->thread); + if (F_status_set_fine(status) == F_memory_not) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_file_role_change", F_true); + } + else if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); - fl_print_format("%rControl socket '", global->main->output.to.stream, f_string_eol_s); - fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); - fl_print_format("' created.%r", global->main->output.to.stream, f_string_eol_s); + fl_print_format("%r%[%QControl socket '%]", global->main->warning.to.stream, f_string_eol_s, global->main->warning.context, global->main->warning.prefix, global->main->warning.context); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("%[' failed to set file mode, code %]", global->main->output.to.stream, global->main->warning.context, global->main->warning.context); + fl_print_format("%[%ui%]", global->main->output.to.stream, global->main->context.set.notable, F_status_set_fine(status), global->main->context.set.notable); + fl_print_format("%[.%]%r", global->main->output.to.stream, global->main->warning.context, global->main->warning.context, f_string_eol_s); - controller_unlock_print_flush(global->main->output.to, global->thread); - } + controller_unlock_print_flush(global->main->output.to, global->thread); + } - status = f_thread_create(0, &global->thread->id_listen, &controller_thread_control_listen, (void *) global); + return status; + } + } - if (status == F_child) { - return status; - } + if (global->main->output.verbosity == f_console_verbosity_debug_e) { + controller_lock_print(global->main->output.to, global->thread); - if (F_status_is_error_not(status)) { - status = f_thread_create(0, &global->thread->id_control, &controller_thread_control, (void *) global); + fl_print_format("%rControl socket '", global->main->output.to.stream, f_string_eol_s); + fl_print_format("%[%Q%]", global->main->output.to.stream, global->main->context.set.notable, global->setting->path_control, global->main->context.set.notable); + fl_print_format("' created.%r", global->main->output.to.stream, f_string_eol_s); - if (status == F_child) { - return status; - } - } + controller_unlock_print_flush(global->main->output.to, global->thread); + } - if (F_status_is_error(status)) { - if (global->thread->id_listen) { - f_thread_cancel(global->thread->id_listen); - f_thread_join(global->thread->id_listen, 0); + status = f_thread_create(0, &global->thread->id_control, &controller_thread_control, (void *) global); - global->thread->id_listen = 0; - } + if (status == F_child) { + return status; + } - global->thread->id_control = 0; + if (F_status_is_error(status)) { + f_socket_disconnect(&global->setting->control.server, f_socket_close_fast_e); - if (global->main->error.verbosity != f_console_verbosity_quiet_e) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_thread_create", F_true); - } - } - } - } - } - } + if (!(global->setting->control.flag & controller_control_flag_readonly_e)) { + f_file_remove(global->setting->path_control); + } - // Don't fail if unable to create socket file. - status = F_none; + if (global->thread->id_control) { + f_thread_cancel(global->thread->id_control); + f_thread_join(global->thread->id_control, 0); + + global->thread->id_control = 0; + } + + if (global->main->error.verbosity != f_console_verbosity_quiet_e) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_thread_create", F_true); } } - return status; + return F_none; } -#endif // _di_controller_perform_ready_ +#endif // _di_controller_perform_ready_socket_ #ifndef _di_controller_status_simplify_error_ f_status_t controller_status_simplify_error(const f_status_t status) { @@ -725,7 +743,7 @@ extern "C" { int controller_time_sleep_nanoseconds(controller_main_t * const main, controller_setting_t * const setting, struct timespec time) { // When sleep is a second or more, instead wait for terminating signals if interruptible. - if (setting->interruptible && time.tv_sec) { + if ((setting->flag & controller_setting_flag_interruptible_e) && time.tv_sec) { siginfo_t information; f_signal_t signal = f_signal_t_initialize; diff --git a/level_3/controller/c/controller/private-controller.h b/level_3/controller/c/controller/private-controller.h index cbab56d..ef956d7 100644 --- a/level_3/controller/c/controller/private-controller.h +++ b/level_3/controller/c/controller/private-controller.h @@ -250,6 +250,43 @@ extern "C" { #endif // _di_controller_perform_ready_ /** + * Perform the socket loading when "ready". + * + * This prints messages on errors. + * + * This does not do any locking or unlocking for the setting data, be sure to lock appropriately before and after calling this. + * + * @param global + * The global data. + * @param cache + * The cache. + * @param is_entry + * If TRUE, then this operate as an entry. + * If FALSE, then this operate as an exit. + * + * @return + * F_none on success. + * F_data_not on success but socket file not created. + * + * Errors (with error bit) from: f_file_mode_set(). + * Errors (with error bit) from: f_file_remove(). + * Errors (with error bit) from: f_file_role_change(). + * Errors (with error bit) from: f_socket_bind_local(). + * Errors (with error bit) from: f_socket_create(). + * Errors (with error bit) from: f_thread_create(). + * + * @see f_file_mode_set() + * @see f_file_remove() + * @see f_file_role_change() + * @see f_socket_bind_local() + * @see f_socket_create() + * @see f_thread_create() + */ +#ifndef _di_controller_perform_ready_socket_ + extern f_status_t controller_perform_ready_socket(const controller_global_t * const global, controller_cache_t * const cache, const bool is_entry) F_attribute_visibility_internal_d; +#endif // _di_controller_perform_ready_socket_ + +/** * Given a wide range of status codes (that are errors), simplify them down to a small subset. * * @param status diff --git a/level_3/controller/c/entry/private-entry.c b/level_3/controller/c/entry/private-entry.c index 57b1884..9c19868 100644 --- a/level_3/controller/c/entry/private-entry.c +++ b/level_3/controller/c/entry/private-entry.c @@ -1486,7 +1486,7 @@ extern "C" { return F_status_is_error(F_critical); } else { - global->setting->failsafe_enabled = F_true; + global->setting->flag |= controller_setting_flag_failsafe_e; global->setting->failsafe_item_id = entry_action->number; controller_entry_preprocess_print_simulate_setting_value(*global, is_entry, controller_failsafe_s, f_string_empty_s, entry->items.array[global->setting->failsafe_item_id].name, f_string_empty_s); @@ -2000,8 +2000,6 @@ extern "C" { if (F_status_is_error(status)) { controller_entry_print_error(is_entry, global.main->error, cache->action, F_status_set_fine(status), "fl_string_dynamic_partial_rip_nulless", F_true, global.thread); - global.setting->path_control.used = 0; - break; } @@ -2039,7 +2037,8 @@ extern "C" { continue; } - global.setting->control_group = number; + global.setting->control.group = number; + global.setting->control.flag |= controller_control_flag_has_group_e; } else if (is_entry && fl_string_dynamic_compare(controller_control_mode_s, cache->action.name_action) == F_equal_to) { mode_t mode = 0; @@ -2072,7 +2071,8 @@ extern "C" { continue; } - global.setting->control_mode = mode; + global.setting->control.mode = mode; + global.setting->control.flag |= controller_control_flag_has_mode_e; } else if (is_entry && fl_string_dynamic_compare(controller_control_user_s, cache->action.name_action) == F_equal_to) { uid_t number = 0; @@ -2098,7 +2098,8 @@ extern "C" { continue; } - global.setting->control_user = number; + global.setting->control.user = number; + global.setting->control.flag |= controller_control_flag_has_user_e; } else if (is_entry && fl_string_dynamic_compare(controller_mode_s, cache->action.name_action) == F_equal_to) { if (cache->content_actions.array[i].used != 1) { diff --git a/level_3/controller/c/lock/private-lock.c b/level_3/controller/c/lock/private-lock.c index ecc0e52..110dcc7 100644 --- a/level_3/controller/c/lock/private-lock.c +++ b/level_3/controller/c/lock/private-lock.c @@ -11,10 +11,13 @@ extern "C" { #ifndef _di_controller_lock_create_ f_status_t controller_lock_create(controller_lock_t *lock) { - f_status_t status = f_thread_mutex_create(0, &lock->print); + f_status_t status = f_thread_mutex_create(0, &lock->alert); if (F_status_is_error(status)) return status; - status = f_thread_mutex_create(0, &lock->alert); + //status = f_thread_mutex_create(0, &lock->listen); + //if (F_status_is_error(status)) return status; + + status = f_thread_mutex_create(0, &lock->print); if (F_status_is_error(status)) return status; status = f_thread_lock_create(0, &lock->process); @@ -26,6 +29,9 @@ extern "C" { status = f_thread_condition_create(0, &lock->alert_condition); if (F_status_is_error(status)) return status; + //status = f_thread_condition_create(0, &lock->listen_condition); + //if (F_status_is_error(status)) return status; + return F_none; } #endif // _di_controller_lock_create_ diff --git a/level_3/controller/c/thread/private-thread.c b/level_3/controller/c/thread/private-thread.c index 78d1f3d..d01d91d 100644 --- a/level_3/controller/c/thread/private-thread.c +++ b/level_3/controller/c/thread/private-thread.c @@ -300,20 +300,14 @@ extern "C" { controller_thread_process_exit(&global); - if (thread.id_listen) { - f_thread_cancel(thread.id_listen); - } - if (thread.id_signal) f_thread_join(thread.id_signal, 0); if (thread.id_cleanup) f_thread_join(thread.id_cleanup, 0); if (thread.id_control) f_thread_join(thread.id_control, 0); - if (thread.id_listen) f_thread_join(thread.id_listen, 0); if (thread.id_entry) f_thread_join(thread.id_entry, 0); if (thread.id_rule) f_thread_join(thread.id_rule, 0); thread.id_cleanup = 0; thread.id_control = 0; - thread.id_listen = 0; thread.id_entry = 0; thread.id_rule = 0; thread.id_signal = 0; diff --git a/level_3/controller/c/thread/private-thread_control.c b/level_3/controller/c/thread/private-thread_control.c index fd3b5dd..8a2098a 100644 --- a/level_3/controller/c/thread/private-thread_control.c +++ b/level_3/controller/c/thread/private-thread_control.c @@ -1,6 +1,7 @@ #include "../controller.h" #include "../common/private-common.h" #include "../control/private-control.h" +#include "../controller/private-controller.h" #include "../controller/private-controller_print.h" #include "private-thread.h" #include "private-thread_control.h" @@ -19,73 +20,77 @@ extern "C" { if (global->thread->enabled != controller_thread_enabled_e) return 0; f_status_t status = F_none; - controller_control_t control = macro_controller_control_t_initialize(&global->setting->control_socket, 0); + struct timespec time; + controller_control_t *control = &global->setting->control; do { - // Shrink any overly large buffers. - if (control.cache_1.size > controller_control_default_socket_cache_d) { - status = f_string_dynamic_resize(controller_control_default_socket_cache_d, &control.cache_1); + // Remove any overly large buffers. + if (control->cache_1.size > controller_control_default_socket_cache_d) { + status = f_string_dynamic_resize(0, &control->cache_1); } - if (F_status_is_error_not(status) && control.cache_2.size > controller_control_default_socket_buffer_d) { - status = f_string_dynamic_resize(controller_control_default_socket_buffer_d, &control.cache_2); + if (F_status_is_error_not(status) && control->cache_2.size > controller_control_default_socket_buffer_d) { + status = f_string_dynamic_resize(0, &control->cache_2); } - if (F_status_is_error_not(status) && control.cache_3.size > controller_control_default_socket_buffer_d) { - status = f_string_dynamic_resize(controller_control_default_socket_buffer_d, &control.cache_3); + if (F_status_is_error_not(status) && control->cache_3.size > controller_control_default_socket_buffer_d) { + status = f_string_dynamic_resize(0, &control->cache_3); } - if (F_status_is_error_not(status) && control.input.size > controller_control_default_socket_buffer_d) { - status = f_string_dynamic_resize(controller_control_default_socket_buffer_d, &control.input); + if (F_status_is_error_not(status) && control->input.size > controller_control_default_socket_buffer_d) { + status = f_string_dynamic_resize(0, &control->input); } - if (F_status_is_error_not(status) && control.output.size > controller_control_default_socket_buffer_d) { - status = f_string_dynamic_resize(controller_control_default_socket_buffer_d, &control.output); + if (F_status_is_error_not(status) && control->output.size > controller_control_default_socket_buffer_d) { + status = f_string_dynamic_resize(0, &control->output); } if (F_status_is_error(status)) { controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_string_dynamic_resize", F_true); + + status = F_none; } - status = controller_control_accept(global, &control); + status = f_socket_listen(&control->server, controller_control_default_socket_backlog_d); if (F_status_is_error(status)) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "controller_control_accept", F_true); - } + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_listen", F_true); - } while (F_status_is_fine(status) && status != F_child && global->thread->enabled == controller_thread_enabled_e); + /*controller_time(controller_thread_wait_timeout_2_seconds_d, controller_thread_wait_timeout_2_nanoseconds_d, &time); - controller_control_delete_simple(&control); + controller_time_sleep_nanoseconds(global->main, global->setting, time); + */ - return 0; - } -#endif // _di_controller_thread_control_ + status = F_none; -#ifndef _di_controller_thread_control_listen_ - void * controller_thread_control_listen(void * const arguments) { + continue; + } - f_thread_cancel_state_set(PTHREAD_CANCEL_ASYNCHRONOUS, 0); + status = controller_control_accept(global, control); + if (status == F_child) break; - const controller_global_t *global = (controller_global_t *) arguments; - - if (global->thread->enabled != controller_thread_enabled_e) return 0; + if (F_status_is_error(status)) { + controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "controller_control_accept", F_true); + } - if (global->setting->interruptible) { - f_signal_mask(SIG_UNBLOCK, &global->main->signal.set, 0); - } + status = F_none; - f_socket_t * const server = &global->setting->control_socket; + } while (global->thread->enabled == controller_thread_enabled_e); - const f_status_t status = f_socket_listen(server, controller_control_default_socket_backlog_d); + if (status == F_child) { - if (F_status_is_error(status)) { - controller_print_error(global->thread, global->main->error, F_status_set_fine(status), "f_socket_listen", F_true); + // A forked child process should deallocate memory on exit. + // It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below. + // Deallocate as much as possible. + controller_thread_delete_simple(global->thread); + controller_setting_delete_simple(global->setting); + controller_main_delete(global->main); } return 0; } -#endif // _di_controller_thread_control_listen_ +#endif // _di_controller_thread_control_ #ifdef __cplusplus } // extern "C" diff --git a/level_3/controller/c/thread/private-thread_control.h b/level_3/controller/c/thread/private-thread_control.h index b8f49d2..73fdc06 100644 --- a/level_3/controller/c/thread/private-thread_control.h +++ b/level_3/controller/c/thread/private-thread_control.h @@ -26,23 +26,6 @@ extern "C" { extern void * controller_thread_control(void * const arguments) F_attribute_visibility_internal_d; #endif // _di_controller_thread_control_ -/** - * Thread for handling the control listener. - * - * This runs on a separate thread entirely to be interuptable and closable distinctly from the main control thread. - * This is simple and has nothing that needs to be cleaned up and so immediately exits on cancel. - * - * @param arguments - * The thread arguments. - * Must be of type controller_global_t. - * - * @return - * 0, always. - */ -#ifndef _di_controller_thread_control_listen_ - extern void * controller_thread_control_listen(void * const arguments) F_attribute_visibility_internal_d; -#endif // _di_controller_thread_control_listen_ - #ifdef __cplusplus } // extern "C" #endif diff --git a/level_3/controller/c/thread/private-thread_entry.c b/level_3/controller/c/thread/private-thread_entry.c index 22da8dc..ea080c4 100644 --- a/level_3/controller/c/thread/private-thread_entry.c +++ b/level_3/controller/c/thread/private-thread_entry.c @@ -58,7 +58,7 @@ extern "C" { if (F_status_is_error(*status)) { entry->setting->ready = controller_setting_ready_fail_e; - if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && entry->global->setting->failsafe_enabled) { + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (entry->global->setting->flag & controller_setting_flag_failsafe_e)) { const uint8_t original_enabled = entry->global->thread->enabled; // Restore operating mode so that the failsafe can execute. @@ -82,7 +82,7 @@ extern "C" { controller_lock_print(main->error.to, entry->global->thread); fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->error.to.stream, f_string_eol_s, main->error.context, main->error.prefix, main->error.context); - fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, entry->global->setting->entry.items.array[entry->global->setting->failsafe_enabled].name, main->error.notable); + fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, entry->global->setting->entry.items.array[entry->global->setting->failsafe_item_id].name, main->error.notable); fl_print_format("%['.%]%r", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s); controller_unlock_print_flush(main->error.to, entry->global->thread); @@ -170,7 +170,7 @@ extern "C" { if (F_status_is_error(*status)) { entry->setting->ready = controller_setting_ready_fail_e; - if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && entry->global->setting->failsafe_enabled) { + if ((F_status_set_fine(*status) == F_execute || F_status_set_fine(*status) == F_require) && (entry->global->setting->flag & controller_setting_flag_failsafe_e)) { const uint8_t original_enabled = entry->global->thread->enabled; @@ -197,7 +197,7 @@ extern "C" { controller_lock_print(main->error.to, entry->global->thread); fl_print_format("%r%[%QFailed while processing requested failsafe item '%]", main->error.to.stream, f_string_eol_s, main->error.context, main->error.prefix, main->error.context); - fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, entry->global->setting->entry.items.array[entry->global->setting->failsafe_enabled].name, main->error.notable); + fl_print_format("%[%Q%]", main->error.to.stream, main->error.notable, entry->global->setting->entry.items.array[entry->global->setting->failsafe_item_id].name, main->error.notable); fl_print_format("%['.%]%r", main->error.to.stream, main->error.context, main->error.context, f_string_eol_s); controller_unlock_print_flush(main->error.to, entry->global->thread); @@ -234,7 +234,6 @@ extern "C" { // A forked child process should deallocate memory on exit. // It seems that this function doesn't return to the calling thread for a forked child process, even with the "return 0;" below. // Deallocate as much as possible. - controller_thread_delete_simple(entry->global->thread); controller_setting_delete_simple(entry->global->setting); controller_main_delete(entry->global->main); diff --git a/level_3/controller/c/thread/private-thread_process.c b/level_3/controller/c/thread/private-thread_process.c index f0210fa..5ce3c88 100644 --- a/level_3/controller/c/thread/private-thread_process.c +++ b/level_3/controller/c/thread/private-thread_process.c @@ -90,6 +90,13 @@ extern "C" { global.thread->id_cleanup = 0; } + if (global.thread->id_control) { + f_thread_cancel(global.thread->id_control); + f_thread_join(global.thread->id_control, 0); + + global.thread->id_control = 0; + } + // The sigtimedwait() function that is run inside of signal must be interrupted via the f_thread_cancel(). if (by != controller_thread_cancel_signal_e && global.thread->id_signal) { f_thread_cancel(global.thread->id_signal); diff --git a/level_3/controller/c/thread/private-thread_signal.c b/level_3/controller/c/thread/private-thread_signal.c index 7684780..75cbc29 100644 --- a/level_3/controller/c/thread/private-thread_signal.c +++ b/level_3/controller/c/thread/private-thread_signal.c @@ -29,7 +29,7 @@ extern "C" { if (errno == EAGAIN) continue; } - if (global->setting->interruptible) { + if (global->setting->flag & controller_setting_flag_interruptible_e) { if (information.si_signo == F_signal_interrupt || information.si_signo == F_signal_abort || information.si_signo == F_signal_quit || information.si_signo == F_signal_termination) { global->thread->signal = information.si_signo; diff --git a/level_3/controller/documents/packet.txt b/level_3/controller/documents/packet.txt index 53fd8a4..f015680 100644 --- a/level_3/controller/documents/packet.txt +++ b/level_3/controller/documents/packet.txt @@ -9,24 +9,67 @@ Packet Documentation: The "packet" is the general category in which multiple types of packets belong. This describes the different packets based on their "type". - Every packet contains a "header", a "type" within the header, a "length" within the header, and a "payload". + Each packet begins with a control block and a size block followed by a payload block. - The "controller" packet type\: - Commands being sent to the controller and their respective responses utilize a "controller" packet. + The control block\: + The leading bit (starting from the left) designates the the format of the payload, which is 0 for string and 1 for binary. + The second bit (starting from the left) designates the the byte order for the rest of the packet, which 0 is for little endian and 1 is for big endian. + The remaining 6-bits are reserved for future use. + + The size block\: + The size block represents the size of the entire packet (the control block, the size blocks, and the payload block). + This number is an 32-bit unsigned integer. + The size block may contain up to 4 32-bit unsigned integers. + If the size is less than the max value of a 32-bit integer (4294967295), then the remaining 32-bit unsigned integers may be omitted. + + Example size that is less than 2^32-1\: + [ control block ] [ size block ] [ payload block ] + [ 0b10000000 ] [ 0b00000000 0b00000000 0b00000100 0b11010010 ] [ size: 1229 (1234 - 5) ] + + Example size that is less than 2^64-1\: + [ control block ] [ size block ] [ size block ] [ payload block ] + [ 0b10000000 ] [ 0b11111111 0b11111111 0b11111111 0b11111111 ] [ 0b00000000 0b00000000 0b00000000 0b11001000 ] [ size: 4294967486 (4294967495 - 9) ] + + The payload block\: + This block is represented by the FSS-000e payload specification and its structure ad use is described in the next sections. + + The following types of payload are received or sent\: + 1) controller payload. + 2) error payload. + + The controller payload\: + Commands being sent to the controller and their respective responses utilize a "controller" payload. These are pre-defined commands to rules or the controller program itself. Commands such as starting or stopping some rule, for example. + A controller payload is also sent in response to a controller payload request to represent a success. When operating in "init" mode, additional commands are available: "reboot" and "shutdown". - The "reboot" is for rebooting the machine and will eventually support "kexec" mode. - The "shutdown" is for shutting down the machine. - These two commands are configurable to fire off based on conditions, namely "time". - Two conditions may be met "on or after a specific date and time" and/or after so many milliseconds (second, minutes, hours, days, etc..) have passed. + The "kexec" is for booting into another kernel, which may effectively be the same as a "reboot" (currently not supported nor implemented). + The "reboot" is for rebooting the machine (currently not implemented). + The "shutdown" is for shutting down the machine (currently not implemented). + These three commands are configurable to fire off based on conditions\: + + The "now" condition designates that the kexec, reboot, or shutdown is to begin immediately. + The "at" condition designates that the kexec, reboot, or shutdown is to begin once a specific date and time is reached by the system clock. + The "in" condition designates that the kexec, reboot, or shutdown is to begin once a specific amount of time is passed by the system clock since the execution of this command started. + + For these "time" conditions, different units of time should be supported, such as "seconds", "days", "years" as standard time, Time or UNIX Time (Epoch Time). - The normal "controller" packet commands are any valid Rule Action that performs some action. + The normal "controller" payload commands are any valid Rule Action that performs some action. This does not include Actions that provide some setting or configuration (such as "with_pid"). Some of the supported commands are: "freeze", "kill", "pause", "reload", "rerun", "restart", "resume", "start", "stop", or "thaw". + Multiple commands may be sent multiple "action" headers. + The "action" headers are order sensitive, executing from top to bottom, and one does not start until the previous successfully completes. + + Multiple "status" headers may exist in the response so long as they each match an "action" in the request. + + The "payload" is expected to be empty and have a length of 0 for a request. + The "payload" may have an FSS-0000 (Basic) format containing a single Object "message" to represent a message associated with an action. + Multuple "message" may exist in the response so long as they each match an "action" in the request. - The "error" packet type\: - The error packet is intended to communicate some sort of failure. - The "status" from the "header" designates the status code (based on the FSS status codes and FLL status codes). - The "payload" will contain a NULL terminated string representin the message used to describe the error. + The error payload\: + The error payload is intended to communicate some sort of failure. + The error payload is only sent in response to some request (and not in response to another response). + The control (the client) is not expected to send error payloads and the controller (the service) should send an error in response to an error payload or ignore it entirely. + The "status" from the "header" designates the status code. + The "payload" will contain a NULL terminated string representing the message used to describe the error. diff --git a/level_3/controller/specifications/packet.txt b/level_3/controller/specifications/packet.txt index 568263d..b388ae0 100644 --- a/level_3/controller/specifications/packet.txt +++ b/level_3/controller/specifications/packet.txt @@ -6,6 +6,11 @@ Entry Specification: The controller program communicates use the FSS-000E Packet format. + Packet Structure\: + Packet is grouped into the following blocks\: + - control: A single 1-byte block representing contol codes. + - size: A set of 1 to 4 4-byte blocks representing the size of the entire packet. + The "header" Object contains the following FSS-0001 Extended Objects (depending on "type")\: - action: A valid action type: "freeze", "kill", "pause", "reboot", "reload", "rerun", "restart", "resume", "shutdown", "start", "stop", or "thaw". - length: A positive whole number inclusively between 0 and 4294965248 representing the length of the "payload". @@ -27,11 +32,12 @@ Entry Specification: The "payload" is a NULL terminated string whose length is defined by the "length" "header" Content. + There are different headers and payload properties based on the "type". + The "controller" type\: Supports the following headers: "action", "length", "status", and "type". - Currently only a single "action" is supported. - Currently only a single "status" is supported. + Multiple "action" may be provided, but at least one must exist. + Multiple "status" may be provided, but at least one must exist. The "payload" is dependent on the "action". - @todo describe the different actions. -- 1.8.3.1