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.
#include <fll/level_0/string.h>
#include <fll/level_0/utf.h>
-// fll-0 console includes
+// fll-0 console includes.
#include <fll/level_0/console/common.h>
#ifdef __cplusplus
#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
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) {
#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);
#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_
#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"
#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
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;
/**
* 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 \
0, \
f_string_dynamic_t_initialize, \
f_socket_t_initialize, \
+ /*f_string_dynamic_t_initialize,*/ \
0, \
}
#endif // _di_control_data_t_
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) {
}
#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)) {
{
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;
}
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);
}
}
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;
} // 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)) {
}
}
- 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);
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)) {
} // 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);
}
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);
}
}
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);
}
}
}
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);
}
}
}
#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.
*
#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.
* - 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.
#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;
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_
#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);
*
* @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;
#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);
* - 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,
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;
} 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, \
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.
* 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.
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;
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, \
#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;
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);
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;
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;
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;
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);
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);
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;
}
// @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.
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_
* @param global
* The global data.
* @param control
- * The control data structure.
+ * The control data.
*
* @return
* F_none on success.
*
* @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.
* @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.
* @param global
* The global data.
* @param control
- * The control structure.
+ * The control data.
* @param status
* The status code.
* @param message
* @param global
* The global data.
* @param control
- * The control structure.
+ * The control data.
* @param status
* The status code.
* @param message
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);
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;
}
}
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) {
}
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);
}
}
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);
}
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) {
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;
#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
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);
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;
}
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;
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;
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) {
#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);
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_
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;
#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"
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"
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
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.
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);
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;
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);
// 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);
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);
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;
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.
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".
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.