From 38d87d6728060d5e196362891d11cae7cfe996b9 Mon Sep 17 00:00:00 2001 From: Kevin Day Date: Wed, 13 Sep 2023 23:22:49 -0500 Subject: [PATCH] Progress: Further work in TacocaT, adding initial code regarding sending. --- sources/c/tacocat/main/common.c | 11 ++- sources/c/tacocat/main/common/define.h | 13 ++- sources/c/tacocat/main/common/enumeration.h | 36 ++++++-- sources/c/tacocat/main/common/print.c | 6 ++ sources/c/tacocat/main/common/print.h | 6 ++ sources/c/tacocat/main/common/type.h | 4 + sources/c/tacocat/main/print/error.h | 2 +- sources/c/tacocat/main/print/warning.c | 41 +++++++++ sources/c/tacocat/main/print/warning.h | 58 ++++++++++++- sources/c/tacocat/main/process.c | 87 ++++++++++++++++++- sources/c/tacocat/main/receive.c | 66 +++++++++------ sources/c/tacocat/main/receive.h | 14 ++-- sources/c/tacocat/main/send.c | 124 +++++++++++++++++++++++++++- sources/c/tacocat/main/send.h | 21 +++++ 14 files changed, 439 insertions(+), 50 deletions(-) diff --git a/sources/c/tacocat/main/common.c b/sources/c/tacocat/main/common.c index 4b0a796..f205e5f 100644 --- a/sources/c/tacocat/main/common.c +++ b/sources/c/tacocat/main/common.c @@ -274,6 +274,11 @@ extern "C" { kt_tacocat_block_size_send_d, }; + const mode_t file_modes[] = { + F_file_mode_all_rw_d, + F_file_mode_all_r_d, + }; + f_number_unsigned_t j = 0; f_number_unsigned_t k = 0; f_number_unsigned_t p = 0; @@ -329,7 +334,7 @@ extern "C" { sets[i]->array[j].size_block = default_block_size[i]; sets[i]->array[j].buffer.used = 0; sets[i]->array[j].client.used = 0; - sets[i]->array[j].flag = kt_tacocat_socket_flag_none_e; + sets[i]->array[j].flag = 0; sets[i]->array[j].name.used = 0; sets[i]->array[j].network.used = 0; sets[i]->array[j].packet.control = 0; @@ -557,8 +562,8 @@ extern "C" { sets[i]->array[j].name.used = main->program.parameters.arguments.array[index].used; sets[i]->array[j].name.size = 0; - // Make sure the file exists and can be read and can be written to, then close when done. - main->setting.state.status = f_file_open(sets[i]->array[j].name, F_file_mode_all_rw_d, &sets[i]->array[j].file); + // Make sure the file exists and can be read and/or can be written to, then close when done. + main->setting.state.status = f_file_open(sets[i]->array[j].name, file_modes[i], &sets[i]->array[j].file); if (F_status_is_error(main->setting.state.status)) { macro_setting_load_handle_send_receive_error_file_continue_1(f_file_open, sets[i]->array[j].name, f_file_operation_open_s, fll_error_file_type_file_e); diff --git a/sources/c/tacocat/main/common/define.h b/sources/c/tacocat/main/common/define.h index 37db509..004a842 100644 --- a/sources/c/tacocat/main/common/define.h +++ b/sources/c/tacocat/main/common/define.h @@ -95,11 +95,13 @@ 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_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_block_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_block_control_e. + * Intended to be used for handling an error during the receive process while processing within flag kt_tacocat_socket_flag_receive_block_control_e. + * + * @todo document macro_kt_send_process_handle_error_exit_1. */ #ifndef _di_kt_tacocat_macros_d_ #define macro_setting_load_print_first() \ @@ -171,6 +173,13 @@ extern "C" { \ return; \ } + + #define macro_kt_send_process_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_send_s, name, status); \ + \ + return F_done_not; \ + } #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 b54688e..2de34ec 100644 --- a/sources/c/tacocat/main/common/enumeration.h +++ b/sources/c/tacocat/main/common/enumeration.h @@ -127,20 +127,42 @@ extern "C" { #endif // _di_kt_tacocat_print_flag_e_ /** - * Individual socket-specific flags. + * Individual socket-specific flags for receiving. * - * kt_tacocat_socket_flag_*_e: + * 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. */ -#ifndef _di_kt_tacocat_socket_flag_e_ +#ifndef _di_kt_tacocat_socket_flag_receive_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_receive_none_e = 0x0, + kt_tacocat_socket_flag_receive_block_control_e = 0x1, + kt_tacocat_socket_flag_receive_block_payload_e = 0x2, }; // enum -#endif // _di_kt_tacocat_socket_flag_e_ +#endif // _di_kt_tacocat_socket_flag_receive_e_ + +/** + * Individual socket-specific flags for receiving. + * + * kt_tacocat_socket_flag_send_*_e: + * - none: No flags set. + * - file_open: File is open. + * - file_buffer: File is buffered. + * - connect: The remote address is connected. + * - buffer: Send the buffer. + * - buffer_sent: Buffer has been sent. + */ +#ifndef _di_kt_tacocat_socket_flag_send_e_ + enum { + kt_tacocat_socket_flag_send_none_e = 0x0, + kt_tacocat_socket_flag_send_file_open_e = 0x1, + kt_tacocat_socket_flag_send_file_buffer_e = 0x2, + kt_tacocat_socket_flag_send_connect_e = 0x4, + kt_tacocat_socket_flag_send_buffer_e = 0x8, + kt_tacocat_socket_flag_send_buffer_sent_e = 0x10, + }; // enum +#endif // _di_kt_tacocat_socket_flag_send_e_ #ifdef __cplusplus } // extern "C" diff --git a/sources/c/tacocat/main/common/print.c b/sources/c/tacocat/main/common/print.c index ebc87ef..1bd7f46 100644 --- a/sources/c/tacocat/main/common/print.c +++ b/sources/c/tacocat/main/common/print.c @@ -7,8 +7,11 @@ extern "C" { #ifndef _di_kt_tacocat_f_a_ const f_string_t kt_tacocat_f_a[] = { "f_console_parameter_process", + "f_file_close", "f_file_close_id", "f_file_open", + "f_file_read_block", + "f_file_size_by_id", "f_file_write", "f_fss_simple_packet_extract_range", "f_memory_array_increase_by", @@ -20,14 +23,17 @@ extern "C" { "f_socket_bind_inet6", "f_socket_bind_local", "f_socket_close", + "f_socket_connect", "f_socket_create", "f_socket_disconnect", "f_socket_listen", "f_socket_option_set", "f_socket_read_stream", + "f_socket_write_stream", "f_string_append_nulless", "f_string_dynamic_append", "f_string_dynamic_append_nulless", + "f_string_dynamic_terminate_after", "f_thread_create", "fl_conversion_dynamic_partial_to_unsigned_detect", "fl_conversion_dynamic_to_unsigned_detect", diff --git a/sources/c/tacocat/main/common/print.h b/sources/c/tacocat/main/common/print.h index f4eea47..d664306 100644 --- a/sources/c/tacocat/main/common/print.h +++ b/sources/c/tacocat/main/common/print.h @@ -40,8 +40,11 @@ extern "C" { #ifndef _di_kt_tacocat_f_e_ enum { kt_tacocat_f_f_console_parameter_process_e, + kt_tacocat_f_f_file_close_e, kt_tacocat_f_f_file_close_id_e, kt_tacocat_f_f_file_open_e, + kt_tacocat_f_f_file_read_block_e, + kt_tacocat_f_f_file_size_by_id_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, @@ -53,14 +56,17 @@ extern "C" { kt_tacocat_f_f_socket_bind_inet6_e, kt_tacocat_f_f_socket_bind_local_e, kt_tacocat_f_f_socket_close_e, + kt_tacocat_f_f_socket_connect_e, 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_socket_write_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_string_dynamic_terminate_after_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, diff --git a/sources/c/tacocat/main/common/type.h b/sources/c/tacocat/main/common/type.h index 198560f..e42fdc3 100644 --- a/sources/c/tacocat/main/common/type.h +++ b/sources/c/tacocat/main/common/type.h @@ -20,6 +20,7 @@ extern "C" { * A set of all socket related properties. * * size_block: The size in bytes to used to represent a block when sending or receiving packets. + * size_done: The size in bytes that are done being processed (generally used by send/write). * * flag: A set of flags. * retry: The current number of retries performed. @@ -36,6 +37,7 @@ extern "C" { #ifndef _di_kt_tacocat_socket_set_t_ typedef struct { f_number_unsigned_t size_block; + size_t size_done; uint16_t flag; uint16_t retry; @@ -55,6 +57,7 @@ extern "C" { kt_tacocat_block_size_d, \ 0, \ 0, \ + 0, \ f_file_t_initialize, \ f_socket_t_initialize, \ f_status_t_initialize, \ @@ -70,6 +73,7 @@ extern "C" { size_block, \ 0, \ 0, \ + 0, \ f_file_t_initialize, \ f_poll_t_initialize, \ f_socket_t_initialize, \ diff --git a/sources/c/tacocat/main/print/error.h b/sources/c/tacocat/main/print/error.h index 1856621..7c6695b 100644 --- a/sources/c/tacocat/main/print/error.h +++ b/sources/c/tacocat/main/print/error.h @@ -65,7 +65,7 @@ extern "C" { #endif // _di_kt_tacocat_print_error_status_ /** - * Print file related error or warning messages. + * Print file related error messages. * * @param print * The output structure to print to. diff --git a/sources/c/tacocat/main/print/warning.c b/sources/c/tacocat/main/print/warning.c index 3efd5f1..fdaf39c 100644 --- a/sources/c/tacocat/main/print/warning.c +++ b/sources/c/tacocat/main/print/warning.c @@ -23,6 +23,47 @@ extern "C" { } #endif // _di_kt_tacocat_print_warning_on_busy_ +#ifndef _di_kt_tacocat_print_warning_on_client_closed_ + f_status_t kt_tacocat_print_warning_on_client_closed(fl_print_t * const print, f_string_static_t on, const f_string_static_t network) { + + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + f_file_stream_lock(print->to); + + 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("%[' closed by the client.%]%r", 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_on_client_closed_ + +#ifndef _di_kt_tacocat_print_warning_on_file_ + f_status_t kt_tacocat_print_warning_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, const f_string_static_t operation) { + + if (!print || !print->custom) return F_status_set_warning(F_output_not); + if (print->verbosity < f_console_verbosity_verbose_e) return F_output_not; + + f_file_stream_lock(print->to); + + fl_print_format("%[%QNetwork on%] ", print->to, print->set->warning, print->prefix, print->set->warning); + 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->warning, print->set->warning, 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->warning, print->set->warning, 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->warning, print->set->warning, 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, operation, fll_error_file_type_file_e); + } +#endif // _di_kt_tacocat_print_warning_on_file_ + #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) { diff --git a/sources/c/tacocat/main/print/warning.h b/sources/c/tacocat/main/print/warning.h index 9b9b632..09841ee 100644 --- a/sources/c/tacocat/main/print/warning.h +++ b/sources/c/tacocat/main/print/warning.h @@ -18,7 +18,6 @@ extern "C" { /** * 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. @@ -44,6 +43,63 @@ extern "C" { #endif // _di_kt_tacocat_print_warning_on_busy_ /** + * Print warning message about client closing the connection unexpectedly. + * + * @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_warning_on_client_closed_ + extern f_status_t kt_tacocat_print_warning_on_client_closed(fl_print_t * const print, f_string_static_t on, const f_string_static_t network); +#endif // _di_kt_tacocat_print_warning_on_client_closed_ + +/** + * Print network-related warning 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 warning 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 warning is related. + * @param status + * The status code representing the warning. + * @param name + * The name of the file or directory. + * @param operation + * The file operation that fails, such as 'open' or 'write'. + * + * @return + * F_okay on success. + * F_output_not on success, but no printing is performed. + * + * F_output_not (with warning bit) if setting is NULL. + * + * @see fll_error_file_print() + */ +#ifndef _di_kt_tacocat_print_warning_on_file_ + extern f_status_t kt_tacocat_print_warning_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, const f_string_static_t operation); +#endif // _di_kt_tacocat_print_warning_on_file_ + +/** * Print warning message about given parameter being a specific integer value. * * @param print diff --git a/sources/c/tacocat/main/process.c b/sources/c/tacocat/main/process.c index dacb744..54acfb2 100644 --- a/sources/c/tacocat/main/process.c +++ b/sources/c/tacocat/main/process.c @@ -222,6 +222,8 @@ extern "C" { if (!main || F_status_is_error(main->setting.status_send)) return; + int value_socket = 0; + for (f_number_unsigned_t i = 0; i < main->setting.send.used; ++i) { if (kt_tacocat_signal_check(main)) return; @@ -237,7 +239,90 @@ extern "C" { continue; } - // @todo f_socket_bind(). + // Make the socket re-usable. + { + value_socket = 1; + + main->setting.send.array[i].status = f_socket_option_set(&main->setting.send.array[i].socket, 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.send.array[i].status)) { + main->setting.status_send = main->setting.send.array[i].status; + + kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_option_set), main->setting.status_send); + + continue; + } + } + + for (main->setting.send.array[i].retry = 0; main->setting.send.array[i].retry < kt_tacocat_startup_retry_max_d; ++main->setting.send.array[i].retry) { + + if (main->setting.send.array[i].socket.domain == f_socket_protocol_family_inet4_e || main->setting.send.array[i].socket.domain == f_socket_protocol_family_inet6_e || main->setting.send.array[i].socket.domain == f_socket_protocol_family_local_e) { + main->setting.send.array[i].status = f_socket_connect(main->setting.send.array[i].socket); + } + else { + main->setting.status_send = F_status_set_error(F_parameter); + + kt_tacocat_print_error_socket_protocol_unsupported(&main->program.error, main->setting.send.array[i].network, main->setting.send.array[i].socket.domain); + + return; + } + + if (F_status_set_fine(main->setting.send.array[i].status) == F_busy_address) { + if (main->setting.send.array[i].retry < kt_tacocat_startup_retry_max_d) { + kt_tacocat_print_warning_on_busy(&main->program.warning, kt_tacocat_send_s, main->setting.send.array[i].network, main->setting.send.array[i].retry + 1); + + struct timespec time = { 0 }; + + main->setting.send.array[i].status = 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.send.array[i].status)) { + nanosleep(&time, 0); + } + + if (main->program.signal_received) { + main->setting.status_send = F_status_set_error(F_interrupt); + + return; + } + + main->setting.send.array[i].status = F_status_set_error(F_busy_address); + + continue; + } + } + + break; + } // for + + if (F_status_is_error_not(main->setting.send.array[i].status) && main->setting.send.array[i].retry < kt_tacocat_startup_retry_max_d) { + main->setting.send.array[i].status = F_okay; + } + + main->setting.send.array[i].retry = 0; + + if (F_status_is_error(main->setting.send.array[i].status)) { + main->setting.status_send = main->setting.send.array[i].status; + + if (F_status_set_fine(main->setting.status_send) == F_busy_address) { + kt_tacocat_print_error_on_busy(&main->program.error, kt_tacocat_send_s, main->setting.send.array[i].network); + } + else { + kt_tacocat_print_error_status(&main->program.error, macro_kt_tacocat_f(f_socket_connect), main->setting.status_send); + } + + continue; + } + + if (main->setting.send.array[i].socket.id == -1) { + main->setting.send_polls.array[i].fd = -1; + main->setting.send_polls.array[i].events = 0; + main->setting.send_polls.array[i].revents = 0; + } + else { + main->setting.send_polls.array[i].fd = main->setting.send.array[i].socket.id; + main->setting.send_polls.array[i].events = f_poll_write_e; + main->setting.send_polls.array[i].revents = 0; + } } // for if (F_status_is_error_not(main->setting.status_send)) { diff --git a/sources/c/tacocat/main/receive.c b/sources/c/tacocat/main/receive.c index 1c933f0..24b4f04 100644 --- a/sources/c/tacocat/main/receive.c +++ b/sources/c/tacocat/main/receive.c @@ -33,7 +33,7 @@ extern "C" { 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, i); + kt_tacocat_receive_process(main, &main->setting.receive.array[i]); main->setting.receive_polls.array[i].revents = 0; @@ -58,17 +58,15 @@ extern "C" { #endif // _di_kt_tacocat_receive_ #ifndef _di_kt_tacocat_receive_process_ - void kt_tacocat_receive_process(kt_tacocat_main_t * const main, const f_number_unsigned_t index) { + void kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set) { - if (!main) return; + if (!main || !set) return; - kt_tacocat_socket_set_t * const set = &main->setting.receive.array[index]; - - // This is a new packet (kt_tacocat_socket_flag_none_e). + // 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_block_control_e; + set->flag = kt_tacocat_socket_flag_receive_block_control_e; set->retry = 0; set->buffer.used = 0; set->socket.size_read = kt_tacocat_packet_read_d; @@ -77,12 +75,14 @@ extern "C" { if (F_status_is_error(set->status)) { kt_tacocat_print_error_on_file(&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; } } // Load the header of the new packet. - if (set->flag & kt_tacocat_socket_flag_block_control_e) { - kt_tacocat_receive_process_control(main, index); + if (set->flag & kt_tacocat_socket_flag_receive_block_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); @@ -105,7 +105,7 @@ extern "C" { macro_kt_receive_process_handle_error_exit_1(main, f_memory_array_increase_by, set->network, set->status, set->flag, &set->socket.id_data); } - if (set->flag & kt_tacocat_socket_flag_block_payload_e) { + if (set->flag & kt_tacocat_socket_flag_receive_block_payload_e) { size_t length_read = 0; set->status = f_socket_read_stream(&set->socket, 0, (void *) set->buffer.string, &length_read); @@ -152,11 +152,9 @@ extern "C" { #endif // _di_kt_tacocat_receive_process_ #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) { - - if (!main) return; + void kt_tacocat_receive_process_control(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set) { - kt_tacocat_socket_set_t * const set = &main->setting.receive.array[index]; + if (!main || !set) return; const size_t size_read = set->socket.size_read; size_t length_read = 0; @@ -192,21 +190,34 @@ extern "C" { set->status = f_socket_read_stream(&set->socket, f_socket_flag_peek_e | f_socket_flag_wait_not_e, (void *) main->cache.peek, &length_read); set->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, set->network, kt_tacocat_packet_peek_d, set->buffer.used); + + set->buffer.used = 0; + set->retry = 0; + set->status = F_status_set_error(F_packet_too_small); + set->flag = 0; + + return; + } } + else { - // 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, set->network, kt_tacocat_packet_peek_d, set->buffer.used); + // 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; - main->setting.receive.array[index].retry = 0; - set->status = F_status_set_error(F_packet_too_small); set->flag = 0; + set->packet.control = 0; + set->packet.size = 0; + set->status = F_status_set_error(F_packet_too_small); return; } - ++main->setting.receive.array[index].retry; + ++set->retry; return; } @@ -214,13 +225,14 @@ extern "C" { set->status = f_fss_simple_packet_extract_range(set->buffer, &set->packet); macro_kt_receive_process_begin_handle_error_exit_1(main, f_fss_simple_packet_extract_range, set->network, set->status, set->flag); - if (set->status == F_packet_too_small) { - set->packet.control = 0; - set->packet.size = 0; - } + if (set->status == F_packet_too_small || set->packet.size < F_fss_simple_packet_block_header_size_d) { + 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); - if (set->packet.size < F_fss_simple_packet_block_header_size_d) { + set->buffer.used = 0; set->flag = 0; + set->packet.control = 0; + set->packet.size = 0; + set->status = F_status_set_error(F_packet_too_small); return; } @@ -247,8 +259,8 @@ extern "C" { } } - set->flag |= kt_tacocat_socket_flag_block_payload_e; - set->flag -= kt_tacocat_socket_flag_block_control_e; + set->flag |= kt_tacocat_socket_flag_receive_block_payload_e; + set->flag -= kt_tacocat_socket_flag_receive_block_control_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; diff --git a/sources/c/tacocat/main/receive.h b/sources/c/tacocat/main/receive.h index 0d3d887..8fd9aa6 100644 --- a/sources/c/tacocat/main/receive.h +++ b/sources/c/tacocat/main/receive.h @@ -42,13 +42,14 @@ extern "C" { * * 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. + * @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, const f_number_unsigned_t index); + extern void kt_tacocat_receive_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set); #endif // _di_kt_tacocat_receive_process_ /** @@ -62,13 +63,14 @@ extern "C" { * * 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. + * @param set + * The socket set to process. + * Must not be NULL. * * @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); + extern void kt_tacocat_receive_process_control(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set); #endif // _di_kt_tacocat_receive_process_control_ #ifdef __cplusplus diff --git a/sources/c/tacocat/main/send.c b/sources/c/tacocat/main/send.c index 3ae0e04..12cb840 100644 --- a/sources/c/tacocat/main/send.c +++ b/sources/c/tacocat/main/send.c @@ -12,11 +12,41 @@ extern "C" { if (!void_main) return 0; kt_tacocat_main_t * const main = (kt_tacocat_main_t *) void_main; + f_number_unsigned_t i = 0; + f_status_t ready = F_okay; kt_tacocat_process_socket_set_send(main); - if (F_status_is_error_not(main->setting.status_send)) { - // @todo + if (F_status_is_error_not(main->setting.status_send) && main->setting.send.used) { + do { + ready = F_okay; + + for (i = 0; i < main->setting.send.used; ++i) { + + if (main->program.signal_received) { + main->setting.status_send = F_status_set_error(F_interrupt); + + return 0; + } + + if (main->setting.send.array[i].status == F_done) { + if (ready != F_done_not) { + ready = F_done; + } + } + else { + if (kt_tacocat_send_process(main, &main->setting.send.array[i]) == F_done) { + if (ready != F_done_not) { + ready = F_done; + } + } + else { + ready = F_done_not; + } + } + } // for + + } while (F_status_is_error_not(main->setting.status_send) && ready == F_done_not); } kt_tacocat_process_socket_sets_disconnect(main, &main->setting.send); @@ -31,6 +61,96 @@ extern "C" { } #endif // _di_kt_tacocat_send_ +#ifndef _di_kt_tacocat_send_process_ + f_status_t kt_tacocat_send_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set) { + + if (!main || !set) return F_status_set_error(F_parameter); + + // @todo this needs a max retries for sending without error, possibly resetting depending on the part (flag). + + if (!set->flag) { + set->size_done = 0; + + 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(&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_file_open_e; + } + + if (set->flag == kt_tacocat_socket_flag_send_file_open_e) { + set->buffer.used = 0; + + // Make sure the buffer is large enough for the file block reads (including a space for a terminating NULL). + set->status = f_memory_array_increase_by(set->file.size_read + 1, sizeof(f_char_t), (void **) &set->buffer.string, &set->buffer.used, &set->buffer.size); + macro_kt_send_process_handle_error_exit_1(main, f_memory_array_increase_by, set->network, set->status, set->flag); + + set->status = f_file_read_block(set->file, &set->buffer); + macro_kt_send_process_handle_error_exit_1(main, f_file_read_block, set->network, set->status, set->flag); + + if (set->buffer.used) { + set->status = f_string_dynamic_terminate_after(&set->buffer); + macro_kt_send_process_handle_error_exit_1(main, f_string_dynamic_terminate_after, set->network, set->status, set->flag); + + set->flag = kt_tacocat_socket_flag_send_file_buffer_e; + } + else { + + // File is empty, nothing left to send. + set->flag = kt_tacocat_socket_flag_send_buffer_sent_e; + } + } + + if (set->flag == kt_tacocat_socket_flag_send_file_buffer_e) { + set->status = f_socket_connect(set->socket); + macro_kt_send_process_handle_error_exit_1(main, f_socket_connect, set->network, set->status, set->flag); + + set->flag = kt_tacocat_socket_flag_send_connect_e; + } + + if (set->flag == kt_tacocat_socket_flag_send_connect_e) { + size_t written = 0; + + set->status = f_socket_write_stream(&set->socket, 0, (void *) (set->buffer.string + set->size_done), &written); + macro_kt_send_process_handle_error_exit_1(main, f_socket_write_stream, set->network, set->status, set->flag); + + set->size_done += written; + + // When the buffer is smaller than the read block size, then the entire file should be completely sent. + if (set->size_done == set->buffer.used && set->size_done < set->file.size_read) { + set->flag = kt_tacocat_socket_flag_send_buffer_sent_e; + } + } + + if (set->flag == kt_tacocat_socket_flag_send_buffer_sent_e) { + set->flag = 0; + set->size_done = 0; + + set->status = f_file_close(&set->file); + + if (F_status_is_error(set->status)) { + kt_tacocat_print_warning_on_file(&main->program.warning, macro_kt_tacocat_f(f_file_close), kt_tacocat_send_s, set->network, set->status, set->name, f_file_operation_close_s); + } + + set->status = f_socket_disconnect(&set->socket, f_socket_close_write_e); + + if (F_status_is_error(set->status)) { + kt_tacocat_print_warning_on_file(&main->program.warning, macro_kt_tacocat_f(f_socket_disconnect), kt_tacocat_send_s, set->network, set->status, set->name, f_file_operation_close_s); + } + + set->status = F_okay; + + return F_done; + } + + return F_done_not; + } +#endif // _di_kt_tacocat_send_process_ + #ifdef __cplusplus } // extern "C" #endif diff --git a/sources/c/tacocat/main/send.h b/sources/c/tacocat/main/send.h index 5dfd0af..39408e8 100644 --- a/sources/c/tacocat/main/send.h +++ b/sources/c/tacocat/main/send.h @@ -31,6 +31,27 @@ extern "C" { extern void * kt_tacocat_send(void * const main); #endif // _di_kt_tacocat_send_ +/** + * Process the network socket, retrieving the data and writing to the file. + * + * @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 set + * The socket set to process. + * Must not be NULL. + * + * @see f_socket_read_stream() + */ +#ifndef _di_kt_tacocat_send_process_ + extern f_status_t kt_tacocat_send_process(kt_tacocat_main_t * const main, kt_tacocat_socket_set_t * const set); +#endif // _di_kt_tacocat_send_process_ + #ifdef __cplusplus } // extern "C" #endif -- 1.8.3.1