]> Kevux Git Server - kevux-tools/commitdiff
Progress: Further work in TacocaT.
authorKevin Day <thekevinday@gmail.com>
Sun, 3 Sep 2023 03:43:11 +0000 (22:43 -0500)
committerKevin Day <thekevinday@gmail.com>
Sun, 3 Sep 2023 03:43:11 +0000 (22:43 -0500)
16 files changed:
data/build/tacocat/dependencies
data/build/tacocat/settings
sources/c/tacocat/main/common.c
sources/c/tacocat/main/common/define.h
sources/c/tacocat/main/common/enumeration.h
sources/c/tacocat/main/common/print.c
sources/c/tacocat/main/common/print.h
sources/c/tacocat/main/common/type.c
sources/c/tacocat/main/common/type.h
sources/c/tacocat/main/print/error.c
sources/c/tacocat/main/print/error.h
sources/c/tacocat/main/print/warning.c
sources/c/tacocat/main/print/warning.h
sources/c/tacocat/main/process.c
sources/c/tacocat/main/receive.c
sources/c/tacocat/main/tacocat.h

index 6ffc06e7c7bdc8d822ec82361ddeaa62e802958c..82111db30e200fd29b45bd34fa78d3f6625baecc 100644 (file)
@@ -19,6 +19,7 @@ f_print
 f_signal
 f_socket
 f_thread
+f_time
 
 fl_conversion
 fl_print
index 05293979de284e435b568f88caef5fd848780baf..03921a7fc2e4b71df3d70f4eeafd4472ee12b130 100644 (file)
@@ -32,7 +32,7 @@ build_indexer_arguments rcs
 build_language c
 
 build_libraries -lc
-build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_conversion -lfl_print -lf_color -lf_compare -lf_console -lf_conversion -lf_file -lf_fss -lf_memory -lf_network -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_string -lf_type_array -lf_utf
+build_libraries-individual -lfll_error -lfll_print -lfll_program -lfl_conversion -lfl_print -lf_color -lf_compare -lf_console -lf_conversion -lf_file -lf_fss -lf_memory -lf_network -lf_path -lf_pipe -lf_print -lf_signal -lf_socket -lf_string -lf_time -lf_type_array -lf_utf
 build_libraries-individual_thread -lf_thread
 build_libraries-level -lfll_2 -lfll_1 -lfll_0
 build_libraries-monolithic -lfll
