From f53412f22c6f091797058869a494e9ed61b9ee84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Fri, 29 Dec 2023 21:23:59 -0500 Subject: [PATCH] Add a mutex to protect the client. --- src/sftp/sftp.h | 3 + src/sftp/sftp_client.c | 193 +++++++++++++++++++++++++---------------- 2 files changed, 120 insertions(+), 76 deletions(-) diff --git a/src/sftp/sftp.h b/src/sftp/sftp.h index 28b0fbf0f2..c9dca4c84f 100644 --- a/src/sftp/sftp.h +++ b/src/sftp/sftp.h @@ -100,9 +100,12 @@ typedef struct sftp_client_state { void *cb_data; sftp_str_t err_msg; sftp_str_t err_lang; + pthread_mutex_t mtx; + uint32_t running; uint32_t id; uint32_t err_id; uint32_t err_code; + bool terminating; } *sftpc_state_t; enum sftp_handle_type { diff --git a/src/sftp/sftp_client.c b/src/sftp/sftp_client.c index 8306ee2c61..ca3254e061 100644 --- a/src/sftp/sftp_client.c +++ b/src/sftp/sftp_client.c @@ -69,6 +69,9 @@ sftpc_finish(sftpc_state_t state) assert(state); if (state == NULL) return; + pthread_mutex_lock(&state->mtx); + state->terminating = true; + pthread_mutex_unlock(&state->mtx); // TODO: Close all open handles while (!CloseEvent(state->recv_event)) { assert(errno == EBUSY); @@ -77,8 +80,16 @@ sftpc_finish(sftpc_state_t state) SetEvent(state->recv_event); SLEEP(1); } + pthread_mutex_lock(&state->mtx); + while (state->running) { + pthread_mutex_unlock(&state->mtx); + SLEEP(1); + pthread_mutex_lock(&state->mtx); + } sftp_free_rx_pkt(state->rxp); sftp_free_tx_pkt(state->txp); + pthread_mutex_unlock(&state->mtx); + pthread_mutex_destroy(&state->mtx); free(state); } @@ -100,6 +111,9 @@ sftpc_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_d ret->id = 0; ret->err_lang = NULL; ret->err_msg = NULL; + ret->running = 0; + pthread_mutex_init(&ret->mtx, NULL); + ret->terminating = false; return ret; } @@ -162,8 +176,12 @@ get_result(sftpc_state_t state) return false; if (!state->send_cb(txbuf, txsz, state->cb_data)) return false; - if (WaitForEvent(state->recv_event, INFINITE) != WAIT_OBJECT_0) + pthread_mutex_unlock(&state->mtx); + if (WaitForEvent(state->recv_event, INFINITE) != WAIT_OBJECT_0) { + pthread_mutex_lock(&state->mtx); return false; + } + pthread_mutex_lock(&state->mtx); if (state->rxp == NULL) return false; if (state->rxp->type != SSH_FXP_VERSION) { @@ -192,201 +210,224 @@ handle_error(sftpc_state_t state) response_handled(state); } +static bool +parse_handle(sftpc_state_t state, sftp_str_t *handle) +{ + assert(state->rxp); + if (state->rxp == NULL) + return false; + assert(state->rxp->type == SSH_FXP_HANDLE); + if (state->rxp->type != SSH_FXP_HANDLE) + return false; + assert(handle); + if (handle == NULL) + return false; + *handle = getstring(state); + if (*handle == NULL) + return false; + return true; +} + +static bool +enter_function(sftpc_state_t state) +{ + if (!check_state(state)) + return false; + if (pthread_mutex_lock(&state->mtx)) + return false; + if (state->terminating) { + pthread_mutex_unlock(&state->mtx); + return false; + } + state->running++; +} + +static bool +exit_function(sftpc_state_t state, bool retval) +{ + assert(state->running > 0); + state->running--; + pthread_mutex_unlock(&state->mtx); + return retval; +} + bool sftpc_init(sftpc_state_t state) { - if (!check_state(state)) + if (!enter_function(state)) return false; if (!appendheader(state, SSH_FXP_INIT)) - return false; + return exit_function(state, false); if (!append32(state, SFTP_VERSION)) - return false; + return exit_function(state, false); if (!get_result(state)) - return false; + return exit_function(state, false); if (state->rxp->type != SSH_FXP_VERSION) - return false; + return exit_function(state, false); if (get32(state) != SFTP_VERSION) { response_handled(state); - return false; + return exit_function(state, false); } response_handled(state); state->id = 0; - return true; + return exit_function(state, true); } bool sftpc_recv(sftpc_state_t state, uint8_t *buf, uint32_t sz) { - if (!check_state(state)) + if (!enter_function(state)) return false; if (!sftp_rx_pkt_append(&state->rxp, buf, sz)) - return false; + return exit_function(state, false); if (sftp_have_full_pkt(state->rxp)) SetEvent(state->recv_event); - return true; + return exit_function(state, true); } bool sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret) { - if (!check_state(state)) + if (!enter_function(state)) return false; assert(ret); if (ret == NULL) - return false; + return exit_function(state, false); if (*ret != NULL) - return false; + return exit_function(state, false); if (!appendheader(state, SSH_FXP_REALPATH)) - return false; + return exit_function(state, false); sftp_str_t pstr = sftp_strdup(path); if (!appendandfreestring(state, &pstr)) - return false; + return exit_function(state, false); if (!get_result(state)) - return false; + return exit_function(state, false); if (state->rxp->type == SSH_FXP_NAME) { if (get32(state) != 1) { response_handled(state); - return false; + return exit_function(state, false); } *ret = getstring(state); response_handled(state); - return true; + return exit_function(state, true); } handle_error(state); - return false; -} - -static bool -parse_handle(sftpc_state_t state, sftp_str_t *handle) -{ - assert(state->rxp); - if (state->rxp == NULL) - return false; - assert(state->rxp->type == SSH_FXP_HANDLE); - if (state->rxp->type != SSH_FXP_HANDLE) - return false; - assert(handle); - if (handle == NULL) - return false; - *handle = getstring(state); - if (*handle == NULL) - return false; - return true; + return exit_function(state, false); } bool sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t attr, sftp_dirhandle_t *handle) { - if (!check_state(state)) - return false; + if (!enter_function(state)) + return exit_function(state, false); assert(path); if (path == NULL) - return false; + return exit_function(state, false); assert(handle); if (handle == NULL) - return false; + return exit_function(state, false); assert(!*handle); if (*handle != NULL) - return false; + return exit_function(state, false); if (!appendheader(state, SSH_FXP_OPEN)) - return false; + return exit_function(state, false); sftp_str_t pstr = sftp_strdup(path); if (!appendandfreestring(state, &pstr)) - return false; + return exit_function(state, false); if (!append32(state, flags)) - return false; + return exit_function(state, false); sftp_file_attr_t a = attr; if (a == NULL) { a = sftp_fattr_alloc(); if (a == NULL) - return false; + return exit_function(state, false); } if (!appendfattr(state, a)) { if (a != attr) sftp_fattr_free(a); - return false; + return exit_function(state, false); } if (a != attr) sftp_fattr_free(a); if (!get_result(state)) - return false; + return exit_function(state, false); if (state->rxp->type == SSH_FXP_HANDLE) { if (!parse_handle(state, (sftp_str_t *)handle)) { response_handled(state); - return false; + return exit_function(state, false); } response_handled(state); - return true; + return exit_function(state, true); } handle_error(state); - return false; + return exit_function(state, false); } bool sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle) { - if (!check_state(state)) + if (!enter_function(state)) return false; if (!appendheader(state, SSH_FXP_CLOSE)) - return false; + return exit_function(state, false); if (!appendfhandle(state, *handle)) - return false; + return exit_function(state, false); if (!get_result(state)) - return false; + return exit_function(state, false); handle_error(state); free_sftp_str(*handle); *handle = NULL; - return state->err_code == SSH_FX_OK; + return exit_function(state, state->err_code == SSH_FX_OK); } bool sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint32_t len, sftp_str_t *ret) { - if (!check_state(state)) - return false; + if (!enter_function(state)) + return exit_function(state, false); assert(ret); if (ret == NULL) - return false; + return exit_function(state, false); assert(*ret == NULL); if (*ret != NULL) - return false; + return exit_function(state, false); if (!appendheader(state, SSH_FXP_READ)) - return false; + return exit_function(state, false); if (!appendfhandle(state, handle)) - return false; + return exit_function(state, false); if (!append64(state, offset)) - return false; + return exit_function(state, false); if (!append32(state, len)) - return false; + return exit_function(state, false); if (!get_result(state)) - return false; + return exit_function(state, false); if (state->rxp->type == SSH_FXP_DATA) { *ret = getstring(state); response_handled(state); - return *ret != NULL; + return exit_function(state, *ret != NULL); } handle_error(state); - return false; + return exit_function(state, false); } bool sftpc_write(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, sftp_str_t data) { - if (!check_state(state)) + if (!enter_function(state)) return false; assert(data); if (data == NULL) - return false; + return exit_function(state, false); if (!appendheader(state, SSH_FXP_WRITE)) - return false; + return exit_function(state, false); if (!appendfhandle(state, handle)) - return false; + return exit_function(state, false); if (!append64(state, offset)) - return false; + return exit_function(state, false); if (!appendstring(state, data)) - return false; + return exit_function(state, false); if (!get_result(state)) - return false; + return exit_function(state, false); handle_error(state); - return state->err_code == SSH_FX_OK; + return exit_function(state, state->err_code == SSH_FX_OK); } -- GitLab