Skip to content
Snippets Groups Projects
Commit f53412f2 authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

Add a mutex to protect the client.

parent eff862f8
No related branches found
No related tags found
No related merge requests found
...@@ -100,9 +100,12 @@ typedef struct sftp_client_state { ...@@ -100,9 +100,12 @@ typedef struct sftp_client_state {
void *cb_data; void *cb_data;
sftp_str_t err_msg; sftp_str_t err_msg;
sftp_str_t err_lang; sftp_str_t err_lang;
pthread_mutex_t mtx;
uint32_t running;
uint32_t id; uint32_t id;
uint32_t err_id; uint32_t err_id;
uint32_t err_code; uint32_t err_code;
bool terminating;
} *sftpc_state_t; } *sftpc_state_t;
enum sftp_handle_type { enum sftp_handle_type {
......
...@@ -69,6 +69,9 @@ sftpc_finish(sftpc_state_t state) ...@@ -69,6 +69,9 @@ sftpc_finish(sftpc_state_t state)
assert(state); assert(state);
if (state == NULL) if (state == NULL)
return; return;
pthread_mutex_lock(&state->mtx);
state->terminating = true;
pthread_mutex_unlock(&state->mtx);
// TODO: Close all open handles // TODO: Close all open handles
while (!CloseEvent(state->recv_event)) { while (!CloseEvent(state->recv_event)) {
assert(errno == EBUSY); assert(errno == EBUSY);
...@@ -77,8 +80,16 @@ sftpc_finish(sftpc_state_t state) ...@@ -77,8 +80,16 @@ sftpc_finish(sftpc_state_t state)
SetEvent(state->recv_event); SetEvent(state->recv_event);
SLEEP(1); 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_rx_pkt(state->rxp);
sftp_free_tx_pkt(state->txp); sftp_free_tx_pkt(state->txp);
pthread_mutex_unlock(&state->mtx);
pthread_mutex_destroy(&state->mtx);
free(state); free(state);
} }
...@@ -100,6 +111,9 @@ sftpc_begin(bool (*send_cb)(uint8_t *buf, size_t len, void *cb_data), void *cb_d ...@@ -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->id = 0;
ret->err_lang = NULL; ret->err_lang = NULL;
ret->err_msg = NULL; ret->err_msg = NULL;
ret->running = 0;
pthread_mutex_init(&ret->mtx, NULL);
ret->terminating = false;
return ret; return ret;
} }
...@@ -162,8 +176,12 @@ get_result(sftpc_state_t state) ...@@ -162,8 +176,12 @@ get_result(sftpc_state_t state)
return false; return false;
if (!state->send_cb(txbuf, txsz, state->cb_data)) if (!state->send_cb(txbuf, txsz, state->cb_data))
return false; 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; return false;
}
pthread_mutex_lock(&state->mtx);
if (state->rxp == NULL) if (state->rxp == NULL)
return false; return false;
if (state->rxp->type != SSH_FXP_VERSION) { if (state->rxp->type != SSH_FXP_VERSION) {
...@@ -192,201 +210,224 @@ handle_error(sftpc_state_t state) ...@@ -192,201 +210,224 @@ handle_error(sftpc_state_t state)
response_handled(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 bool
sftpc_init(sftpc_state_t state) sftpc_init(sftpc_state_t state)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return false;
if (!appendheader(state, SSH_FXP_INIT)) if (!appendheader(state, SSH_FXP_INIT))
return false; return exit_function(state, false);
if (!append32(state, SFTP_VERSION)) if (!append32(state, SFTP_VERSION))
return false; return exit_function(state, false);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
if (state->rxp->type != SSH_FXP_VERSION) if (state->rxp->type != SSH_FXP_VERSION)
return false; return exit_function(state, false);
if (get32(state) != SFTP_VERSION) { if (get32(state) != SFTP_VERSION) {
response_handled(state); response_handled(state);
return false; return exit_function(state, false);
} }
response_handled(state); response_handled(state);
state->id = 0; state->id = 0;
return true; return exit_function(state, true);
} }
bool bool
sftpc_recv(sftpc_state_t state, uint8_t *buf, uint32_t sz) sftpc_recv(sftpc_state_t state, uint8_t *buf, uint32_t sz)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return false;
if (!sftp_rx_pkt_append(&state->rxp, buf, sz)) if (!sftp_rx_pkt_append(&state->rxp, buf, sz))
return false; return exit_function(state, false);
if (sftp_have_full_pkt(state->rxp)) if (sftp_have_full_pkt(state->rxp))
SetEvent(state->recv_event); SetEvent(state->recv_event);
return true; return exit_function(state, true);
} }
bool bool
sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret) sftpc_realpath(sftpc_state_t state, char *path, sftp_str_t *ret)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return false;
assert(ret); assert(ret);
if (ret == NULL) if (ret == NULL)
return false; return exit_function(state, false);
if (*ret != NULL) if (*ret != NULL)
return false; return exit_function(state, false);
if (!appendheader(state, SSH_FXP_REALPATH)) if (!appendheader(state, SSH_FXP_REALPATH))
return false; return exit_function(state, false);
sftp_str_t pstr = sftp_strdup(path); sftp_str_t pstr = sftp_strdup(path);
if (!appendandfreestring(state, &pstr)) if (!appendandfreestring(state, &pstr))
return false; return exit_function(state, false);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
if (state->rxp->type == SSH_FXP_NAME) { if (state->rxp->type == SSH_FXP_NAME) {
if (get32(state) != 1) { if (get32(state) != 1) {
response_handled(state); response_handled(state);
return false; return exit_function(state, false);
} }
*ret = getstring(state); *ret = getstring(state);
response_handled(state); response_handled(state);
return true; return exit_function(state, true);
} }
handle_error(state); handle_error(state);
return false; return exit_function(state, 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;
} }
bool bool
sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t attr, sftp_dirhandle_t *handle) sftpc_open(sftpc_state_t state, char *path, uint32_t flags, sftp_file_attr_t attr, sftp_dirhandle_t *handle)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return exit_function(state, false);
assert(path); assert(path);
if (path == NULL) if (path == NULL)
return false; return exit_function(state, false);
assert(handle); assert(handle);
if (handle == NULL) if (handle == NULL)
return false; return exit_function(state, false);
assert(!*handle); assert(!*handle);
if (*handle != NULL) if (*handle != NULL)
return false; return exit_function(state, false);
if (!appendheader(state, SSH_FXP_OPEN)) if (!appendheader(state, SSH_FXP_OPEN))
return false; return exit_function(state, false);
sftp_str_t pstr = sftp_strdup(path); sftp_str_t pstr = sftp_strdup(path);
if (!appendandfreestring(state, &pstr)) if (!appendandfreestring(state, &pstr))
return false; return exit_function(state, false);
if (!append32(state, flags)) if (!append32(state, flags))
return false; return exit_function(state, false);
sftp_file_attr_t a = attr; sftp_file_attr_t a = attr;
if (a == NULL) { if (a == NULL) {
a = sftp_fattr_alloc(); a = sftp_fattr_alloc();
if (a == NULL) if (a == NULL)
return false; return exit_function(state, false);
} }
if (!appendfattr(state, a)) { if (!appendfattr(state, a)) {
if (a != attr) if (a != attr)
sftp_fattr_free(a); sftp_fattr_free(a);
return false; return exit_function(state, false);
} }
if (a != attr) if (a != attr)
sftp_fattr_free(a); sftp_fattr_free(a);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
if (state->rxp->type == SSH_FXP_HANDLE) { if (state->rxp->type == SSH_FXP_HANDLE) {
if (!parse_handle(state, (sftp_str_t *)handle)) { if (!parse_handle(state, (sftp_str_t *)handle)) {
response_handled(state); response_handled(state);
return false; return exit_function(state, false);
} }
response_handled(state); response_handled(state);
return true; return exit_function(state, true);
} }
handle_error(state); handle_error(state);
return false; return exit_function(state, false);
} }
bool bool
sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle) sftpc_close(sftpc_state_t state, sftp_filehandle_t *handle)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return false;
if (!appendheader(state, SSH_FXP_CLOSE)) if (!appendheader(state, SSH_FXP_CLOSE))
return false; return exit_function(state, false);
if (!appendfhandle(state, *handle)) if (!appendfhandle(state, *handle))
return false; return exit_function(state, false);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
handle_error(state); handle_error(state);
free_sftp_str(*handle); free_sftp_str(*handle);
*handle = NULL; *handle = NULL;
return state->err_code == SSH_FX_OK; return exit_function(state, state->err_code == SSH_FX_OK);
} }
bool bool
sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint32_t len, sftp_str_t *ret) sftpc_read(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, uint32_t len, sftp_str_t *ret)
{ {
if (!check_state(state)) if (!enter_function(state))
return false; return exit_function(state, false);
assert(ret); assert(ret);
if (ret == NULL) if (ret == NULL)
return false; return exit_function(state, false);
assert(*ret == NULL); assert(*ret == NULL);
if (*ret != NULL) if (*ret != NULL)
return false; return exit_function(state, false);
if (!appendheader(state, SSH_FXP_READ)) if (!appendheader(state, SSH_FXP_READ))
return false; return exit_function(state, false);
if (!appendfhandle(state, handle)) if (!appendfhandle(state, handle))
return false; return exit_function(state, false);
if (!append64(state, offset)) if (!append64(state, offset))
return false; return exit_function(state, false);
if (!append32(state, len)) if (!append32(state, len))
return false; return exit_function(state, false);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
if (state->rxp->type == SSH_FXP_DATA) { if (state->rxp->type == SSH_FXP_DATA) {
*ret = getstring(state); *ret = getstring(state);
response_handled(state); response_handled(state);
return *ret != NULL; return exit_function(state, *ret != NULL);
} }
handle_error(state); handle_error(state);
return false; return exit_function(state, false);
} }
bool bool
sftpc_write(sftpc_state_t state, sftp_filehandle_t handle, uint64_t offset, sftp_str_t data) 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; return false;
assert(data); assert(data);
if (data == NULL) if (data == NULL)
return false; return exit_function(state, false);
if (!appendheader(state, SSH_FXP_WRITE)) if (!appendheader(state, SSH_FXP_WRITE))
return false; return exit_function(state, false);
if (!appendfhandle(state, handle)) if (!appendfhandle(state, handle))
return false; return exit_function(state, false);
if (!append64(state, offset)) if (!append64(state, offset))
return false; return exit_function(state, false);
if (!appendstring(state, data)) if (!appendstring(state, data))
return false; return exit_function(state, false);
if (!get_result(state)) if (!get_result(state))
return false; return exit_function(state, false);
handle_error(state); handle_error(state);
return state->err_code == SSH_FX_OK; return exit_function(state, state->err_code == SSH_FX_OK);
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment