Progress: Further work in TacocaT.
authorKevin Day <thekevinday@gmail.com>
Thu, 28 Dec 2023 05:10:21 +0000 (23:10 -0600)
committerKevin Day <thekevinday@gmail.com>
Thu, 28 Dec 2023 05:10:21 +0000 (23:10 -0600)
I have confirmed that the send and receive to/from tacocat works.
This does send and receive with the current code but the written data writes the entire packet rather than just the payload.
This behavior will change.

This begins changing the design to make the receive consistent with some design differences from the send.
The received packet needs to be processed using the appropriate FSS functions.
Much of this is commented out next to where the work needs to be done.

12 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/type.c
sources/c/tacocat/main/common/type.h
sources/c/tacocat/main/receive.c
sources/c/tacocat/main/receive.h
sources/c/tacocat/main/send.c
sources/c/tacocat/main/send.h
sources/c/tacocat/main/tacocat.h

index f3be5631c172f87d418b94cfb5a7bd03ec5b8532..9b4c10e0397c73dfd9c018c0ccbff98139826a57 100644 (file)
@@ -27,5 +27,6 @@ fl_fss
 fl_print
 
 fll_error
+fll_fss
 fll_print
 fll_program
index 42f3596e8660477900ed58f80f8186e4434741ac..3366b949fa954a1e263a63fdde6f11063d1158b6 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_fss -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_status_string -lf_string -lf_time -lf_type_array -lf_utf
+build_libraries-individual -lfll_error -lfll_fss -lfll_print -lfll_program -lfl_conversion -lfl_fss -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_status_string -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 7dbc1502deac5ab6d699f26d3993ff299303c410..522a32b5b5e88a154c96a9246dc55807dc8e2d5b 100644 (file)
@@ -162,6 +162,10 @@ extern "C" {
       }
 
       main->setting.interval = number;