index cddf62f0156c8200d945a041b7ffa813f7492ab8..a471c97c66c02b3322ba5aec345e1a6b6e449a99 100644 (file)
@@ -188,7 +188,7 @@ extern "C" {
       }
 
       if (number == 0) {
-        kt_tacocat_print_warning_parameter_integer_is(&main->program.warning, f_console_symbol_long_normal_s, kt_tacocat_long_max_buffer_s, f_string_ascii_0_s);
+        kt_tacocat_print_warning_parameter_integer_less_than(&main->program.warning, f_console_symbol_long_normal_s, kt_tacocat_long_max_buffer_s, main->program.parameters.arguments.array[index]);
 
         main->setting.max_buffer = 0;
         main->setting.flag |= kt_tacocat_main_flag_max_buffer_e;
@@ -309,6 +309,8 @@ extern "C" {
 
           sets[i]->statuss.array[j] = F_okay;
           sets[i]->flags.array[j] = kt_tacocat_socket_flag_none_e;
+          sets[i]->retrys.array[j] = 0;
+          sets[i]->totals.array[j] = 0;
           sets[i]->names.array[j].used = 0;
           sets[i]->buffers.array[j].used = 0;
           sets[i]->packets.array[j].control.start = 1;
@@ -604,8 +606,10 @@ extern "C" {
     set->names.used = 0;
     set->packets.used = 0;
     set->polls.used = 0;
+    set->retrys.used = 0;
     set->sockets.used = 0;
     set->statuss.used = 0;
+    set->totals.used = 0;
 
     if (!set) {
       main->setting.state.status = F_status_set_error(F_parameter);
@@ -628,6 +632,10 @@ extern "C" {
     }
 
     if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.state.status = f_memory_array_increase_by(total, sizeof(uint16_t), (void **) &set->retrys.array, &set->retrys.used, &set->retrys.size);
+    }
+
+    if (F_status_is_error_not(main->setting.state.status)) {
       main->setting.state.status = f_memory_array_increase_by(total, sizeof(f_string_dynamic_t), (void **) &set->names.array, &set->names.used, &set->names.size);
     }
 
@@ -644,6 +652,10 @@ extern "C" {
     }
 
     if (F_status_is_error_not(main->setting.state.status)) {
+      main->setting.state.status = f_memory_array_increase_by(total, sizeof(uint32_t), (void **) &set->totals.array, &set->totals.used, &set->totals.size);
+    }
+
+    if (F_status_is_error_not(main->setting.state.status)) {
       main->setting.state.status = F_okay;
     }
   }
index 2682fea6afd8991a7338fd6f022ddafa48188aa5..232f8aed764ac1e06f33408a5f649c4615b7c018 100644 (file)
@@ -29,6 +29,9 @@ extern "C" {
  *   - size_receive: The block size in bytes to use when sending packets.
  *   - size_send:    The block size in bytes to use when receiving packets.
  *
+ * kt_tacocat_cache_*_d:
+ *   - peek: The size in bytes representing the size of the peek cache (should be set to at least "kt_tacocat_block_size_receive_d + 1" and must be greater than zero).
+ *
  * kt_tacocat_interval_*_d:
  *   - poll: The time in milliseconds to poll for before returning (this is the amount of time poll() blocks).
  *
@@ -44,15 +47,22 @@ extern "C" {
  * kt_tacocat_signal_*_d:
  *   - check:          When not using threads, this is how often to perform the check (lower numbers incur more kernel I/O).
  *   - check_failsafe: When using threads, how many consecutive failures to check signal before aborting (as a recursion failsafe).
+ *
+ * kt_tacocat_startup_*_d:
+ *   - retry_delay_second:      The delay in seconds to wait between each retry.
+ *   - retry_delay_millisecond: The delay in milliseconds to wait between each retry.
+ *   - retry_max:               During start up, the maximum number of retries to perform when trying to establish the initial connection before giving up.
  */
 #ifndef _di_kt_tacocat_d_
   #define kt_tacocat_allocation_console_d 0x4
   #define kt_tacocat_allocation_large_d   0x800
   #define kt_tacocat_allocation_small_d   0x80
 
-  #define kt_tacocat_block_size_d         0xffff
-  #define kt_tacocat_block_size_receive_d kt_tacocat_block_size_d
-  #define kt_tacocat_block_size_send_d    kt_tacocat_block_size_d
+  #define kt_tacocat_block_size_d          0xffff
+  #define kt_tacocat_block_size_receive_d  kt_tacocat_block_size_d
+  #define kt_tacocat_block_size_send_d     kt_tacocat_block_size_d
+
+  #define kt_tacocat_cache_size_peek_d (kt_tacocat_block_size_receive_d + 1)
 
   #define kt_tacocat_interval_poll_d 1400 // 1.4 second.
 
@@ -65,6 +75,10 @@ extern "C" {
 
   #define kt_tacocat_signal_check_d          0x4e20
   #define kt_tacocat_signal_check_failsafe_d 0x4e20
+
+  #define kt_tacocat_startup_retry_delay_second_d      3
+  #define kt_tacocat_startup_retry_delay_millisecond_d 0
+  #define kt_tacocat_startup_retry_max_d               24
 #endif // _di_kt_tacocat_d_
 
 /**
@@ -79,6 +93,14 @@ extern "C" {
  *
  * macro_setting_load_handle_send_receive_error_file_continue_1:
  *   The same as macro_setting_load_handle_send_receive_error_continue_1() but intended for file errors.
+ *
+ * macro_kt_receive_process_handle_error_exit_1:
+ *   Intended to be used for handling an error during the receive process while processing within flag kt_tacocat_socket_flag_block_begin_e.
+ *   The parameter id_data and is set to 0 to disable and is otherwise an address pointer.
+ *
+ * macro_kt_receive_process_handle_error_exit_2:
+ *   Intended to be used for handling an error during the receive process while not processing within flag kt_tacocat_socket_flag_block_begin_e.
+ *   The parameter id_data and is set to 0 to disable and is otherwise an address pointer.
  */
 #ifndef _di_kt_tacocat_macros_d_
   #define macro_setting_load_print_first() \
@@ -128,6 +150,36 @@ extern "C" {
       \
       continue; \
     }
+
+  // @todo handle error, perform memory clearing and possibly send try again message to client but for now, just close the connection gracefully.
+  #define macro_kt_receive_process_handle_error_exit_1(main, method, name, status, flag, id_data) \
+    if (F_status_is_error(*status)) { \
+      kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(method), kt_tacocat_receive_s, *name, *status); \
+      \
+      if (id_data) { \
+        f_file_close_id(id_data); \
+      } \
+      \
+      *flag -= kt_tacocat_socket_flag_block_begin_e; \
+      \
+      return; \
+    }
+
+    // @todo handle error, perform memory clearing and possibly send try again message to client but for now, just close the connection gracefully.
+    #define macro_kt_receive_process_handle_error_exit_2(main, method, name, status, flag, id_data) \
+      if (F_status_is_error(*status)) { \
+        kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(method), kt_tacocat_receive_s, *name, *status); \
+        \
+        if (id_data) { \
+          f_file_close_id(id_data); \
+        } \
+        \
+        *flag -= *flag & kt_tacocat_socket_flag_block_begin_e; \
+        *flag -= *flag & kt_tacocat_socket_flag_block_control_e; \
+        *flag -= *flag & kt_tacocat_socket_flag_block_payload_e; \
+        \
+        return; \
+      }
 #endif // _di_kt_tacocat_macro_d_
 
 #ifdef __cplusplus
index a7b6537250eae6fce54eb4688b6d267a1d9f8571..eee8aa66f39cdb66db209913931cb8c5e7064293 100644 (file)
@@ -131,14 +131,16 @@ extern "C" {
  *
  * kt_tacocat_socket_flag_*_e:
  *   - none:          No flags set.
+ *   - block_begin:   The control block is ready to be read (but has not been fully ready yet).
  *   - block_control: The control block is fully read.
  *   - block_payload: The payload block is fully read.
  */
 #ifndef _di_kt_tacocat_socket_flag_e_
   enum {
     kt_tacocat_socket_flag_none_e          = 0x0,
-    kt_tacocat_socket_flag_block_control_e = 0x1,
-    kt_tacocat_socket_flag_block_payload_e = 0x2,
+    kt_tacocat_socket_flag_block_begin_e   = 0x1,
+    kt_tacocat_socket_flag_block_control_e = 0x2,
+    kt_tacocat_socket_flag_block_payload_e = 0x4,
   }; // enum
 #endif // _di_kt_tacocat_socket_flag_e_
 
index eed371706d0be0b53f97800bc88c3827f99a2a07..6553719fbad662ae78a80f5027d9dcbbe2d1d4c6 100644 (file)
@@ -7,6 +7,7 @@ extern "C" {
 #ifndef _di_kt_tacocat_f_a_
   const f_string_t kt_tacocat_f_a[] = {
     "f_console_parameter_process",
+    "f_file_close_id",
     "f_file_open",
     "f_fss_simple_packet_identify",
     "f_memory_array_increase_by",
@@ -21,11 +22,13 @@ extern "C" {
     "f_socket_create",
     "f_socket_disconnect",
     "f_socket_listen",
+    "f_socket_option_set",
     "f_socket_read_stream",
     "f_string_append_nulless",
     "f_string_dynamic_append",
     "f_string_dynamic_append_nulless",
     "f_thread_create",
+    "fl_conversion_dynamic_partial_to_unsigned_detect",
     "fl_conversion_dynamic_to_unsigned_detect",
     "fll_program_parameter_process_context",
     "fll_program_parameter_process_verbosity",
index 2f119355e3f46238e370cbe3722d992555c4badf..b1a4e309987c3b1c78bca3824e234be4a4df2322 100644 (file)
@@ -40,6 +40,7 @@ extern "C" {
 #ifndef _di_kt_tacocat_f_e_
   enum {
     kt_tacocat_f_f_console_parameter_process_e,
+    kt_tacocat_f_f_file_close_id_e,
     kt_tacocat_f_f_file_open_e,
     kt_tacocat_f_f_fss_simple_packet_identify_e,
     kt_tacocat_f_f_memory_array_increase_by_e,
@@ -54,11 +55,13 @@ extern "C" {
     kt_tacocat_f_f_socket_create_e,
     kt_tacocat_f_f_socket_disconnect_e,
     kt_tacocat_f_f_socket_listen_e,
+    kt_tacocat_f_f_socket_option_set_e,
     kt_tacocat_f_f_socket_read_stream_e,
     kt_tacocat_f_f_string_append_nulless_e,
     kt_tacocat_f_f_string_dynamic_append_e,
     kt_tacocat_f_f_string_dynamic_append_nulless_e,
     kt_tacocat_f_f_thread_create_e,
+    kt_tacocat_f_fl_conversion_dynamic_partial_to_unsigned_detect_e,
     kt_tacocat_f_fl_conversion_dynamic_to_unsigned_detect_e,
     kt_tacocat_f_fll_program_parameter_process_context_e,
     kt_tacocat_f_fll_program_parameter_process_verbosity_e,
index 7e55f033998f10c0b695c7d2eb131ba4f1ef7f55..c20ef6630db3ed2a338ce7ed911c4fb3ab07296d 100644 (file)
@@ -35,10 +35,15 @@ extern "C" {
         } // for
 
         for (j = 0; j < sets[i]->sockets.used ; ++j) {
+
+          f_file_close_id(&sets[i]->sockets.array[j].id_data);
+
           f_socket_disconnect(&sets[i]->sockets.array[j], program.signal_received ? f_socket_close_fast_e : f_socket_close_read_write_e);
         } // for
 
         f_memory_array_resize(0, sizeof(uint16_t), (void **) &sets[i]->flags.array, &sets[i]->flags.used, &sets[i]->flags.size);
+        f_memory_array_resize(0, sizeof(uint16_t), (void **) &sets[i]->retrys.array, &sets[i]->retrys.used, &sets[i]->retrys.size);
+        f_memory_array_resize(0, sizeof(uint32_t), (void **) &sets[i]->totals.array, &sets[i]->totals.used, &sets[i]->totals.size);
         f_memory_array_resize(0, sizeof(f_file_t), (void **) &sets[i]->files.array, &sets[i]->files.used, &sets[i]->files.size);
         f_memory_array_resize(0, sizeof(f_poll_t), (void **) &sets[i]->polls.array, &sets[i]->polls.used, &sets[i]->polls.size);
         f_memory_array_resize(0, sizeof(f_socket_t), (void **) &sets[i]->sockets.array, &sets[i]->sockets.used, &sets[i]->sockets.size);
index 76fbdcbb238a4293e35dc834db3cfd93d0498001..fe8da645a237523cc982c18c8612a4926e711de9 100644 (file)
@@ -23,6 +23,8 @@ extern "C" {
  * max_buffer:  The maximum size in bytes to used to represent a block when sending or receiving packets.
  *
  * flags:   An array of flags for each socket.
+ * retrys:  An array of the current number of retries performed for the given network packet.
+ * totals:  An array of the total network stream size accoding to the processed packet.
  * files:   An array of files for each socket.
  * polls:   An array of sockets to poll, specifically for passing to f_file_poll().
  * sockets: An array of the network sockets.
@@ -37,6 +39,8 @@ extern "C" {
     f_number_unsigned_t size_block;
 
     f_uint16s_t flags;
+    f_uint16s_t retrys;
+    f_uint32s_t totals;
     f_files_t files;
     f_polls_t polls;
     f_sockets_t sockets;
@@ -51,6 +55,8 @@ extern "C" {
     { \
       kt_tacocat_block_size_d, \
       f_uint16s_t_initialize, \
+      f_uint16s_t_initialize, \
+      f_uint32s_t_initialize, \
       f_files_t_initialize, \
       f_polls_t_initialize, \
       f_sockets_t_initialize, \
@@ -64,6 +70,8 @@ extern "C" {
     { \
       size_block, \
       f_uint16s_t_initialize, \
+      f_uint16s_t_initialize, \
+      f_uint32s_t_initialize, \
       f_files_t_initialize, \
       f_polls_t_initialize, \
       f_sockets_t_initialize, \
@@ -129,6 +137,22 @@ extern "C" {
 #endif // _di_kt_tacocat_setting_t_
 
 /**
+ * The TacocaT caches.
+ *
+ * peek: A static cache intended to be used for performing a peek on a given network stream.
+ */
+#ifndef _di_kt_tacocat_cache_t_
+  typedef struct {
+    f_char_t peek[kt_tacocat_cache_size_peek_d];
+  } kt_tacocat_cache_t;
+
+  #define kt_tacocat_cache_t_initialize \
+    { \
+      { 0 }, \
+    }
+#endif // _di_kt_tacocat_cache_t_
+
+/**
  * The TacocaT callbacks.
  *
  * setting_load_send_receive: Process loading the settings regarding send and receive, handling DNS resolution and file opening as needed.
@@ -174,6 +198,7 @@ extern "C" {
     kt_tacocat_setting_t setting;
     kt_tacocat_callback_t callback;
     kt_tacocat_thread_t thread;
+    kt_tacocat_cache_t cache;
   } kt_tacocat_main_t;
 
   #define kt_tacocat_main_t_initialize \
@@ -182,6 +207,7 @@ extern "C" {
       kt_tacocat_setting_t_initialize, \
       kt_tacocat_callback_t_initialize, \
       kt_tacocat_thread_t_initialize, \
+      kt_tacocat_cache_t_initialize, \
     }
 #endif // _di_kt_tacocat_main_t_
 
index 595fe9f5604d88c8bce24025a8b78205035cd7f1..a759af77cdb90da61422a260f8ec8187e8d787dc 100644 (file)
@@ -16,6 +16,18 @@ extern "C" {
   }
 #endif // _di_kt_tacocat_print_error_
 
+#ifndef _di_kt_tacocat_print_error_status_
+  f_status_t kt_tacocat_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status) {
+
+    if (!print) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    fll_error_print(print, F_status_set_fine(status), function, F_true);
+
+    return F_okay;
+  }
+#endif // _di_kt_tacocat_print_error_status_
+
 #ifndef _di_kt_tacocat_print_error_file_
   f_status_t kt_tacocat_print_error_file(fl_print_t * const print, const f_string_t function, const f_string_static_t name, const f_string_static_t operation, const uint8_t type) {
 
@@ -31,7 +43,7 @@ extern "C" {
 #ifndef _di_kt_tacocat_print_error_on_
   f_status_t kt_tacocat_print_error_on(fl_print_t * const print, const f_string_t function, f_string_static_t on, const f_string_static_t network, const f_status_t status) {
 
-    if (!print || !print->custom) return F_status_set_error(F_output_not);
+    if (!print) return F_status_set_error(F_output_not);
     if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
 
     f_file_stream_lock(print->to);
@@ -53,7 +65,7 @@ extern "C" {
 #ifndef _di_kt_tacocat_print_error_on_buffer_too_large_
   f_status_t kt_tacocat_print_error_on_buffer_too_large(fl_print_t * const print, f_string_static_t on, const f_string_static_t network) {
 
-    if (!print || !print->custom) return F_status_set_error(F_output_not);
+    if (!print) return F_status_set_error(F_output_not);
     if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
 
     f_file_stream_lock(print->to);
@@ -70,6 +82,50 @@ extern "C" {
   }
 #endif // _di_kt_tacocat_print_error_on_buffer_too_large_
 
+#ifndef _di_kt_tacocat_print_error_on_busy_
+  f_status_t kt_tacocat_print_error_on_busy(fl_print_t * const print, f_string_static_t on, const f_string_static_t network) {
+
+    if (!print) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    f_file_stream_lock(print->to);
+
+    fl_print_format("%[%QNetwork on%] ", print->to, print->set->error, print->prefix, print->set->error);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, on, print->set->notable);
+    fl_print_format(" %[for '%]", print->to, print->set->error, print->set->error, f_string_eol_s);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, network, print->set->notable);
+    fl_print_format("%[' is busy.%]%r", print->to, print->set->error, print->set->error, f_string_eol_s);
+
+    f_file_stream_unlock(print->to);
+
+    return F_okay;
+  }
+#endif // _di_kt_tacocat_print_error_on_busy_
+
+#ifndef _di_kt_tacocat_print_error_on_packet_too_small_
+  f_status_t kt_tacocat_print_error_on_packet_too_small(fl_print_t * const print, f_string_static_t on, const f_string_static_t network, const f_number_unsigned_t size_expect, const f_number_unsigned_t size_got) {
+
+    if (!print) return F_status_set_error(F_output_not);
+    if (print->verbosity < f_console_verbosity_error_e) return F_output_not;
+
+    f_file_stream_lock(print->to);
+
+    fl_print_format("%[%QNetwork on%] ", print->to, print->set->error, print->prefix, print->set->error);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, on, print->set->notable);
+    fl_print_format(" %[for '%]", print->to, print->set->error, print->set->error, f_string_eol_s);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, network, print->set->notable);
+    fl_print_format("%[', the received packet is too small (expecting%] ", print->to, print->set->error, print->set->error);
+    fl_print_format("%[%ul%]", print->to, print->set->notable, size_expect, print->set->notable);
+    fl_print_format(" %[bytes but instead got%] ", print->to, print->set->error, print->set->error, f_string_eol_s);
+    fl_print_format("%[%ul%]", print->to, print->set->notable, size_got, print->set->notable);
+    fl_print_format("%[ bytes).%]%r", print->to, print->set->error, print->set->error, f_string_eol_s);
+
+    f_file_stream_unlock(print->to);
+
+    return F_okay;
+  }
+#endif // _di_kt_tacocat_print_error_on_packet_too_small_
+
 #ifndef _di_kt_tacocat_print_error_parameter_value_resolve_unknown_
   f_status_t kt_tacocat_print_error_parameter_value_resolve_unknown(fl_print_t * const print, const f_string_dynamic_t unknown) {
 
index 18f3613213552c4c718aa037a5d4db8fb0d3d9cd..0800437ce8bdb06003afe69f8506a5423434f335 100644 (file)
@@ -22,7 +22,11 @@ extern "C" {
  * @param print
  *   The output structure to print to.
  *
+ *   This requires print.custom to be fake_main_t.
+ *
  *   This does not alter print.custom.setting.state.status.
+ * @param function
+ *   A string representing the function that has an error.
  *
  * @return
  *   F_okay on success.
@@ -37,11 +41,37 @@ extern "C" {
 #endif // _di_kt_tacocat_print_error_
 
 /**
+ * Print generic error message regarding a function failing in some way using the given status.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param function
+ *   A string representing the function that has an error.
+ * @param status
+ *   The status code representing the error being reported.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_print()
+ */
+#ifndef _di_kt_tacocat_print_error_status_
+  extern f_status_t kt_tacocat_print_error_status(fl_print_t * const print, const f_string_t function, const f_status_t status);
+#endif // _di_kt_tacocat_print_error_status_
+
+/**
  * Print file related error or warning messages.
  *
  * @param print
  *   The output structure to print to.
  *
+ *   This requires print.custom to be fake_main_t.
+ *
  *   This does not alter print.custom.setting.state.status.
  * @param function
  *   The name of the function where the error happened.
@@ -66,7 +96,7 @@ extern "C" {
 #endif // _di_kt_tacocat_print_error_file_
 
 /**
- * Print file related error or warning messages.
+ * Print network-related error message regarding a function failing in some way using the given status.
  *
  * @param print
  *   The output structure to print to.
@@ -91,11 +121,11 @@ extern "C" {
  * @see fll_error_file_print()
  */
 #ifndef _di_kt_tacocat_print_error_on_
-  f_status_t kt_tacocat_print_error_on(fl_print_t * const print, const f_string_t function, f_string_static_t on, const f_string_static_t network, const f_status_t status);
+  extern f_status_t kt_tacocat_print_error_on(fl_print_t * const print, const f_string_t function, f_string_static_t on, const f_string_static_t network, const f_status_t status);
 #endif // _di_kt_tacocat_print_error_on_
 
 /**
- * Print file related error or warning messages for when buffer is too large to accept additional packet blocks.
+ * Print network-related error message for when buffer is too large to accept additional packet blocks.
  *
  * @param print
  *   The output structure to print to.
@@ -115,10 +145,62 @@ extern "C" {
  * @see fll_error_file_print()
  */
 #ifndef _di_kt_tacocat_print_error_on_buffer_too_large_
-  f_status_t kt_tacocat_print_error_on_buffer_too_large(fl_print_t * const print, f_string_static_t on, const f_string_static_t network);
+  extern f_status_t kt_tacocat_print_error_on_buffer_too_large(fl_print_t * const print, f_string_static_t on, const f_string_static_t network);
 #endif // _di_kt_tacocat_print_error_on_buffer_too_large_
 
 /**
+ * Print network-related error message for when the connection is busy.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param on
+ *   The network connection direction, which should either be "receive" or "send".
+ * @param network
+ *   The name of the network in which the error is related.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_file_print()
+ */
+#ifndef _di_kt_tacocat_print_error_on_busy_
+  extern f_status_t kt_tacocat_print_error_on_busy(fl_print_t * const print, f_string_static_t on, const f_string_static_t network);
+#endif // _di_kt_tacocat_print_error_on_busy_
+
+/**
+ * Print network-related error message for when the connection is busy.
+ *
+ * @param print
+ *   The output structure to print to.
+ *
+ *   This does not alter print.custom.setting.state.status.
+ * @param on
+ *   The network connection direction, which should either be "receive" or "send".
+ * @param network
+ *   The name of the network in which the error is related.
+ * @param size_expect
+ *   The expected packet size.
+ * @param size_got
+ *   The packet size that is received.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_file_print()
+ */
+#ifndef _di_kt_tacocat_print_error_on_packet_too_small_
+  extern f_status_t kt_tacocat_print_error_on_packet_too_small(fl_print_t * const print, f_string_static_t on, const f_string_static_t network, const f_number_unsigned_t size_expect, const f_number_unsigned_t size_got);
+#endif // _di_kt_tacocat_print_error_on_packet_too_small_
+
+/**
  * Print error message for when an unknown value for the resolve parameter is provided.
  *
  * @param print
@@ -146,6 +228,8 @@ extern "C" {
  * @param print
  *   The output structure to print to.
  *
+ *   This requires print.custom to be fake_main_t.
+ *
  *   This does not alter print.custom.setting.state.status.
  * @param address
  *   The entire address string, including the port number.
index 3e3b16e74028f66e2b45828f17a8d4cfc240978b..3efd5f17f8c8966678e64e86e495fba2d9728572 100644 (file)
@@ -4,24 +4,45 @@
 extern "C" {
 #endif
 
-#ifndef _di_kt_tacocat_print_warning_parameter_integer_is_
-  f_status_t kt_tacocat_print_warning_parameter_integer_is(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name, const f_string_static_t is) {
+#ifndef _di_kt_tacocat_print_warning_on_busy_
+  f_status_t kt_tacocat_print_warning_on_busy(fl_print_t * const print, f_string_static_t on, const f_string_static_t network, const f_number_unsigned_t retry) {
 
     if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not;
 
     f_file_stream_lock(print->to);
 
-    fl_print_format("%[%QThe value for the parameter '%]", print->to, print->set->error, print->set->error);
+    fl_print_format("%[%QNetwork on%] ", print->to, print->context, print->prefix, print->context);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, on, print->set->notable);
+    fl_print_format(" %[for '%]", print->to, print->context, print->context, f_string_eol_s);
+    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, network, print->set->notable);
+    fl_print_format("%[' is busy, pausing and then retrying %ul/%ul.%]%r", print->to, print->context, retry, kt_tacocat_startup_retry_max_d, print->context, f_string_eol_s);
+
+    f_file_stream_unlock(print->to);
+
+    return F_okay;
+  }
+#endif // _di_kt_tacocat_print_warning_on_busy_
+
+#ifndef _di_kt_tacocat_print_warning_parameter_integer_less_than_
+  f_status_t kt_tacocat_print_warning_parameter_integer_less_than(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name, const f_string_static_t is) {
+
+    if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not;
+
+    f_file_stream_lock(print->to);
+
+    fl_print_format("%[%QThe value '%]", print->to, print->context, print->context);
+    fl_print_format(f_string_format_QQ_single_s.string, print->to, print->set->notable, is, print->set->notable);
+    fl_print_format("%[' for the parameter '%]", print->to, print->context, print->context);
     fl_print_format(f_string_format_QQ_single_s.string, print->to, print->set->notable, symbol, name, print->set->notable);
-    fl_print_format("%[' is %]", print->to, print->set->error, print->set->error);
-    fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, is, print->set->notable);
-    fl_print_format(f_string_format_sentence_end_s.string, print->to, print->set->error, print->set->error, f_string_eol_s);
+    fl_print_format("%[' is less than %]", print->to, print->context, print->context);
+    fl_print_format("%[%ul%]", print->to, print->notable, kt_tacocat_packet_peek_d, print->notable);
+    fl_print_format(f_string_format_sentence_end_s.string, print->to, print->context, print->context, f_string_eol_s);
 
     f_file_stream_unlock(print->to);
 
     return F_okay;
   }
-#endif // _di_kt_tacocat_print_warning_parameter_integer_is_
+#endif // _di_kt_tacocat_print_warning_parameter_integer_less_than_
 
 #ifndef _di_kt_tacocat_print_warning_port_number_overflow_
   f_status_t kt_tacocat_print_warning_port_number_overflow(fl_print_t * const print, const f_string_static_t address, const f_number_unsigned_t port) {
index a4ed861d8c7113a56715ba1bb81ad1fca1030a36..9b9b6329c13205c5a522d8bf8c2daf5465455151 100644 (file)
@@ -17,12 +17,37 @@ extern "C" {
 #endif
 
 /**
- * Print warning message about given parameter being a specific integer value.
+ * Print warning message about given port number being out of range for this system.
+ * Print file related error or warning messages.
  *
  * @param print
  *   The output structure to print to.
  *
- *   This requires print.custom to be fake_main_t.
+ *   This does not alter print.custom.setting.state.status.
+ * @param on
+ *   The network connection direction, which should either be "receive" or "send".
+ * @param network
+ *   The name of the network in which the error is related.
+ * @param retry
+ *   The current retry attempt.
+ *
+ * @return
+ *   F_okay on success.
+ *   F_output_not on success, but no printing is performed.
+ *
+ *   F_output_not (with error bit) if setting is NULL.
+ *
+ * @see fll_error_file_print()
+ */
+#ifndef _di_kt_tacocat_print_warning_on_busy_
+  extern f_status_t kt_tacocat_print_warning_on_busy(fl_print_t * const print, f_string_static_t on, const f_string_static_t network, const f_number_unsigned_t retry);
+#endif // _di_kt_tacocat_print_warning_on_busy_
+
+/**
+ * Print warning message about given parameter being a specific integer value.
+ *
+ * @param print
+ *   The output structure to print to.
  *
  *   This does not alter print.custom.setting.state.status.
  * @param symbol
@@ -44,9 +69,9 @@ extern "C" {
  * @see f_file_stream_unlock()
  * @see fl_print_format()
  */
-#ifndef _di_kt_tacocat_print_warning_parameter_integer_is_
-  extern f_status_t kt_tacocat_print_warning_parameter_integer_is(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name, const f_string_static_t is);
-#endif // _di_kt_tacocat_print_warning_parameter_integer_is_
+#ifndef _di_kt_tacocat_print_warning_parameter_integer_less_than_
+  extern f_status_t kt_tacocat_print_warning_parameter_integer_less_than(fl_print_t * const print, const f_string_static_t symbol, const f_string_static_t name, const f_string_static_t than);
+#endif // _di_kt_tacocat_print_warning_parameter_integer_less_than_
 
 /**
  * Print warning message about given port number being out of range for this system.
@@ -54,8 +79,6 @@ extern "C" {
  * @param print
  *   The output structure to print to.
  *
- *   This requires print.custom to be fake_main_t.
- *
  *   This does not alter print.custom.setting.state.status.
  * @param address
  *   The original address string.
index 2748b3a15a158b515301d646e9003d93f0096fa4..68ab129d8f26010fab81ab5c76b54e1a5b022d88 100644 (file)
@@ -72,12 +72,20 @@ extern "C" {
 
       if (kt_tacocat_signal_check(main)) return F_status_set_error(F_interrupt);
 
+      status = f_file_close_id(&set->sockets.array[i].id_data);
+
+      if (F_status_is_error_not(set->statuss.array[i]) && F_status_is_error(status)) {
+        set->statuss.array[i] = status;
+
+        kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_file_close_id), status);
+      }
+
       status = f_socket_disconnect(&set->sockets.array[i], f_socket_close_read_write_e);
 
       if (F_status_is_error_not(set->statuss.array[i]) && F_status_is_error(status)) {
         set->statuss.array[i] = status;
 
-        kt_tacocat_print_error(&main->program.error, macro_kt_tacocat_f(f_socket_disconnect));
+        kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_disconnect), status);
       }
     } // for
 
@@ -114,7 +122,7 @@ extern "C" {
         *status = F_status_set_error(F_parameter);
       }
 
-      kt_tacocat_print_error(&main->program.error, macro_kt_tacocat_f(kt_tacocat_process_socket_set_error_has));
+      kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(kt_tacocat_process_socket_set_error_has), *status);
 
       return F_status_set_error(F_parameter);
     }
@@ -136,6 +144,8 @@ extern "C" {
 
     if (!main || F_status_is_error(main->setting.status_receive)) return;
 
+    int value_socket = 0;
+
     for (f_number_unsigned_t i = 0; i < main->setting.receive.sockets.used; ++i) {
 
       if (kt_tacocat_signal_check(main)) return;
@@ -146,37 +156,93 @@ extern "C" {
       if (F_status_is_error(main->setting.receive.statuss.array[i])) {
         main->setting.status_receive = main->setting.receive.statuss.array[i];
 
-        kt_tacocat_print_error(&main->program.error, macro_kt_tacocat_f(f_socket_create));
+        kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_create), main->setting.status_receive);
 
         continue;
       }
 
-      if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet4_e) {
-        main->setting.receive.statuss.array[i] = f_socket_bind_inet4(&main->setting.receive.sockets.array[i]);
-      }
-      else if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet6_e) {
-        main->setting.receive.statuss.array[i] = f_socket_bind_inet6(&main->setting.receive.sockets.array[i]);
-      }
-      else if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_local_e) {
-        main->setting.receive.statuss.array[i] = f_socket_bind_local(&main->setting.receive.sockets.array[i]);
+      // Make the socket re-usable.
+      {
+        value_socket = 1;
+
+        main->setting.receive.statuss.array[i] = f_socket_option_set(&main->setting.receive.sockets.array[i], SOL_SOCKET, f_socket_option_address_reuse_e | f_socket_option_port_reuse_e, &value_socket, sizeof(int));
+
+        if (F_status_is_error(main->setting.receive.statuss.array[i])) {
+          main->setting.status_receive = main->setting.receive.statuss.array[i];
+
+          kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_option_set), main->setting.status_receive);
+
+          continue;
+        }
       }
-      else {
-        main->setting.status_receive = F_status_set_error(F_parameter);
 
-        kt_tacocat_print_error_socket_protocol_unsupported(&main->program.error, main->setting.receive.names.array[i], main->setting.receive.sockets.array[i].domain);
+      for (main->setting.receive.retrys.array[i] = 0; main->setting.receive.retrys.array[i] < kt_tacocat_startup_retry_max_d; ++main->setting.receive.retrys.array[i]) {
 
-        return;
+        if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet4_e) {
+          main->setting.receive.statuss.array[i] = f_socket_bind_inet4(&main->setting.receive.sockets.array[i]);
+        }
+        else if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet6_e) {
+          main->setting.receive.statuss.array[i] = f_socket_bind_inet6(&main->setting.receive.sockets.array[i]);
+        }
+        else if (main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_local_e) {
+          main->setting.receive.statuss.array[i] = f_socket_bind_local(&main->setting.receive.sockets.array[i]);
+        }
+        else {
+          main->setting.status_receive = F_status_set_error(F_parameter);
+
+          kt_tacocat_print_error_socket_protocol_unsupported(&main->program.error, main->setting.receive.names.array[i], main->setting.receive.sockets.array[i].domain);
+
+          return;
+        }
+
+        if (F_status_set_fine(main->setting.receive.statuss.array[i]) == F_busy_address) {
+          if (main->setting.receive.retrys.array[i] < kt_tacocat_startup_retry_max_d) {
+            kt_tacocat_print_warning_on_busy(&main->program.warning, kt_tacocat_receive_s, main->setting.receive.names.array[i], main->setting.receive.retrys.array[i] + 1);
+
+            struct timespec time = { 0 };
+
+            main->setting.receive.statuss.array[i] = f_time_spec_millisecond(kt_tacocat_startup_retry_delay_second_d, kt_tacocat_startup_retry_delay_millisecond_d, &time);
+
+            if (F_status_is_error_not(main->setting.receive.statuss.array[i])) {
+              nanosleep(&time, 0);
+            }
+
+            if (main->program.signal_received) {
+              main->setting.status_receive = F_status_set_error(F_interrupt);
+
+              return;
+            }
+
+            main->setting.receive.statuss.array[i] = F_status_set_error(F_busy_address);
+
+            continue;
+          }
+        }
+
+        break;
+      } // for
+
+      if (F_status_is_error_not(main->setting.receive.statuss.array[i]) && main->setting.receive.retrys.array[i] < kt_tacocat_startup_retry_max_d) {
+        main->setting.receive.statuss.array[i] = F_okay;
       }
 
+      main->setting.receive.retrys.array[i] = 0;
+
       if (F_status_is_error(main->setting.receive.statuss.array[i])) {
         main->setting.status_receive = main->setting.receive.statuss.array[i];
 
-        kt_tacocat_print_error(&main->program.error, main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet4_e
-          ? macro_kt_tacocat_f(f_socket_bind_inet4)
-          : main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet6_e
-            ? macro_kt_tacocat_f(f_socket_bind_inet6)
-            : macro_kt_tacocat_f(f_socket_bind_local)
-        );
+        if (F_status_set_fine(main->setting.status_receive) == F_busy_address) {
+          kt_tacocat_print_error_on_busy(&main->program.error, kt_tacocat_receive_s, main->setting.receive.names.array[i]);
+        }
+        else {
+          kt_tacocat_print_error_status(&main->program.error, main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet4_e
+            ? macro_kt_tacocat_f(f_socket_bind_inet4)
+            : main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet6_e
+              ? macro_kt_tacocat_f(f_socket_bind_inet6)
+              : macro_kt_tacocat_f(f_socket_bind_local),
+            main->setting.status_receive
+          );
+        }
 
         continue;
       }
@@ -186,7 +252,7 @@ extern "C" {
       if (F_status_is_error(main->setting.receive.statuss.array[i])) {
         main->setting.status_receive = main->setting.receive.statuss.array[i];
 
-        kt_tacocat_print_error(&main->program.error, macro_kt_tacocat_f(f_socket_listen));
+        kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_listen), main->setting.status_receive);
 
         continue;
       }
@@ -224,7 +290,7 @@ extern "C" {
       if (F_status_is_error(main->setting.send.statuss.array[i])) {
         main->setting.status_send = main->setting.send.statuss.array[i];
 
-        kt_tacocat_print_error(&main->program.error, macro_kt_tacocat_f(f_socket_create));
+        kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_create), main->setting.status_send);
 
         continue;
       }
index fe3841af65245143d13b49a2b5e25d9e7ead27b3..29f2be257433d108b0292ef71b1877f57843a9f2 100644 (file)
@@ -32,8 +32,7 @@ extern "C" {
 
             if (main->setting.receive.polls.array[i].fd == -1) continue;
 
-            // @todo figure out what f_poll_urgent_e can be.
-            if (main->setting.receive.polls.array[i].revents & (f_poll_read_e | f_poll_urgent_e)) {
+            if (main->setting.receive.polls.array[i].revents & (f_poll_read_e)) {
               kt_tacocat_receive_process(main, i);
 
               main->setting.receive.polls.array[i].revents = 0;
@@ -68,6 +67,8 @@ extern "C" {
   void kt_tacocat_receive_process(kt_tacocat_main_t * const main, const f_number_unsigned_t index) {
 
     uint16_t * const flag = &main->setting.receive.flags.array[index];
+    uint16_t * const retry = &main->setting.receive.retrys.array[index];
+    uint32_t * const total = &main->setting.receive.totals.array[index];
     f_poll_t * const poll = &main->setting.receive.polls.array[index];
     f_socket_t * const socket = &main->setting.receive.sockets.array[index];
     f_status_t * const status = &main->setting.receive.statuss.array[index];
@@ -75,62 +76,70 @@ extern "C" {
     f_string_dynamic_t * const buffer = &main->setting.receive.buffers.array[index];
     f_fss_simple_packet_range_t * const packet = &main->setting.receive.packets.array[index];
 
-    //if (poll->revents & f_poll_urgent_e) { // handle out of band, via f_socket_flag_out_of_band_e?
-
-    size_t length = 0;
+    size_t length_read = 0;
 
     // This is a new packet (kt_tacocat_socket_flag_none_e).
     if (!(*flag)) {
+      *flag = kt_tacocat_socket_flag_block_begin_e;
+      *retry = 0;
+      *total = 0;
       buffer->used = 0;
       socket->size_read = kt_tacocat_packet_read_d;
     }
 
-    // @todo this check should also be performed after reading the FSS Packet Header against the FSS Payload length value.
-    if (main->setting.flag & kt_tacocat_main_flag_max_buffer_e) {
-      if ((buffer->used + socket->size_read) > main->setting.max_buffer) {
-        buffer->used = 0;
+    const size_t size_read = socket->size_read;
 
-        if (buffer->size > kt_tacocat_max_maintain_d) {
-          *status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
+    // @todo move this section into its own function call.
+    // Load the header of the new packet.
+    if ((*flag) & kt_tacocat_socket_flag_block_begin_e) {
+      *status = f_socket_accept(socket);
 
-          if (F_status_is_error(*status)) {
-            kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_resize), kt_tacocat_receive_s, *name, *status);
+      // The socket failed to accept and so there is no data socket id to close.
+      macro_kt_receive_process_handle_error_exit_1(main, f_socket_accept, name, status, flag, 0);
 
-            return;
-          }
-        }
+      *status = f_memory_array_increase_by(kt_tacocat_packet_peek_d + 1, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
+      macro_kt_receive_process_handle_error_exit_1(main, f_memory_array_increase_by, name, status, flag, &socket->id_data);
 
-        // @todo for all unrecoverable errors, make sure to drop/flush the packet to prevent processing and then reset the status code (otherwise an infinite error loop will occur, which is the current behavior).
-        *status = F_status_set_error(F_packet_too_large);
+      socket->size_read = kt_tacocat_packet_peek_d;
 
-        kt_tacocat_print_error_on_buffer_too_large(&main->program.error, kt_tacocat_receive_s, *name);
+      *status = f_socket_read_stream(socket, 0, (void *) (buffer->string + buffer->used), &length_read);
 
-        return;
-      }
-    }
+      socket->size_read = size_read;
 
-    *status = f_memory_array_increase_by(socket->size_read, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
+      macro_kt_receive_process_handle_error_exit_1(main, f_socket_read_stream, name, status, flag, &socket->id_data);
 
-    if (F_status_is_error(*status)) {
-      kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_increase_by), kt_tacocat_receive_s, *name, *status);
+      buffer->used += length_read;
 
-      return;
-    }
+      // Continue if the packet header is not fully ready (@todo, implement a counter with a max length thaat prevents infinite loop waits, "retry" is intended for this).
+      if (buffer->used < kt_tacocat_packet_peek_d) {
 
-    // This is a new packet (kt_tacocat_socket_flag_none_e).
-    if (!(*flag)) {
-      *status = f_socket_accept(socket);
+        // Peek ahead to see if the client has closed the connection (all the intended data should have been transmitted).
+        if (length_read) {
+          memset(main->cache.peek, 0, kt_tacocat_cache_size_peek_d);
 
-      if (F_status_is_error(*status)) {
-        kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_socket_accept), kt_tacocat_receive_s, *name, *status);
+          socket->size_read = kt_tacocat_cache_size_peek_d - 1;
+          length_read = 0;
 
-        return;
-      }
+          *status = f_socket_read_stream(socket, f_socket_flag_peek_e | f_socket_flag_wait_not_e, (void *) main->cache.peek, &length_read);
 
-      *status = f_socket_read_stream(socket, f_socket_flag_peek_e, (void *) buffer->string, &length);
+          socket->size_read = size_read;
+        }
 
-      if (F_status_is_error(*status)) {
-        kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_socket_read_stream), kt_tacocat_receive_s, *name, *status);
+        // Connection is closed when length is 0, which means the packet is too small.
+        if (!length_read) {
+          kt_tacocat_print_error_on_packet_too_small(&main->program.error, kt_tacocat_receive_s, *name, kt_tacocat_packet_peek_d, buffer->used);
+
+          buffer->used = 0;
+          *retry = 0;
+          *status = F_status_set_error(F_packet_too_small);
+          *flag -= kt_tacocat_socket_flag_block_begin_e;
+
+          f_file_close_id(&socket->id_data);
+
+          return;
+        }
+
+        ++(*retry);
 
         f_file_close_id(&socket->id_data);
 
@@ -144,18 +153,56 @@ extern "C" {
       packet->payload.start = 1;
       packet->payload.stop = 0;
 
+      // @todo need to check/handle if all of the parts exists (want F_okay, but check F_partial, F_data_not, and F_valid_not (F_valid_not has error bit set).
       *status = f_fss_simple_packet_identify(*buffer, packet);
+      macro_kt_receive_process_handle_error_exit_1(main, f_fss_simple_packet_identify, name, status, flag, &socket->id_data);
 
-      if (F_status_is_error(*status)) {
-        kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_fss_simple_packet_identify), kt_tacocat_receive_s, *name, *status);
+      // @todo this needs to be wrapped in big/little endian checks, but for now just use ntohl.
+      *total = ntohl(*((uint32_t *) (buffer->string + 1)));
 
+      if (*total <= F_fss_simple_packet_block_header_size_d) {
+        // @todo handle error, perform memory clearing and possibly send try again message to client but for now, just close the connection gracefully.
         f_file_close_id(&socket->id_data);
 
+        *flag -= kt_tacocat_socket_flag_block_begin_e;
+
         return;
       }
+
+      if (main->setting.flag & kt_tacocat_main_flag_max_buffer_e) {
+        if (*total > main->setting.max_buffer) {
+          buffer->used = 0;
+
+          if (buffer->size > kt_tacocat_max_maintain_d) {
+            *status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
+
+            // Report the resize error but do not fail.
+            if (F_status_is_error(*status)) {
+              kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_resize), kt_tacocat_receive_s, *name, *status);
+            }
+          }
+
+          // @todo for all unrecoverable errors, make sure to drop/flush the packet to prevent processing and then reset the status code (otherwise an infinite error loop will occur, which is the current behavior).
+          *status = F_status_set_error(F_packet_too_large);
+
+          kt_tacocat_print_error_on_buffer_too_large(&main->program.error, kt_tacocat_receive_s, *name); // @todo pass total parameter to print requested packet size.
+
+          // @todo send message to client that the packet is too large but for now, just close the connection gracefully.
+          f_file_close_id(&socket->id_data);
+
+          return;
+        }
+      }
+
+      *flag -= kt_tacocat_socket_flag_block_begin_e;
+      *flag |= kt_tacocat_socket_flag_block_control_e;
     }
 
-    socket->size_read = kt_tacocat_packet_read_d;
+    *status = f_memory_array_increase_by(socket->size_read, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
+    macro_kt_receive_process_handle_error_exit_2(main, f_memory_array_increase_by, name, status, flag, &socket->id_data);
+
+    *status = f_socket_read_stream(socket, f_socket_flag_wait_not_e, (void *) buffer->string, &length_read);
+    macro_kt_receive_process_handle_error_exit_2(main, f_socket_read_stream, name, status, flag, &socket->id_data);
 
     //kt_tacocat_socket_flag_none_e          = 0x0,
     //kt_tacocat_socket_flag_block_control_e = 0x1,
@@ -167,12 +214,13 @@ extern "C" {
     // For now just close the socket until the appropriate code gets written here.
     f_file_close_id(&socket->id_data);
 
-    // @todo perform this check only when fully finished processing all of the packet parts.
+    // @todo perform this check only when fully finished processing all of the packet parts (expected *total is reached).
     if (buffer->size > kt_tacocat_max_maintain_d) {
       buffer->used = 0;
 
       *status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size);
 
+      // Report the resize error but do not fail.
       if (F_status_is_error(*status)) {
         kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_resize), kt_tacocat_receive_s, *name, *status);
       }
index 8331c784376474aed058ca547871fba115372676..8bd461e48556d5c292436445466497979364f36e 100644 (file)
@@ -35,6 +35,7 @@
 #include <fll/level_0/print.h>
 #include <fll/level_0/signal.h>
 #include <fll/level_0/socket.h>
+#include <fll/level_0/time.h>
 #include <fll/level_0/thread.h>
 
 // FLL-1 includes.