From e8ff49ad6aa7843077c69dccfa19e263388c6ddd Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Mon, 4 Sep 2023 21:25:56 -0500 Subject: [PATCH] Progress: Further work in TacocaT, getting the "receive" working and writing to a file. This gets the receive mostly working. There may be a few fixme or todo comments to address. I decided to not bother with some of the more complex handling of problems to get this program out the door. To test this, I used the FLL-0.6 branch version of the file specifications/fss-000f.txt. I then created the Packet header using the bash script like this: printf '\x00\x00\x00\x15\x78' > test.binary cat 0.6/specifications/fss-000f.txt >> test.binary The resulting binary file size is 0x1578 bytes (5496 bytes) and this can be confirmed via the wc command: wc test.binary I can then start the TacocaT program in a new terminal like this: tacocat -r 127.0.0.1:12345 test.out +V In a different terminal, I use netcat to test (because the "send" support is not yet written). cat test.binary | netcat 127.0.0.1 12345 Use control-c to terminate TacocaT. I can then confirm that the file has been created successfully via a md5sum check. md5sum test.out 0.6/specifications/fss-000f.txt The checksums should match, and in my testing they do match. --- sources/c/tacocat/main/common.c | 44 +++-- sources/c/tacocat/main/common/define.h | 34 ++-- sources/c/tacocat/main/common/enumeration.h | 10 +- sources/c/tacocat/main/common/print.c | 3 +- sources/c/tacocat/main/common/print.h | 3 +- sources/c/tacocat/main/common/type.c | 3 +- sources/c/tacocat/main/common/type.h | 12 +- sources/c/tacocat/main/print/error.c | 32 +++- sources/c/tacocat/main/print/error.h | 40 ++++- sources/c/tacocat/main/process.c | 11 +- sources/c/tacocat/main/receive.c | 242 +++++++++++++++------------- sources/c/tacocat/main/receive.h | 22 ++- 12 files changed, 270 insertions(+), 186 deletions(-) diff --git a/sources/c/tacocat/main/common.c b/sources/c/tacocat/main/common.c index a471c97..ec75ac0 100644 --- a/sources/c/tacocat/main/common.c +++ b/sources/c/tacocat/main/common.c @@ -310,42 +310,39 @@ 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]->networks.array[j].used = 0; sets[i]->buffers.array[j].used = 0; - sets[i]->packets.array[j].control.start = 1; - sets[i]->packets.array[j].control.stop = 0; - sets[i]->packets.array[j].size.start = 1; - sets[i]->packets.array[j].size.stop = 0; + sets[i]->packets.array[j].control = 0; + sets[i]->packets.array[j].size = 0; sets[i]->packets.array[j].payload.start = 1; sets[i]->packets.array[j].payload.stop = 0; if (main->program.parameters.arguments.array[index].used) { if (f_path_is_absolute(main->program.parameters.arguments.array[index]) == F_true || f_path_is_relative_current(main->program.parameters.arguments.array[index]) == F_true) { - main->setting.state.status = f_memory_array_increase_by(main->program.parameters.arguments.array[index].used + 2, sizeof(f_char_t), (void **) &sets[i]->names.array[j].string, &sets[i]->names.array[j].used, &sets[i]->names.array[j].size); + main->setting.state.status = f_memory_array_increase_by(main->program.parameters.arguments.array[index].used + 2, sizeof(f_char_t), (void **) &sets[i]->networks.array[j].string, &sets[i]->networks.array[j].used, &sets[i]->networks.array[j].size); macro_setting_load_handle_send_receive_error_continue_2(f_memory_array_increase_by); - main->setting.state.status = f_string_dynamic_append_nulless(main->program.parameters.arguments.array[index], &sets[i]->names.array[j]); + main->setting.state.status = f_string_dynamic_append_nulless(main->program.parameters.arguments.array[index], &sets[i]->networks.array[j]); macro_setting_load_handle_send_receive_error_continue_2(f_string_dynamic_append_nulless); // Designate this as a socket file by appending after the terminating NULL, past the used length. - sets[i]->names.array[j].string[sets[i]->names.array[j].used] = 0; - sets[i]->names.array[j].string[sets[i]->names.array[j].used + 1] = f_string_ascii_slash_forward_s.string[0]; + sets[i]->networks.array[j].string[sets[i]->networks.array[j].used] = 0; + sets[i]->networks.array[j].string[sets[i]->networks.array[j].used + 1] = f_string_ascii_slash_forward_s.string[0]; if (is_receive[i]) { - main->setting.state.status = f_file_exists(sets[i]->names.array[j], F_true); + main->setting.state.status = f_file_exists(sets[i]->networks.array[j], F_true); macro_setting_load_handle_send_receive_error_continue_2(f_string_dynamic_append_nulless); } - sets[i]->names.array[j].string[sets[i]->names.array[j].used] = 0; + sets[i]->networks.array[j].string[sets[i]->networks.array[j].used] = 0; sets[i]->sockets.array[j].domain = f_socket_protocol_family_local_e; sets[i]->sockets.array[j].protocol = f_socket_protocol_tcp_e; sets[i]->sockets.array[j].type = f_socket_type_stream_e; - sets[i]->sockets.array[j].name = sets[i]->names.array[j]; + sets[i]->sockets.array[j].name = sets[i]->networks.array[j]; } else if (main->setting.flag & kt_tacocat_main_flag_resolve_classic_e) { memset(&host, 0, sizeof(struct hostent)); @@ -404,7 +401,7 @@ extern "C" { } if (host.h_addrtype) { - main->setting.state.status = f_string_dynamic_append(address, &sets[i]->names.array[j]); + main->setting.state.status = f_string_dynamic_append(address, &sets[i]->networks.array[j]); macro_setting_load_handle_send_receive_error_continue_2(f_string_dynamic_append); } @@ -432,7 +429,7 @@ extern "C" { continue; } - main->setting.state.status = f_memory_array_increase_by(INET6_ADDRSTRLEN + 1, sizeof(f_char_t), (void **) &sets[i]->names.array[j].string, &sets[i]->names.array[j].used, &sets[i]->names.array[j].size); + main->setting.state.status = f_memory_array_increase_by(INET6_ADDRSTRLEN + 1, sizeof(f_char_t), (void **) &sets[i]->networks.array[j].string, &sets[i]->networks.array[j].used, &sets[i]->networks.array[j].size); macro_setting_load_handle_send_receive_error_continue_2(f_memory_array_increase_by); @@ -450,7 +447,7 @@ extern "C" { k = 0; } - main->setting.state.status = f_memory_array_increase_by(INET6_ADDRSTRLEN + 1, sizeof(f_char_t), (void **) &sets[i]->names.array[j].string, &sets[i]->names.array[j].used, &sets[i]->names.array[j].size); + main->setting.state.status = f_memory_array_increase_by(INET6_ADDRSTRLEN + 1, sizeof(f_char_t), (void **) &sets[i]->networks.array[j].string, &sets[i]->networks.array[j].used, &sets[i]->networks.array[j].size); macro_setting_load_handle_send_receive_error_continue_2(f_memory_array_increase_by); @@ -463,7 +460,7 @@ extern "C" { family.address.v6 = *((struct in6_addr *) host.h_addr_list[k]); } - main->setting.state.status = f_network_to_ip_string(family, &sets[i]->names.array[j]); + main->setting.state.status = f_network_to_ip_string(family, &sets[i]->networks.array[j]); if (main->setting.state.status == F_data_not || !host.h_addr_list || !host.h_addr_list[0]) { main->setting.state.status = F_status_set_error(F_parameter); @@ -482,7 +479,7 @@ extern "C" { continue; } - sets[i]->names.array[j].string[sets[i]->names.array[j].used] = 0; + sets[i]->networks.array[j].string[sets[i]->networks.array[j].used] = 0; } sets[i]->sockets.array[j].protocol = f_socket_protocol_tcp_e; @@ -506,7 +503,7 @@ extern "C" { ++sets[i]->buffers.used; ++sets[i]->files.used; ++sets[i]->flags.used; - ++sets[i]->names.used; + ++sets[i]->networks.used; ++sets[i]->packets.used; ++sets[i]->polls.used; ++sets[i]->sockets.used; @@ -603,13 +600,12 @@ extern "C" { set->buffers.used = 0; set->files.used = 0; set->flags.used = 0; - set->names.used = 0; + set->networks.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); @@ -636,7 +632,7 @@ extern "C" { } 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); + main->setting.state.status = f_memory_array_increase_by(total, sizeof(f_string_dynamic_t), (void **) &set->networks.array, &set->networks.used, &set->networks.size); } if (F_status_is_error_not(main->setting.state.status)) { @@ -652,10 +648,6 @@ 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; } } diff --git a/sources/c/tacocat/main/common/define.h b/sources/c/tacocat/main/common/define.h index 232f8ae..6087f33 100644 --- a/sources/c/tacocat/main/common/define.h +++ b/sources/c/tacocat/main/common/define.h @@ -95,12 +95,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 processing within flag kt_tacocat_socket_flag_block_begin_e. + * Intended to be used for handling an error during the receive process while not processing within flag kt_tacocat_socket_flag_block_control_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. + * 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_block_control_e. */ #ifndef _di_kt_tacocat_macros_d_ #define macro_setting_load_print_first() \ @@ -151,7 +150,6 @@ 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); \ @@ -160,26 +158,20 @@ extern "C" { f_file_close_id(id_data); \ } \ \ - *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; \ } - // @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; \ - } + #define macro_kt_receive_process_begin_handle_error_exit_1(main, method, name, status, flag) \ + 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); \ + \ + *flag -= kt_tacocat_socket_flag_block_control_e; \ + \ + return; \ + } #endif // _di_kt_tacocat_macro_d_ #ifdef __cplusplus diff --git a/sources/c/tacocat/main/common/enumeration.h b/sources/c/tacocat/main/common/enumeration.h index eee8aa6..b54688e 100644 --- a/sources/c/tacocat/main/common/enumeration.h +++ b/sources/c/tacocat/main/common/enumeration.h @@ -131,16 +131,14 @@ 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. + * - block_control: Reading and processing the Control block and Size block. + * - block_payload: Reading and processing the Payload block. */ #ifndef _di_kt_tacocat_socket_flag_e_ enum { kt_tacocat_socket_flag_none_e = 0x0, - kt_tacocat_socket_flag_block_begin_e = 0x1, - kt_tacocat_socket_flag_block_control_e = 0x2, - kt_tacocat_socket_flag_block_payload_e = 0x4, + kt_tacocat_socket_flag_block_control_e = 0x1, + kt_tacocat_socket_flag_block_payload_e = 0x2, }; // enum #endif // _di_kt_tacocat_socket_flag_e_ diff --git a/sources/c/tacocat/main/common/print.c b/sources/c/tacocat/main/common/print.c index 6553719..e928c47 100644 --- a/sources/c/tacocat/main/common/print.c +++ b/sources/c/tacocat/main/common/print.c @@ -9,7 +9,8 @@ extern "C" { "f_console_parameter_process", "f_file_close_id", "f_file_open", - "f_fss_simple_packet_identify", + "f_file_write", + "f_fss_simple_packet_extract_range", "f_memory_array_increase_by", "f_memory_array_resize", "f_network_from_ip_name", diff --git a/sources/c/tacocat/main/common/print.h b/sources/c/tacocat/main/common/print.h index b1a4e30..f4eea47 100644 --- a/sources/c/tacocat/main/common/print.h +++ b/sources/c/tacocat/main/common/print.h @@ -42,7 +42,8 @@ extern "C" { 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_file_write_e, + kt_tacocat_f_f_fss_simple_packet_extract_range_e, kt_tacocat_f_f_memory_array_increase_by_e, kt_tacocat_f_f_memory_array_resize_e, kt_tacocat_f_f_network_from_ip_name_e, diff --git a/sources/c/tacocat/main/common/type.c b/sources/c/tacocat/main/common/type.c index c20ef66..a0e7a33 100644 --- a/sources/c/tacocat/main/common/type.c +++ b/sources/c/tacocat/main/common/type.c @@ -43,12 +43,11 @@ extern "C" { 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); f_memory_array_resize(0, sizeof(f_status_t), (void **) &sets[i]->statuss.array, &sets[i]->statuss.used, &sets[i]->statuss.size); - f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &sets[i]->names.array, &sets[i]->names.used, &sets[i]->names.size, &f_string_dynamics_delete_callback); + f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &sets[i]->networks.array, &sets[i]->networks.used, &sets[i]->networks.size, &f_string_dynamics_delete_callback); f_memory_arrays_resize(0, sizeof(f_string_dynamic_t), (void **) &sets[i]->buffers.array, &sets[i]->buffers.used, &sets[i]->buffers.size, &f_string_dynamics_delete_callback); f_memory_array_resize(0, sizeof(f_fss_simple_packet_range_t), (void **) &sets[i]->packets.array, &sets[i]->packets.used, &sets[i]->packets.size); } // for diff --git a/sources/c/tacocat/main/common/type.h b/sources/c/tacocat/main/common/type.h index fe8da64..418e230 100644 --- a/sources/c/tacocat/main/common/type.h +++ b/sources/c/tacocat/main/common/type.h @@ -24,15 +24,14 @@ extern "C" { * * 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. * statuss: An array of statuses for each socket. * - * names: An array of names for each socket. - * buffers: An array of buffers for sending or receiving data between clients for each socket. - * packets: An array of simple packet ranges representing the parts of the packet for each socket for use during processing. + * networks: An array of networks for each socket. + * buffers: An array of buffers for sending or receiving data between clients for each socket. + * packets: An array of simple packet ranges representing the parts of the packet for each socket for use during processing. */ #ifndef _di_kt_tacocat_socket_set_t_ typedef struct { @@ -40,13 +39,12 @@ extern "C" { f_uint16s_t flags; f_uint16s_t retrys; - f_uint32s_t totals; f_files_t files; f_polls_t polls; f_sockets_t sockets; f_statuss_t statuss; - f_string_dynamics_t names; + f_string_dynamics_t networks; f_string_dynamics_t buffers; f_fss_simple_packet_ranges_t packets; } kt_tacocat_socket_set_t; @@ -56,7 +54,6 @@ 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, \ @@ -71,7 +68,6 @@ 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, \ diff --git a/sources/c/tacocat/main/print/error.c b/sources/c/tacocat/main/print/error.c index a759af7..9f51903 100644 --- a/sources/c/tacocat/main/print/error.c +++ b/sources/c/tacocat/main/print/error.c @@ -63,7 +63,7 @@ extern "C" { #endif // _di_kt_tacocat_print_error_ #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) { + 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, 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; @@ -74,7 +74,11 @@ extern "C" { fl_print_format(f_string_format_Q_single_s.string, print->to, print->set->notable, on, print->set->notable); fl_print_format(" %[buffer 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("%['.%]%r", print->to, print->set->error, print->set->error, f_string_eol_s); + fl_print_format("%[', the maximum size is%] ", 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("%[, and the provided size is%] ", print->to, print->set->error, print->set->error); + fl_print_format("%[%ul%]", print->to, print->set->notable, size_got, 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); f_file_stream_unlock(print->to); @@ -102,6 +106,28 @@ extern "C" { } #endif // _di_kt_tacocat_print_error_on_busy_ +#ifndef _di_kt_tacocat_print_error_on_file_ + f_status_t kt_tacocat_print_error_on_file(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, const f_string_static_t name) { + + if (!print || !print->custom) 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("%[' failed to write to file '%]", 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, name, print->set->notable); + fl_print_format("%['.%]%r", print->to, print->set->error, print->set->error, f_string_eol_s); + + f_file_stream_unlock(print->to); + + fll_error_file_print(print, F_status_set_fine(((kt_tacocat_main_t *) print->custom)->setting.state.status), function, F_true, name, f_file_operation_write_s, fll_error_file_type_file_e); + } +#endif // _di_kt_tacocat_print_error_on_file_ + #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) { @@ -183,7 +209,7 @@ extern "C" { fl_print_format("%[%QThe lengths of all%] ", 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, name, print->set->notable); fl_print_format(" %[arrays do not have the same length, name array length is '%]", print->to, print->set->error, print->set->error, f_string_eol_s); - fl_print_format("%[%ul%]", print->to, print->set->notable, set.names.used, print->set->notable); + fl_print_format("%[%ul%]", print->to, print->set->notable, set.networks.used, print->set->notable); fl_print_format("%', the buffer array length is '%]", print->to, print->set->error, print->set->error, f_string_eol_s); fl_print_format("%[%ul%]", print->to, print->set->notable, set.buffers.used, print->set->notable); fl_print_format("%', the file array length is '%]", print->to, print->set->error, print->set->error, f_string_eol_s); diff --git a/sources/c/tacocat/main/print/error.h b/sources/c/tacocat/main/print/error.h index 0800437..9742480 100644 --- a/sources/c/tacocat/main/print/error.h +++ b/sources/c/tacocat/main/print/error.h @@ -135,6 +135,10 @@ extern "C" { * 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_max + * The maximum buffer size. + * @param size_got + * The provided buffer size. * * @return * F_okay on success. @@ -145,7 +149,7 @@ extern "C" { * @see fll_error_file_print() */ #ifndef _di_kt_tacocat_print_error_on_buffer_too_large_ - 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); + 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, const f_number_unsigned_t size_expect, const f_number_unsigned_t size_got); #endif // _di_kt_tacocat_print_error_on_buffer_too_large_ /** @@ -171,6 +175,36 @@ extern "C" { #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 regarding the writing the network data to a file. + * + * @param print + * The output structure to print to. + * + * This does not alter print.custom.setting.state.status. + * @param function + * The name of the function where the error happened. + * Set to 0 to disable. + * @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 status + * The status code representing the error. + * @param name + * The name of the file or directory. + * + * @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_file_ + extern f_status_t kt_tacocat_print_error_on_file(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, const f_string_static_t name); +#endif // _di_kt_tacocat_print_error_on_file_ /** * Print network-related error message for when the connection is busy. @@ -184,9 +218,9 @@ extern "C" { * @param network * The name of the network in which the error is related. * @param size_expect - * The expected packet size. + * The expected buffer size. * @param size_got - * The packet size that is received. + * The provided buffer size. * * @return * F_okay on success. diff --git a/sources/c/tacocat/main/process.c b/sources/c/tacocat/main/process.c index 68ab129..ef28e39 100644 --- a/sources/c/tacocat/main/process.c +++ b/sources/c/tacocat/main/process.c @@ -127,7 +127,7 @@ extern "C" { return F_status_set_error(F_parameter); } - if (set.sockets.used != set.files.used || set.sockets.used != set.files.used || set.sockets.used != set.statuss.used || set.sockets.used != set.names.used || set.sockets.used != set.buffers.used) { + if (set.sockets.used != set.files.used || set.sockets.used != set.files.used || set.sockets.used != set.statuss.used || set.sockets.used != set.networks.used || set.sockets.used != set.buffers.used) { *status = F_status_set_error(F_parameter); kt_tacocat_print_error_setting_socket_lengths_must_match(&main->program.error, parameter, set); @@ -151,6 +151,9 @@ extern "C" { if (kt_tacocat_signal_check(main)) return; if (F_status_is_error(main->setting.receive.statuss.array[i])) continue; + main->setting.receive.sockets.array[i].id = -1; + main->setting.receive.sockets.array[i].id_data = -1; + main->setting.receive.statuss.array[i] = f_socket_create(&main->setting.receive.sockets.array[i]); if (F_status_is_error(main->setting.receive.statuss.array[i])) { @@ -190,14 +193,14 @@ extern "C" { 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); + kt_tacocat_print_error_socket_protocol_unsupported(&main->program.error, main->setting.receive.networks.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); + kt_tacocat_print_warning_on_busy(&main->program.warning, kt_tacocat_receive_s, main->setting.receive.networks.array[i], main->setting.receive.retrys.array[i] + 1); struct timespec time = { 0 }; @@ -232,7 +235,7 @@ extern "C" { main->setting.status_receive = main->setting.receive.statuss.array[i]; 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]); + kt_tacocat_print_error_on_busy(&main->program.error, kt_tacocat_receive_s, main->setting.receive.networks.array[i]); } else { kt_tacocat_print_error_status(&main->program.error, main->setting.receive.sockets.array[i].domain == f_socket_protocol_family_inet4_e diff --git a/sources/c/tacocat/main/receive.c b/sources/c/tacocat/main/receive.c index 29f2be2..a566013 100644 --- a/sources/c/tacocat/main/receive.c +++ b/sources/c/tacocat/main/receive.c @@ -40,12 +40,6 @@ extern "C" { if (F_status_is_error(main->setting.state.status)) continue; } } // for - - // @todo handle errors - //if (F_status_is_error(main->setting.receive.statuss.array[i])) ... // @todo more work needed to clear error bit when a new read is ready. - } - else { - // @todo handle error or F_time_out on main->setting.status_receive. } } while (F_status_is_error_not(main->setting.status_receive)); @@ -66,167 +60,195 @@ extern "C" { #ifndef _di_kt_tacocat_receive_process_ 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]; + if (!main) return; + f_socket_t * const socket = &main->setting.receive.sockets.array[index]; f_status_t * const status = &main->setting.receive.statuss.array[index]; - f_string_dynamic_t * const name = &main->setting.receive.names.array[index]; + f_string_dynamic_t * const network = &main->setting.receive.networks.array[index]; 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]; - 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; + if (!(main->setting.receive.flags.array[index])) { + main->setting.receive.flags.array[index] = kt_tacocat_socket_flag_block_control_e; + main->setting.receive.retrys.array[index] = 0; buffer->used = 0; socket->size_read = kt_tacocat_packet_read_d; } - const size_t size_read = socket->size_read; - - // @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 (main->setting.receive.flags.array[index] & kt_tacocat_socket_flag_block_control_e) { + kt_tacocat_receive_process_control(main, index); - // 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); + if (F_status_is_error(*status) || buffer->used < kt_tacocat_packet_peek_d) { + f_file_close_id(&socket->id_data); - *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); + return; + } - socket->size_read = kt_tacocat_packet_peek_d; + // Reset the buffer to allow for reusing and writing to the file in blocks. + buffer->used = 0; + socket->size_read = kt_tacocat_packet_read_d; - *status = f_socket_read_stream(socket, 0, (void *) (buffer->string + buffer->used), &length_read); + // Make sure the buffer is large enough for payload processing block reads. + *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_memory_array_increase_by, network, status, main->setting.receive.flags.array[index], &socket->id_data); + } - socket->size_read = size_read; + if (main->setting.receive.flags.array[index] & kt_tacocat_socket_flag_block_payload_e) { + size_t length_read = 0; - macro_kt_receive_process_handle_error_exit_1(main, f_socket_read_stream, name, status, flag, &socket->id_data); + *status = f_socket_read_stream(socket, 0, (void *) buffer->string, &length_read); + macro_kt_receive_process_handle_error_exit_1(main, f_socket_read_stream, network, status, main->setting.receive.flags.array[index], &socket->id_data); - buffer->used += length_read; + if (length_read) { + buffer->used = length_read; - // 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) { + *status = f_file_write(main->setting.receive.files.array[index], *buffer, 0); - // 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); + // 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(*status)) { + // @fixme The file name is not being saved, need to add the file name. For now just adding "socket->name" as a placeholder. + kt_tacocat_print_error_on_file(&main->program.error, macro_kt_tacocat_f(f_file_write), kt_tacocat_receive_s, *network, *status, socket->name); + } - socket->size_read = kt_tacocat_cache_size_peek_d - 1; - length_read = 0; + // Reset buffer used and increment counter. + main->setting.receive.packets.array[index].payload.stop += buffer->used; + buffer->used = 0; - *status = f_socket_read_stream(socket, f_socket_flag_peek_e | f_socket_flag_wait_not_e, (void *) main->cache.peek, &length_read); + f_file_close_id(&socket->id_data); - socket->size_read = size_read; - } + if (main->setting.receive.packets.array[index].payload.stop < main->setting.receive.packets.array[index].size) return; + } - // 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); + main->setting.receive.flags.array[index] -= kt_tacocat_socket_flag_block_payload_e; + } - buffer->used = 0; - *retry = 0; - *status = F_status_set_error(F_packet_too_small); - *flag -= kt_tacocat_socket_flag_block_begin_e; + // Done processing the Packet. + f_file_close_id(&socket->id_data); + main->setting.receive.flags.array[index] = 0; - f_file_close_id(&socket->id_data); + if (buffer->size > kt_tacocat_max_maintain_d) { + buffer->used = 0; - return; - } + *status = f_memory_array_resize(kt_tacocat_max_maintain_d, sizeof(f_char_t), (void **) &buffer->string, &buffer->used, &buffer->size); - ++(*retry); + // 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, *network, *status); + } + } + } +#endif // _di_kt_tacocat_receive_process_ - f_file_close_id(&socket->id_data); +#ifndef _di_kt_tacocat_receive_process_control_ + void kt_tacocat_receive_process_control(kt_tacocat_main_t * const main, const f_number_unsigned_t index) { - return; - } + if (!main) return; - packet->control.start = 1; - packet->control.stop = 0; - packet->size.start = 1; - packet->size.stop = 0; - packet->payload.start = 1; - packet->payload.stop = 0; + uint16_t * const flag = &main->setting.receive.flags.array[index]; + f_socket_t * const socket = &main->setting.receive.sockets.array[index]; + f_status_t * const status = &main->setting.receive.statuss.array[index]; + f_string_dynamic_t * const network = &main->setting.receive.networks.array[index]; + f_string_dynamic_t * const buffer = &main->setting.receive.buffers.array[index]; - // @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); + const size_t size_read = socket->size_read; + size_t length_read = 0; - // @todo this needs to be wrapped in big/little endian checks, but for now just use ntohl. - *total = ntohl(*((uint32_t *) (buffer->string + 1))); + *status = f_socket_accept(socket); - 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); + // The socket failed to accept and so there is no data socket id to close. + macro_kt_receive_process_begin_handle_error_exit_1(main, f_socket_accept, network, status, flag); - *flag -= kt_tacocat_socket_flag_block_begin_e; + *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_begin_handle_error_exit_1(main, f_memory_array_increase_by, network, status, flag); - return; - } + socket->size_read = kt_tacocat_packet_peek_d; - if (main->setting.flag & kt_tacocat_main_flag_max_buffer_e) { - if (*total > main->setting.max_buffer) { - buffer->used = 0; + *status = f_socket_read_stream(socket, 0, (void *) (buffer->string + buffer->used), &length_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); + socket->size_read = size_read; - // 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); - } - } + macro_kt_receive_process_begin_handle_error_exit_1(main, f_socket_read_stream, network, status, flag); - // @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); + buffer->used += length_read; - 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. + // Continue if the packet header is not fully ready. + if (buffer->used < kt_tacocat_packet_peek_d) { - // @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); + // 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); - return; - } + socket->size_read = kt_tacocat_cache_size_peek_d - 1; + length_read = 0; + + *status = f_socket_read_stream(socket, f_socket_flag_peek_e | f_socket_flag_wait_not_e, (void *) main->cache.peek, &length_read); + + socket->size_read = size_read; + } + + // 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, *network, kt_tacocat_packet_peek_d, buffer->used); + + buffer->used = 0; + main->setting.receive.retrys.array[index] = 0; + *status = F_status_set_error(F_packet_too_small); + *flag = 0; + + return; } - *flag -= kt_tacocat_socket_flag_block_begin_e; - *flag |= kt_tacocat_socket_flag_block_control_e; + ++main->setting.receive.retrys.array[index]; + + return; } - *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_fss_simple_packet_extract_range(*buffer, &main->setting.receive.packets.array[index]); + macro_kt_receive_process_begin_handle_error_exit_1(main, f_fss_simple_packet_extract_range, network, status, flag); - *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); + if (*status == F_packet_too_small) { + main->setting.receive.packets.array[index].control = 0; + main->setting.receive.packets.array[index].size = 0; + } - //kt_tacocat_socket_flag_none_e = 0x0, - //kt_tacocat_socket_flag_block_control_e = 0x1, - //kt_tacocat_socket_flag_block_payload_e = 0x2, + if (main->setting.receive.packets.array[index].size < F_fss_simple_packet_block_header_size_d) { + *flag = 0; - // f_socket_flag_peek_e, - //f_socket_read_stream + return; + } - // For now just close the socket until the appropriate code gets written here. - f_file_close_id(&socket->id_data); + if (main->setting.flag & kt_tacocat_main_flag_max_buffer_e) { + if (main->setting.receive.packets.array[index].size > main->setting.max_buffer) { + buffer->used = 0; - // @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; + 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); - *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, *network, *status); + } + } - // 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); + *status = F_status_set_error(F_packet_too_large); + *flag = 0; + + kt_tacocat_print_error_on_buffer_too_large(&main->program.error, kt_tacocat_receive_s, *network, main->setting.max_buffer, main->setting.receive.packets.array[index].size); + + return; } } + + *flag |= kt_tacocat_socket_flag_block_payload_e; + *flag -= kt_tacocat_socket_flag_block_control_e; + + // The payload range "stop" is used to represent the total amount of bytes processed so far (uncluding the header). + main->setting.receive.packets.array[index].payload.start = 0; + main->setting.receive.packets.array[index].payload.stop = buffer->used - 1; } -#endif // _di_kt_tacocat_receive_process_ +#endif // _di_kt_tacocat_receive_process_control_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/tacocat/main/receive.h b/sources/c/tacocat/main/receive.h index 000e984..0d3d887 100644 --- a/sources/c/tacocat/main/receive.h +++ b/sources/c/tacocat/main/receive.h @@ -32,7 +32,7 @@ extern "C" { #endif // _di_kt_tacocat_receive_ /** - * Process the buffer, retrieving the data and writing to the file. + * Process the network socket, retrieving the data and writing to the file. * * @param main * The main program and settings data. @@ -51,6 +51,26 @@ extern "C" { extern void kt_tacocat_receive_process(kt_tacocat_main_t * const main, const f_number_unsigned_t index); #endif // _di_kt_tacocat_receive_process_ +/** + * Process the network socket, retrieving and processing the Control and Size header information. + * + * @param main + * The main program and settings data. + * + * This alters main.setting.state.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 index + * The position within the receive arrays to process. + * + * @see f_socket_read_stream() + */ +#ifndef _di_kt_tacocat_receive_process_control_ + extern void kt_tacocat_receive_process_control(kt_tacocat_main_t * const main, const f_number_unsigned_t index); +#endif // _di_kt_tacocat_receive_process_control_ + #ifdef __cplusplus } // extern "C" #endif -- 1.8.3.1