fix(client,protocol): EINTR-safe sends, armed abort, keepalive drain grace, TLS WANT_WRITE
This commit is contained in:
+23
-8
@@ -34,20 +34,35 @@
|
||||
* client_send.c, still links the symbol. */
|
||||
volatile sig_atomic_t client_abort_requested = 0;
|
||||
|
||||
#ifndef FASTSYNC_TEST_BUILD
|
||||
/* Signal handler: perform NO work beyond storing the flag. Logging, protocol
|
||||
* I/O and the STATUS_ABORT frame are all done later on the normal send path,
|
||||
* which is not async-signal-safe. Only the production client installs it. */
|
||||
static void client_signal_handler(int signo) {
|
||||
(void)signo;
|
||||
client_abort_requested = 1;
|
||||
/* Only armed while a network transfer is in flight. Outside that window the
|
||||
* handler restores the default disposition and re-raises, so purely local modes
|
||||
* (--list-only/--dry-run/--read-batch/--only-write-batch and the batch-emission
|
||||
* pass) keep terminating on Ctrl-C/SIGTERM instead of silently swallowing it. */
|
||||
volatile sig_atomic_t client_abort_armed = 0;
|
||||
|
||||
void client_set_abort_armed(bool armed) {
|
||||
client_abort_armed = armed ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool client_abort_pending(void) {
|
||||
return client_abort_requested != 0;
|
||||
}
|
||||
|
||||
#ifndef FASTSYNC_TEST_BUILD
|
||||
/* Signal handler: perform NO work beyond storing the flag. Logging, protocol
|
||||
* I/O and the STATUS_ABORT frame are all done later on the normal send path,
|
||||
* which is not async-signal-safe. When no transfer is armed, fall back to the
|
||||
* default action so local-only modes remain interruptible. */
|
||||
static void client_signal_handler(int signo) {
|
||||
if (!client_abort_armed) {
|
||||
signal(signo, SIG_DFL);
|
||||
raise(signo);
|
||||
return;
|
||||
}
|
||||
client_abort_requested = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef FASTSYNC_TEST_BUILD
|
||||
/* Parse environment variables for source/destination directories and save-to-disk flag. */
|
||||
static void parse_environment(const char** out_env_source, const char** out_env_dest,
|
||||
|
||||
@@ -1949,6 +1949,9 @@ int send_files(Config* config) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* From here on a server session may be live, so Ctrl-C/SIGTERM should set the
|
||||
abort flag (and be forwarded as STATUS_ABORT) instead of terminating. */
|
||||
client_set_abort_armed(true);
|
||||
Client* client = connect_transfer_client(config);
|
||||
if (!client) {
|
||||
if (config->transport == TRANSPORT_TCP)
|
||||
@@ -2228,6 +2231,7 @@ send_fail:
|
||||
prepared_scanner_destroy(&prepared);
|
||||
disconnect_transfer_client(client);
|
||||
protocol_session_unbind();
|
||||
client_set_abort_armed(false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2257,6 +2261,9 @@ int send_files_multithreaded(Config** config_ptr) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Armed only once a session may go live (see send_files). */
|
||||
client_set_abort_armed(true);
|
||||
|
||||
long pages = sysconf(_SC_AVPHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
unsigned long long available_memory =
|
||||
@@ -2411,5 +2418,6 @@ int send_files_multithreaded(Config** config_ptr) {
|
||||
/* --ignore-errors: the run completed (and deleted) past an unreadable source
|
||||
directory; report it as errored like rsync does. */
|
||||
pipeline_context_sender_destroy(context);
|
||||
client_set_abort_armed(false);
|
||||
return sender_ok && !scan_io ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
* receiver can clean up before the client exits. */
|
||||
extern volatile sig_atomic_t client_abort_requested;
|
||||
bool client_abort_pending(void);
|
||||
/* Arm/disarm abort handling around the network phase. While disarmed, a
|
||||
* SIGINT/SIGTERM takes the default action (immediate termination) so local-only
|
||||
* modes are not left unresponsive. Defined in client_cli.c. */
|
||||
void client_set_abort_armed(bool armed);
|
||||
|
||||
/* Both sender entry points BORROW `config` for the duration of the call; they
|
||||
* never free it, and the caller retains ownership (freeing it with
|
||||
|
||||
Reference in New Issue
Block a user