+
+      if (number < kt_tacocat_interval_poll_fast_d) {
+        main->setting.interval_fast = number;
+      }
     }
     else if (main->program.parameters.array[kt_tacocat_parameter_interval_e].result & f_console_result_found_e) {
       main->setting.state.status = F_status_set_error(F_parameter);
@@ -346,6 +350,14 @@ extern "C" {
           sets[i]->array[j].packet.payload.stop = 0;
           sets[i]->array[j].retry = 0;
           sets[i]->array[j].status = F_okay;
+          sets[i]->array[j].range.start = 1;
+          sets[i]->array[j].range.stop = 0;
+          sets[i]->array[j].objects.used = 0;
+          sets[i]->array[j].contents.used = 0;
+          sets[i]->array[j].objects_delimits.used = 0;
+          sets[i]->array[j].contents_delimits.used = 0;
+          sets[i]->array[j].comments.used = 0;
+          sets[i]->array[j].state = main->setting.state;
           sets[i]->array[j].socket.id = -1;
           sets[i]->array[j].socket.id_data = -1;
           sets[i]->array[j].socket.form = f_socket_address_form_generic_e;
index 15c6da8f0752abf46ab1eed446cfcb0e62f532f8..f8ca80e7ea7eed6a0ec601f15bf74f5f1c954537 100644 (file)
@@ -33,7 +33,8 @@ extern "C" {
  *   - 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).
+ *   - poll:      The time in milliseconds to poll for before returning (this is the amount of time poll() blocks).
+ *   - poll_fast: The time in milliseconds to poll for before returning fo fast polls, such as when there is an active process (this is the amount of time poll() blocks).
  *
  * kt_tacocat_max_*_d:
  *   - backlog:  The max backlog in bytes size to use.
@@ -67,7 +68,8 @@ extern "C" {
 
   #define kt_tacocat_cache_size_peek_d (kt_tacocat_block_size_receive_d + 1)
 
-  #define kt_tacocat_interval_poll_d 1400 // 1.4 second.
+  #define kt_tacocat_interval_poll_d      1400 // 1.4 second.
+  #define kt_tacocat_interval_poll_fast_d 50   // 0.05 second.
 
   #define kt_tacocat_max_backlog_d  0x400
   #define kt_tacocat_max_buffer_d   0x10000000 // 0x10^0x5 * 0x100 (Which is 256 Megabytes (0x10^0x5 where the base unit is 16 rather than 10 or 2 (maybe call this xytes? Megaxytes?)).
@@ -101,11 +103,11 @@ extern "C" {
  *   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 not processing within flag kt_tacocat_socket_flag_receive_block_control_e.
+ *   Intended to be used for handling an error during the receive process while not processing within flag kt_tacocat_socket_flag_receive_control_e.
  *   The parameter id_data and is set to 0 to disable and is otherwise an address pointer.
  *
  * macro_kt_receive_process_begin_handle_error_exit_1:
- *   Intended to be used for handling an error during the receive process while processing within flag kt_tacocat_socket_flag_receive_block_control_e.
+ *   Intended to be used for handling an error during the receive process while processing within flag kt_tacocat_socket_flag_receive_control_e.
  *
  * @todo document macro_kt_send_process_handle_error_exit_1.
  */
@@ -168,7 +170,7 @@ extern "C" {
       \
       flag = 0; \
       \
-      return; \
+      return F_done_not; \
     }
 
   #define macro_kt_receive_process_begin_handle_error_exit_1(main, method, network, status, name, flag) \
index 747e715040837b1563822fb0c2ffdc3675c06b5e..ce24f5c4f548b5f46f55f9c95c947dc94a2da3f1 100644 (file)
@@ -130,15 +130,21 @@ extern "C" {
  * Individual socket-specific flags for receiving.
  *
  * kt_tacocat_socket_flag_receive_*_e:
- *   - none:          No flags set.
- *   - block_control: Reading and processing the Control block and Size block.
- *   - block_payload: Reading and processing the Payload block.
+ *   - none:    No flags set.
+ *   - control: Reading and processing the Control block and Size block.
+ *   - packet:  Reading and processing the rest of the Packet block (the Header and Payload).
+ *   - check:   Process and check the loaded Payload block, processing the Header.
+ *   - write:   Save the loaded Payload block to the file (write to the file).
+ *   - done:    Done processing file.
  */
 #ifndef _di_kt_tacocat_socket_flag_receive_e_
   enum {
-    kt_tacocat_socket_flag_receive_none_e          = 0x0,
-    kt_tacocat_socket_flag_receive_block_control_e = 0x1,
-    kt_tacocat_socket_flag_receive_block_payload_e = 0x2,
+    kt_tacocat_socket_flag_receive_none_e    = 0x0,
+    kt_tacocat_socket_flag_receive_control_e = 0x1,
+    kt_tacocat_socket_flag_receive_packet_e  = 0x2,
+    kt_tacocat_socket_flag_receive_check_e   = 0x4,
+    kt_tacocat_socket_flag_receive_write_e   = 0x8,
+    kt_tacocat_socket_flag_receive_done_e    = 0x10,
   }; // enum
 #endif // _di_kt_tacocat_socket_flag_receive_e_
 
index a985eb7ca4f285783635c2c232c5a0186e89ba33..8c5ba3d2fc71d33334f35319b0d11a75d1740cd4 100644 (file)
@@ -50,6 +50,26 @@ extern "C" {
         f_file_close_id(&array[i].socket.id_data);
         f_socket_disconnect(&array[i].socket, f_socket_close_fast_e);
 
+        if (array[i].objects.size) {
+          f_memory_array_resize(0, sizeof(f_range_t), (void **) &array[i].objects.array, &array[i].objects.used, &array[i].objects.size);
+        }
+
+        if (array[i].contents.size) {
+          f_memory_arrays_resize(0, sizeof(f_range_t), (void **) &array[i].contents.array, &array[i].contents.used, &array[i].contents.size, &f_rangess_delete_callback);
+        }
+
+        if (array[i].objects_delimits.size) {
+          f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &array[i].objects_delimits.array, &array[i].objects_delimits.used, &array[i].objects_delimits.size);
+        }
+
+        if (array[i].objects_delimits.size) {
+          f_memory_array_resize(0, sizeof(f_number_unsigned_t), (void **) &array[i].contents_delimits.array, &array[i].contents_delimits.used, &array[i].contents_delimits.size);
+        }
+
+        if (array[i].comments.size) {
+          f_memory_array_resize(0, sizeof(f_range_t), (void **) &array[i].comments.array, &array[i].comments.used, &array[i].comments.size);
+        }
+
         if (array[i].buffer.size) {
           f_memory_array_resize(0, sizeof(f_char_t), (void **) &array[i].buffer.string, &array[i].buffer.used, &array[i].buffer.size);
         }
index 7513334f19aec5a1d3f90d6f2add4bc7b8877054..25ae0d1dfa670ba56e2deea8db2ed336e78108fc 100644 (file)
@@ -29,6 +29,14 @@ extern "C" {
  * socket: Socket structure.
  * status: The status of the socket operations.
  *
+ * range:             A generic range, often used for FSS processing.
+ * objects:           An array of FSS Objects.
+ * contents:          An array of FSS Contents.
+ * objects_delimits:  An array of FSS Object delimits.
+ * contents_delimits: An array of FSS Content delimits.
+ * comments:          An array of FSS comments.
+ * state:             Basic state information, usually passed to the FSS functions.
+ *
  * buffer:      A buffer for sending or receiving data between clients.
  * cache:       A cache used for various purposes, but primarily for the building of the send packet.
  * client:      A single client address for some network connection.
@@ -53,6 +61,14 @@ extern "C" {
     f_socket_t socket;
     f_status_t status;
 
+    f_range_t range;
+    f_ranges_t objects;
+    f_rangess_t contents;
+    f_number_unsigneds_t objects_delimits;
+    f_number_unsigneds_t contents_delimits;
+    f_ranges_t comments;
+    f_state_t state;
+
     f_string_dynamic_t buffer;
     f_string_dynamic_t cache;
     f_string_dynamic_t client;
@@ -76,6 +92,13 @@ extern "C" {
       f_file_t_initialize, \
       f_socket_t_initialize, \
       f_status_t_initialize, \
+      f_range_t_initialize, \
+      f_ranges_t_initialize, \
+      f_rangess_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_ranges_t_initialize, \
+      f_state_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
@@ -99,6 +122,13 @@ extern "C" {
       f_poll_t_initialize, \
       f_socket_t_initialize, \
       f_status_t_initialize, \
+      f_range_t_initialize, \
+      f_ranges_t_initialize, \
+      f_rangess_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_ranges_t_initialize, \
+      f_state_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
@@ -122,6 +152,13 @@ extern "C" {
       f_poll_t_initialize, \
       f_socket_t_initialize, \
       f_status_t_initialize, \
+      f_range_t_initialize, \
+      f_ranges_t_initialize, \
+      f_rangess_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_number_unsigneds_t_initialize, \
+      f_ranges_t_initialize, \
+      f_state_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
       f_string_dynamic_t_initialize, \
@@ -164,9 +201,12 @@ extern "C" {
  * This is passed to the program-specific main entry point to designate program settings.
  * These program settings are often processed from the program arguments (often called the command line arguments).
  *
- * flag:       Flags passed to the main function.
- * interval:   The poll interval to use.
- * max_buffer: The maximum buffer size to use on receive.
+ * flag:           Flags passed to the main function.
+ * interval:       The poll interval to use.
+ * interval_fast:  A poll interval to use when needing the interval to be short.
+ * max_buffer:     The maximum buffer size to use on receive.
+ * active_receive: The number of active receive processes, after initial connection is established.
+ * active_send:    The number of active send processes, after initial connection is established.
  *
  * status_receive: A status used exclusively by the receive thread.
  * status_send:    A status used exclusively by the send thread.
@@ -184,7 +224,10 @@ extern "C" {
   typedef struct {
     uint64_t flag;
     uint64_t interval;
+    uint64_t interval_fast;
     f_number_unsigned_t max_buffer;
+    f_number_unsigned_t active_receive;
+    f_number_unsigned_t active_send;
 
     f_status_t status_receive;
     f_status_t status_send;
@@ -203,7 +246,10 @@ extern "C" {
     { \
       kt_tacocat_main_flag_max_buffer_e, \
       kt_tacocat_interval_poll_d, \
+      kt_tacocat_interval_poll_fast_d, \
       kt_tacocat_max_buffer_d, \
+      0, \
+      0, \
       F_okay, \
       F_okay, \
       F_okay, \
index e58f8c59a506bddd15a0245687198e02a47cfc99..ace18caabffa587ad2dab13e7f9893203368283f 100644 (file)
@@ -16,9 +16,9 @@ extern "C" {
 
     kt_tacocat_process_socket_set_receive(main);
 
-    if (F_status_is_error_not(main->setting.status_receive)) {
+    if (F_status_is_error_not(main->setting.status_receive) && main->setting.receive.used) {
       do {
-        main->setting.status_receive = f_file_poll(main->setting.receive_polls, main->setting.interval);
+        main->setting.status_receive = f_file_poll(main->setting.receive_polls, main->setting.active_receive ? main->setting.interval_fast : main->setting.interval);
 
         if (main->program.signal_received) {
           main->setting.status_receive = F_status_set_error(F_interrupt);
@@ -26,18 +26,54 @@ extern "C" {
           return 0;
         }
 
-        // Skip if status is an error or is F_time_out.
+        // @todo or check if there is any lingering in-progress process not waiting on receive.
+        // @todo when there is a lingering iin-progress process, change the poll timeout to a shorter period to process the lingering process more.
+        // Skip if status from poll is an error or is F_time_out.
         if (main->setting.status_receive == F_okay) {
           for (i = 0; i < main->setting.receive_polls.used; ++i) {
 
             if (main->setting.receive_polls.array[i].fd == -1) continue;
 
             if (main->setting.receive_polls.array[i].revents & (f_poll_read_e)) {
-              kt_tacocat_receive_process(main, &main->setting.receive.array[i]);
+              if (kt_tacocat_receive_process(main, &main->setting.receive.array[i]) == F_done) {
+                if (F_status_is_error(main->setting.receive.array[i].status)) {
+                  // @todo there probably should be a timeout as well as a retry, which should be checked if the poll read condition above is false.
+                  if (++main->setting.receive.array[i].retry >= kt_tacocat_startup_retry_max_d) {
+                    f_file_close(&main->setting.receive.array[i].file);
+
+                    // Keep error bit but set state to done to designate that nothing else is to be done.
+                    main->setting.receive.array[i].status = F_status_set_error(F_done);
+
+                    if (main->setting.receive.array[i].flag) {
+                      main->setting.receive.array[i].flag = 0;
+                      --main->setting.active_receive;
+                    }
+
+                    kt_tacocat_print_error_on_max_retries(&main->program.error, kt_tacocat_receive_s, main->setting.receive.array[i].network, main->setting.receive.array[i].name);
+                  }
+
+                  // @todo if flag is kt_tacocat_socket_flag_receive_control_e, check if error is either F_packet_too_small or F_packet_too_large. This is a non-retrying error.
+                }
+              }
+              else {
+                if (F_status_is_error(main->setting.receive.array[i].status)) {
+                  if (++main->setting.receive.array[i].retry >= kt_tacocat_startup_retry_max_d) {
+                    f_file_close(&main->setting.receive.array[i].file);
+
+                    // Keep error bit but set state to done to designate that nothing else is to be done. @todo review and confirm if this assignment with error bit set is needed anymore or should be changed.
+                    main->setting.receive.array[i].status = F_status_set_error(F_done);
+
+                    if (main->setting.receive.array[i].flag) {
+                      main->setting.receive.array[i].flag = 0;
+                      --main->setting.active_receive;
+                    }
+
+                    kt_tacocat_print_error_on_max_retries(&main->program.error, kt_tacocat_receive_s, main->setting.receive.array[i].network, main->setting.receive.array[i].name);
+                  }
+                }
+              }
 
               main->setting.receive_polls.array[i].revents = 0;
-
-              if (F_status_is_error(main->setting.state.status)) continue;
             }
           } // for
         }
@@ -58,42 +94,62 @@ extern "C" {
 #endif // _di_kt_tacocat_receive_
 
 #ifndef _di_kt_tacocat_receive_process_
-  void kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set) {
+  f_status_t kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set) {
 
-    if (!main || !set) return;
+    if (!main || !set) return F_status_set_error(F_parameter);
 
     // This is a new packet (kt_tacocat_socket_flag_receive_none_e).
     if (!(set->flag)) {
       kt_tacocat_print_message_receive_operation_received(&main->program.message, *set);
 
-      set->flag = kt_tacocat_socket_flag_receive_block_control_e;
-      set->retry = 0;
+      set->abstruses.used = 0;
       set->buffer.used = 0;
+      set->cache.used = 0;
+      set->header.used = 0;
+      set->headers.used = 0;
+      set->objects.used = 0;
+      set->contents.used = 0;
+      set->objects_delimits.used = 0;
+      set->contents_delimits.used = 0;
+      set->comments.used = 0;
+      set->retry = 0;
+      set->size_done = 0;
+      set->size_total = 0;
+      set->file.size_read = set->size_block;
       set->socket.size_read = kt_tacocat_packet_read_d;
+      set->socket.id_data = -1;
+      set->range.start = -1;
+      set->range.stop = 0;
+      set->state.status = F_none;
+      set->status = F_none;
+      set->packet.control = 0;
+      set->packet.size = 0;
+      set->flag = kt_tacocat_socket_flag_receive_control_e;
 
-      set->status = f_file_open(set->name, F_file_mode_all_rw_d, &set->file);
+      ++main->setting.active_receive;
+    }
 
-      if (F_status_is_error(set->status)) {
-        kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_open), kt_tacocat_receive_s, set->network, set->status, set->name, f_file_operation_open_s);
+    if (set->retry >= kt_tacocat_startup_retry_max_d) {
+      f_file_close(&set->file);
 
-        return;
-      }
+      // Keep error bit but set state to done to designate that nothing else is to be done.
+      set->status = F_status_set_error(F_done);
+      set->flag = 0;
+      --main->setting.active_receive;
+
+      kt_tacocat_print_error_on_max_retries(&main->program.error, kt_tacocat_receive_s, set->network, set->name);
+
+      return F_done;
     }
 
     // Load the header of the new packet.
-    if (set->flag & kt_tacocat_socket_flag_receive_block_control_e) {
+    if (set->flag & kt_tacocat_socket_flag_receive_control_e) {
       kt_tacocat_receive_process_control(main, set);
 
-      if (set->buffer.used < kt_tacocat_packet_peek_d) {
-        f_file_close_id(&set->socket.id_data);
+      if (set->buffer.used < kt_tacocat_packet_peek_d || F_status_is_error(set->status)) {
+        --main->setting.active_receive;
 
-        return;
-      }
-
-      if (set->buffer.used < kt_tacocat_packet_peek_d) {
-        f_file_close_id(&set->socket.id_data);
-
-        return;
+        return F_done;
       }
 
       // Reset the buffer to allow for reusing and writing to the file in blocks.
@@ -103,51 +159,101 @@ extern "C" {
       // Make sure the buffer is large enough for payload processing block reads.
       set->status = f_memory_array_increase_by(set->socket.size_read, sizeof(f_char_t), (void **) &set->buffer.string, &set->buffer.used, &set->buffer.size);
       macro_kt_receive_process_handle_error_exit_1(main, f_memory_array_increase_by, set->network, set->status, set->name, set->flag, &set->socket.id_data);
+
+      set->retry = 0;
+      set->flag = kt_tacocat_socket_flag_receive_packet_e;
     }
 
-    if (set->flag & kt_tacocat_socket_flag_receive_block_payload_e) {
+    if (set->flag & kt_tacocat_socket_flag_receive_packet_e) {
       size_t length_read = 0;
 
       set->status = f_socket_read_stream(&set->socket, 0, (void *) set->buffer.string, &length_read);
       macro_kt_receive_process_handle_error_exit_1(main, f_socket_read_stream, set->network, set->status, set->name, set->flag, &set->socket.id_data);
 
       if (length_read) {
-        set->buffer.used = length_read;
+        set->retry = 0;
+        set->buffer.used += length_read;
+        set->flag = kt_tacocat_socket_flag_receive_check_e;
+      }
+      else {
+        ++set->retry;
+      }
+    }
 
-        set->status = f_file_write(set->file, set->buffer, 0);
+    if (set->flag & kt_tacocat_socket_flag_receive_check_e) {
+       // @todo after payload, a headers, and a save step. The check step will be the FSS processing check and if the proper step is reached, then set another flag to designate that the payload start has been found, process the headers (another flag),
+       set->range.start = 0;
+       set->range.stop = set->buffer.used - 1;
+       set->state.status = F_none;
 
-        // Keep going on error, but in the future more advanced error handling/recovery is needed to make this more robust.
-        if (F_status_is_error(set->status)) {
-          kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_write), kt_tacocat_receive_s, set->network, set->status, set->name, f_file_operation_write_s);
-        }
+       fll_fss_payload_read(set->buffer, &set->range, &set->objects, &set->contents, &set->objects_delimits, &set->contents_delimits, &set->comments, &set->state);
 
-        // Reset buffer used and increment counter.
-        set->packet.payload.stop += set->buffer.used;
-        set->buffer.used = 0;
+       // @todo before writing the buffer to the file, attempt to read the header, keep appending to the current buffer until in memory matches "payload:".
+       // @todo if the entire header is not available, then set flag back to kt_tacocat_socket_flag_receive_packet_e.
+      //extern void fll_fss_payload_read(const f_string_static_t buffer, f_range_t * const range, f_ranges_t * const objects, f_rangess_t * const contents, f_number_unsigneds_t * const objects_delimits, f_number_unsigneds_t * const contents_delimits, f_ranges_t * const comments, f_state_t * const state);
+
+      /*if (set->packet.payload.stop + 1 < set->packet.size) {
+        set->flag = kt_tacocat_socket_flag_receive_packet_e;
+
+        return F_data_not;
+      }*/
 
-        f_file_close_id(&set->socket.id_data);
+      set->flag = kt_tacocat_socket_flag_receive_write_e;
+    }
+
+    if (set->flag & kt_tacocat_socket_flag_receive_write_e) {
+      set->status = f_file_open(set->name, F_file_mode_all_rw_d, &set->file);
 
-        if (set->packet.payload.stop + 1 < set->packet.size) return;
+      if (F_status_is_error(set->status)) {
+        kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_open), kt_tacocat_receive_s, set->network, set->status, set->name, f_file_operation_open_s);
+
+        return F_done_not; // @todo consider sending a file error to caller. This should not infinitely attempt to open on failure.
       }
+
+      // @todo write only the Payload.
+      set->status = f_file_write(set->file, set->buffer, 0);
+
+      // Keep going on error, but in the future more advanced error handling/recovery is needed to make this more robust.
+      if (F_status_is_error(set->status)) {
+        f_file_close(&set->file);
+
+        kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_write), kt_tacocat_receive_s, set->network, set->status, set->name, f_file_operation_write_s);
+      }
+
+      // Reset buffer used and increment counter.
+      set->packet.payload.stop += set->buffer.used;
+      set->buffer.used = 0;
+
+      f_file_close(&set->file);
+
+      set->flag = kt_tacocat_socket_flag_receive_done_e;
     }
 
     // Done processing the Packet.
-    kt_tacocat_print_message_receive_operation_complete(&main->program.message, *set);
+    if (set->flag & kt_tacocat_socket_flag_receive_done_e) {
+      kt_tacocat_print_message_receive_operation_complete(&main->program.message, *set);
 
-    f_file_close_id(&set->socket.id_data);
-    f_file_close(&set->file);
-    set->flag = 0;
+      f_file_close(&set->file);
 
-    if (set->buffer.size > kt_tacocat_max_maintain_d) {
-      set->buffer.used = 0;
+      set->flag = 0;
+      set->status = F_okay;
+      --main->setting.active_receive;
 
-      set->status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &set->buffer.string, &set->buffer.used, &set->buffer.size);
+      if (set->buffer.size > kt_tacocat_max_maintain_d) {
+        set->buffer.used = 0;
 
-      // Report the resize error but do not fail.
-      if (F_status_is_error(set->status)) {
-        kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_resize), kt_tacocat_receive_s, set->network, set->status, set->name);
+        set->status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &set->buffer.string, &set->buffer.used, &set->buffer.size);
+
+        // Report the resize error but do not fail.
+        if (F_status_is_error(set->status)) {
+          kt_tacocat_print_error_on(&main->program.error, macro_kt_tacocat_f(f_memory_array_resize), kt_tacocat_receive_s, set->network, set->status, set->name);
+        }
       }
+
+      return F_done;
     }
+
+    return F_done_not;
   }
 #endif // _di_kt_tacocat_receive_process_
 
@@ -177,7 +283,7 @@ extern "C" {
 
     set->buffer.used += length_read;
 
-    // Continue if the packet header is not fully ready.
+    // Try peeking again if the packet header is not fully ready.
     if (set->buffer.used < kt_tacocat_packet_peek_d) {
 
       // Peek ahead to see if the client has closed the connection (all the intended data should have been transmitted).
@@ -195,11 +301,6 @@ extern "C" {
         if (!length_read) {
           kt_tacocat_print_error_on_packet_too_small(&main->program.error, kt_tacocat_receive_s, set->network, kt_tacocat_packet_peek_d, set->buffer.used);
 
-          set->buffer.used = 0;
-          set->flag = 0;
-          set->packet.control = 0;
-          set->packet.size = 0;
-          set->retry = 0;
           set->status = F_status_set_error(F_packet_too_small);
 
           return;
@@ -210,11 +311,7 @@ extern "C" {
         // Connection is closed when length is 0.
         kt_tacocat_print_warning_on_client_closed(&main->program.warning, kt_tacocat_receive_s, set->network);
 
-        set->buffer.used = 0;
         set->flag = 0;
-        set->packet.control = 0;
-        set->packet.size = 0;
-        set->retry = 0;
         set->status = F_status_set_error(F_packet_too_small);
 
         return;
@@ -241,9 +338,6 @@ extern "C" {
       }
 
       set->flag = 0;
-      set->packet.control = 0;
-      set->packet.size = 0;
-      set->retry = 0;
 
       if (set->status == F_packet_too_small || set->packet.size < kt_tacocat_packet_minimum_d) {
         set->status = F_status_set_error(F_packet_too_small);
@@ -257,8 +351,7 @@ extern "C" {
       return;
     }
 
-    set->flag |= kt_tacocat_socket_flag_receive_block_payload_e;
-    set->flag -= kt_tacocat_socket_flag_receive_block_control_e;
+    set->flag = kt_tacocat_socket_flag_receive_packet_e;
 
     // The payload range "stop" is used to represent the total amount of bytes processed so far (uncluding the header).
     set->packet.payload.start = 0;
index 8fd9aa699003a5eac1b97d7e752bb51ec27dddc0..a04d60fc72e4f83989add599458a01afa4e4f19e 100644 (file)
@@ -20,9 +20,12 @@ extern "C" {
  *
  *   Must be of type kt_tacocat_main_t.
  *
- *   This alters main.setting.state.status:
+ *   This does not alter main.setting.state.status, except on interrupt signal.
+ *
+ *   This alters main.setting.status_receive:
  *     F_okay on success.
- *     F_child on child process exiting.
+ *
+ *     F_interrupt (with error bit set) on interrupt received.
  *
  * @return
  *   0, always.
@@ -37,19 +40,21 @@ extern "C" {
  * @param main
  *   The main program and settings data.
  *
- *   This alters main.setting.state.status:
+ *   This does not alter main.setting.state.status, except on interrupt signal.
+ * @param set
+ *   The socket set to process.
+ *   Must not be NULL.
+ *
+ *   This alters set.status:
  *     F_okay on success.
  *
  *     F_packet_too_large (with error bit) on total packet size is too large.
  *     F_payload_too_large (with error bit) on total payload size is too large.
- * @param set
- *   The socket set to process.
- *   Must not be NULL.
  *
  * @see f_socket_read_stream()
  */
 #ifndef _di_kt_tacocat_receive_process_
-  extern void kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set);
+  extern f_status_t kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set);
 #endif // _di_kt_tacocat_receive_process_
 
 /**
@@ -58,14 +63,16 @@ extern "C" {
  * @param main
  *   The main program and settings data.
  *
- *   This alters main.setting.state.status:
+ *   This does not alter main.setting.state.status, except on interrupt signal.
+ * @param set
+ *   The socket set to process.
+ *   Must not be NULL.
+ *
+ *   This alters set.status:
  *     F_okay on success.
  *
  *     F_packet_too_large (with error bit) on total packet size is too large.
  *     F_payload_too_large (with error bit) on total payload size is too large.
- * @param set
- *   The socket set to process.
- *   Must not be NULL.
  *
  * @see f_socket_read_stream()
  */
index fac69bf1f54abbc4c1d4420ec84665db0b0e1922..6e7643b8849fa81308479fc73aa121d3539c68ab 100644 (file)
@@ -17,6 +17,7 @@ extern "C" {
 
     kt_tacocat_process_socket_set_send(main);
 
+    // @todo this needs to integrate send_polls, for checking responses to sent packets.
     if (F_status_is_error_not(main->setting.status_send) && main->setting.send.used) {
       do {
         ready = F_okay;
@@ -35,7 +36,6 @@ extern "C" {
             }
           }
           else {
-            // @todo the kt_tacocat_receive_process() and kt_tacocat_send_process() have different return designs, figure out which design to use and be consistent.
             // @todo in all cases error or success, when done be sure set->file is closed.
             // @todo on error during partial transfer either attempt to resend, attempt to send failure packet, or abandon.
             if (kt_tacocat_send_process(main, &main->setting.send.array[i]) == F_done) {
@@ -79,11 +79,27 @@ extern "C" {
     if (!set->flag) {
       set->abstruses.used = 0;
       set->buffer.used = 0;
+      set->cache.used = 0;
       set->header.used = 0;
       set->headers.used = 0;
+      set->objects.used = 0;
+      set->contents.used = 0;
+      set->objects_delimits.used = 0;
+      set->contents_delimits.used = 0;
+      set->comments.used = 0;
+      set->retry = 0;
       set->size_done = 0;
       set->size_total = 0;
       set->file.size_read = set->size_block;
+      set->socket.size_read = kt_tacocat_packet_read_d;
+      set->range.start = -1;
+      set->range.stop = 0;
+      set->packet.control = 0;
+      set->packet.size = 0;
+      set->status = F_none;
+
+      // For writes, the id_data is the same as the id.
+      set->socket.id_data = set->socket.id;
 
       // Initialize the default file payload.
       set->status = f_memory_array_increase_by(kt_tacocat_packet_headers_d, sizeof(f_string_map_t), (void **) &set->headers.array, &set->headers.used, &set->headers.size);
@@ -137,14 +153,6 @@ extern "C" {
 
       set->abstruses.used = 7;
 
-      set->status = f_file_open(set->name, F_file_mode_all_r_d, &set->file);
-
-      if (F_status_is_error(set->status)) {
-        kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_open), kt_tacocat_send_s, set->network, set->status, set->name, f_file_operation_open_s);
-
-        return F_done_not;
-      }
-
       set->flag = kt_tacocat_socket_flag_send_size_e;
     }
 
@@ -152,17 +160,27 @@ extern "C" {
       f_file_close(&set->file);
       f_socket_disconnect(&set->socket, f_socket_close_fast_e);
 
+      set->flag = 0;
+      set->socket.id_data = -1;
+
       // Keep error bit but set state to done to designate that nothing else is to be done.
       set->status = F_status_set_error(F_done);
-      set->socket.id = -1;
-      set->socket.id_data = -1;
 
       kt_tacocat_print_error_on_max_retries(&main->program.error, kt_tacocat_send_s, set->network, set->name);
 
       return F_done;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_size_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_size_e) {
+      if (set->file.id == -1) {
+        set->status = f_file_open(set->name, F_file_mode_all_r_d, &set->file);
+
+        if (F_status_is_error(set->status)) {
+          kt_tacocat_print_error_on_file_receive(&main->program.error, macro_kt_tacocat_f(f_file_open), kt_tacocat_send_s, set->network, set->status, set->name, f_file_operation_open_s);
+
+          return F_done_not;
+        }
+      }
 
       // Total is used here to explicitly pass a pointer of off_t rather than a pointer of size_t cast to an off_t.
       off_t total = 0;
@@ -208,7 +226,7 @@ extern "C" {
       set->flag = kt_tacocat_socket_flag_send_build_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_build_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_build_e) {
       f_state_t state_local = main->setting.state;
       state_local.data = &set->write_state;
 
@@ -218,7 +236,7 @@ extern "C" {
       set->flag = kt_tacocat_socket_flag_send_header_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_header_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_header_e) {
       // @todo this needs to check the current status, accodingly (for when multiple blocks are being sent).
 
       // Reserve the FSS Packet header, which will be calculated just before sending.
@@ -270,7 +288,7 @@ extern "C" {
       set->flag = kt_tacocat_socket_flag_send_file_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_file_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_file_e) {
       const f_number_unsigned_t size_header = set->buffer.used;
 
       set->status = f_string_dynamic_append(f_fss_payload_object_payload_s, &set->buffer);
@@ -295,10 +313,11 @@ extern "C" {
       set->status = f_string_dynamic_terminate_after(&set->buffer);
       macro_kt_send_process_handle_error_exit_1(main, f_string_dynamic_terminate_after, kt_tacocat_send_combine_s, set->network, set->status, set->name, set->flag);
 
+      set->retry = 0;
       set->flag = kt_tacocat_socket_flag_send_check_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_check_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_check_e) {
       // @todo this needs to check if the size read has changed and then re-build the header (swap the buffer read block into the cache then rebuild the header with th new size).
       //if (set->abstruses.array[2].value.is.a_unsigned < set->file.size_read) {
       //}
@@ -306,7 +325,7 @@ extern "C" {
       set->flag = kt_tacocat_socket_flag_send_encode_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_encode_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_encode_e) {
       const f_number_unsigned_t original = set->buffer.used;
 
       set->buffer.used = 0;
@@ -322,7 +341,7 @@ extern "C" {
       set->flag = kt_tacocat_socket_flag_send_packet_e;
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_packet_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_packet_e) {
       size_t written = 0;
 
       {
@@ -353,7 +372,7 @@ extern "C" {
       }
     }
 
-    if (set->flag == kt_tacocat_socket_flag_send_done_e) {
+    if (set->flag & kt_tacocat_socket_flag_send_done_e) {
       set->status = f_file_close(&set->file);
 
       if (F_status_is_error(set->status)) {
@@ -366,11 +385,7 @@ extern "C" {
         kt_tacocat_print_warning_on_file(&main->program.warning, macro_kt_tacocat_f(f_socket_disconnect), kt_tacocat_send_done_s, set->network, set->status, set->name, f_file_operation_close_s);
       }
 
-      f_file_close_id(&set->socket.id_data);
-
       set->flag = 0;
-      set->size_done = 0;
-      set->socket.id = -1;
       set->socket.id_data = -1;
       set->status = F_okay;
 
index 42d5a2f974d6d40526d995532c17b2817d65bbe2..d213b6658e887450426f275eb5f47ca38530a0c3 100644 (file)
@@ -20,9 +20,12 @@ extern "C" {
  *
  *   Must be of type kt_tacocat_main_t.
  *
- *   This alters main.setting.state.status:
+ *   This does not alter main.setting.state.status, except on interrupt signal.
+ *
+ *   This alters main.setting.status_send:
  *     F_okay on success.
- *     F_child on child process exiting.
+ *
+ *     F_interrupt (with error bit set) on interrupt received.
  *
  * @return
  *   0, always.
@@ -40,17 +43,17 @@ extern "C" {
  * @param main
  *   The main program and settings data.
  *
- *   This alters main.setting.state.status:
+ *   This does not alter main.setting.state.status, except on interrupt signal.
+ * @param set
+ *   The socket set to process.
+ *   Must not be NULL.
+ *
+ *   This alters set.status:
  *     F_okay on success.
  *
  *     F_packet_too_large (with error bit) on total packet size is too large.
  *     F_payload_too_large (with error bit) on total payload size is too large.
  *     F_too_large (with error bit) on file too large.
- * @param set
- *   The socket set to process.
- *   Must not be NULL.
- *
- * @todo Processing and logic around the return status needs to reviewed and updated.
  *
  * @see f_socket_read_stream()
  */
index 6b832700d6bf07fa2f8799763f7708db2cc343cb..7cf37c4c4370e3dd4cdcae1cde8ddf67f5080096 100644 (file)
@@ -47,6 +47,8 @@
 
 // FLL-2 includes.
 #include <fll/level_2/error.h>
+#include <fll/level_2/fss.h>
+#include <fll/level_2/fss/payload.h>
 #include <fll/level_2/print.h>
 #include <fll/level_2/program.h>