From db782849f2611e0ecaf18b2ea7df84a600d84e2f Mon Sep 17 00:00:00 2001 From: Thomas Guillem Date: Mon, 24 Jan 2022 11:48:03 +0100 Subject: [PATCH] smb2: use an operation struct for all operations Instead of using the same context from the access_sys struct. (cherry picked from commit 3b4a40e9e33dc00b1b18a900ef62db38170f31b8) Signed-off-by: Thomas Guillem --- modules/access/smb2.c | 219 ++++++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 92 deletions(-) diff --git a/modules/access/smb2.c b/modules/access/smb2.c index 823d92df8c..21eb280589 100644 --- a/modules/access/smb2.c +++ b/modules/access/smb2.c @@ -85,7 +85,17 @@ struct access_sys vlc_url_t encoded_url; bool eof; bool smb2_connected; + int error_status; +}; + +struct vlc_smb2_op +{ + vlc_object_t *log; + + struct smb2_context *smb2; + + int error_status; bool res_done; union { @@ -93,43 +103,56 @@ struct access_sys { size_t len; } read; + void *data; } res; }; -static int -smb2_check_status(stream_t *access, struct smb2_context *smb2, int status, const char *psz_func) +#define VLC_SMB2_OP(access, smb2_) { \ + .log = access ? VLC_OBJECT(access) : NULL, \ + .smb2 = smb2_, \ + .error_status = access ? ((struct access_sys *)access->p_sys)->error_status : 0, \ + .res_done = false, \ +}; + +static inline void +vlc_smb2_op_reset(struct vlc_smb2_op *op, struct smb2_context *smb2) { - struct access_sys *sys = access->p_sys; + op->res_done = false; + op->smb2 = smb2; + op->error_status = 0; +} +static int +smb2_check_status(struct vlc_smb2_op *op, int status, const char *psz_func) +{ if (status < 0) { - const char *psz_error = smb2_get_error(smb2); - msg_Warn(access, "%s failed: %d, '%s'", psz_func, status, psz_error); - sys->error_status = status; + const char *psz_error = smb2_get_error(op->smb2); + if (op->log) + msg_Warn(op->log, "%s failed: %d, '%s'", psz_func, status, psz_error); + op->error_status = status; return -1; } else { - sys->res_done = true; + op->res_done = true; return 0; } } static void -smb2_set_error(stream_t *access, const char *psz_func, int err) +smb2_set_error(struct vlc_smb2_op *op, const char *psz_func, int err) { - struct access_sys *sys = access->p_sys; - - msg_Err(access, "%s failed: %d, %s", psz_func, err, - smb2_get_error(sys->smb2)); - sys->error_status = err; + if (op->log) + msg_Err(op->log, "%s failed: %d, %s", psz_func, err, smb2_get_error(op->smb2)); + op->error_status = err; } -#define VLC_SMB2_CHECK_STATUS(access, smb2, status) \ - smb2_check_status(access, smb2, status, __func__) +#define VLC_SMB2_CHECK_STATUS(op, status) \ + smb2_check_status(op, status, __func__) -#define VLC_SMB2_SET_ERROR(access, func, err) \ - smb2_set_error(access, func, err) +#define VLC_SMB2_SET_ERROR(op, func, err) \ + smb2_set_error(op, func, err) #define VLC_SMB2_STATUS_DENIED(x) (x == -ECONNREFUSED || x == -EACCES) @@ -162,10 +185,9 @@ smb2_service_fd(struct smb2_context *smb2, int fd, int revents) #endif static int -vlc_smb2_mainloop(stream_t *access, struct smb2_context *smb2, bool teardown) +vlc_smb2_mainloop(struct vlc_smb2_op *op, bool teardown) { #define TEARDOWN_TIMEOUT 250 /* in ms */ - struct access_sys *sys = access->p_sys; int timeout = -1; int (*poll_func)(struct pollfd *, unsigned, int) = vlc_poll_i11e; @@ -174,7 +196,7 @@ vlc_smb2_mainloop(stream_t *access, struct smb2_context *smb2, bool teardown) * function can override the error_status (from async cbs). Therefore, * store the original error_status in order to restore it at the end of * this call (since we want to keep the first and original error status). */ - int original_error_status = sys->error_status; + int original_error_status = op->error_status; if (teardown) { @@ -183,16 +205,15 @@ vlc_smb2_mainloop(stream_t *access, struct smb2_context *smb2, bool teardown) * timeout to let a chance for a clean teardown. */ timeout = TEARDOWN_TIMEOUT; poll_func = (void *)poll; - sys->error_status = 0; + op->error_status = 0; } - sys->res_done = false; - while (sys->error_status == 0 && !sys->res_done) + while (op->error_status == 0 && !op->res_done) { int ret, smb2_timeout; size_t fd_count; - const t_socket *fds = smb2_get_fds(smb2, &fd_count, &smb2_timeout); - int events = smb2_which_events(smb2); + const t_socket *fds = smb2_get_fds(op->smb2, &fd_count, &smb2_timeout); + int events = smb2_which_events(op->smb2); struct pollfd p_fds[fd_count]; for (size_t i = 0; i < fd_count; ++i) @@ -207,7 +228,8 @@ vlc_smb2_mainloop(stream_t *access, struct smb2_context *smb2, bool teardown) { if (errno == EINTR) { - msg_Warn(access, "vlc_poll_i11e interrupted"); + if (op->log) + msg_Warn(op->log, "vlc_poll_i11e interrupted"); if (poll_func != (void *) poll) { /* Try again with a timeout to let the command complete. @@ -217,41 +239,43 @@ vlc_smb2_mainloop(stream_t *access, struct smb2_context *smb2, bool teardown) poll_func = (void *) poll; } else - sys->error_status = -errno; + op->error_status = -errno; } else { - msg_Err(access, "vlc_poll_i11e failed"); - sys->error_status = -errno; + if (op->log) + msg_Err(op->log, "vlc_poll_i11e failed"); + op->error_status = -errno; } } else if (ret == 0) { if (teardown) - sys->error_status = -ETIMEDOUT; - else if (smb2_service_fd(smb2, -1, 0) < 0) - VLC_SMB2_SET_ERROR(access, "smb2_service", 1); + op->error_status = -ETIMEDOUT; + else if (smb2_service_fd(op->smb2, -1, 0) < 0) + VLC_SMB2_SET_ERROR(op, "smb2_service", 1); } else { for (size_t i = 0; i < fd_count; ++i) { if (p_fds[i].revents - && smb2_service_fd(smb2, p_fds[i].fd, p_fds[i].revents) < 0) - VLC_SMB2_SET_ERROR(access, "smb2_service", 1); + && smb2_service_fd(op->smb2, p_fds[i].fd, p_fds[i].revents) < 0) + VLC_SMB2_SET_ERROR(op, "smb2_service", 1); } } } - int ret = sys->error_status == 0 ? 0 : -1; + int ret = op->error_status == 0 ? 0 : -1; if (original_error_status != 0) - sys->error_status = original_error_status; + op->error_status = original_error_status; return ret; } #define VLC_SMB2_GENERIC_CB() \ - stream_t *access = private_data; \ - if (VLC_SMB2_CHECK_STATUS(access, smb2, status)) \ + struct vlc_smb2_op *op = private_data; \ + assert(op->smb2 == smb2); (void) smb2; \ + if (VLC_SMB2_CHECK_STATUS(op, status)) \ return static void @@ -268,12 +292,8 @@ smb2_read_cb(struct smb2_context *smb2, int status, void *data, { VLC_UNUSED(data); VLC_SMB2_GENERIC_CB(); - struct access_sys *sys = access->p_sys; - if (status == 0) - sys->eof = true; - else - sys->res.read.len = status; + op->res.read.len = status; } static ssize_t @@ -290,18 +310,26 @@ FileRead(stream_t *access, void *buf, size_t len) if (len > 262144) len = 262144; - sys->res.read.len = 0; + struct vlc_smb2_op op = VLC_SMB2_OP(access, sys->smb2); + op.res.read.len = 0; + if (smb2_read_async(sys->smb2, sys->smb2fh, buf, len, - smb2_read_cb, access) < 0) + smb2_read_cb, &op) < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_read_async", 1); + VLC_SMB2_SET_ERROR(&op, "smb2_read_async", 1); return 0; } - if (vlc_smb2_mainloop(access, sys->smb2, false) < 0) + if (vlc_smb2_mainloop(&op, false) < 0) + { + sys->error_status = op.error_status; return 0; + } + + if (op.res.read.len == 0) + sys->eof = true; - return sys->res.read.len; + return op.res.read.len; } static int @@ -312,9 +340,12 @@ FileSeek(stream_t *access, uint64_t i_pos) if (sys->error_status != 0) return VLC_EGENERIC; - if (smb2_lseek(sys->smb2, sys->smb2fh, i_pos, SEEK_SET, NULL) < 0) + struct vlc_smb2_op op = VLC_SMB2_OP(access, sys->smb2); + + if (smb2_lseek(op.smb2, sys->smb2fh, i_pos, SEEK_SET, NULL) < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_seek_async", 1); + VLC_SMB2_SET_ERROR(&op, "smb2_seek_async", 1); + sys->error_status = op.error_status; return VLC_EGENERIC; } sys->eof = false; @@ -466,35 +497,29 @@ static int vlc_smb2_close_fh(stream_t *access, struct smb2_context *smb2, struct smb2fh *smb2fh) { - if (smb2_close_async(smb2, smb2fh, smb2_generic_cb, access) < 0) + struct vlc_smb2_op op = VLC_SMB2_OP(access, smb2); + + if (smb2_close_async(smb2, smb2fh, smb2_generic_cb, &op) < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_close_async", 1); + VLC_SMB2_SET_ERROR(&op, "smb2_close_async", 1); return -1; } - return vlc_smb2_mainloop(access, smb2, true); + return vlc_smb2_mainloop(&op, true); } static int vlc_smb2_disconnect_share(stream_t *access, struct smb2_context *smb2) { - if (smb2_disconnect_share_async(smb2, smb2_generic_cb, access) < 0) + struct vlc_smb2_op op = VLC_SMB2_OP(access, smb2); + + if (smb2_disconnect_share_async(smb2, smb2_generic_cb, &op) < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_connect_share_async", 1); + VLC_SMB2_SET_ERROR(&op, "smb2_connect_share_async", 1); return -1; } - return vlc_smb2_mainloop(access, smb2, true); -} - -static void -smb2_opendir_cb(struct smb2_context *smb2, int status, void *data, - void *private_data) -{ - VLC_SMB2_GENERIC_CB(); - struct access_sys *sys = access->p_sys; - - sys->smb2dir = data; + return vlc_smb2_mainloop(&op, true); } static void @@ -502,19 +527,8 @@ smb2_open_cb(struct smb2_context *smb2, int status, void *data, void *private_data) { VLC_SMB2_GENERIC_CB(); - struct access_sys *sys = access->p_sys; - - sys->smb2fh = data; -} - -static void -smb2_share_enum_cb(struct smb2_context *smb2, int status, void *data, - void *private_data) -{ - VLC_SMB2_GENERIC_CB(); - struct access_sys *sys = access->p_sys; - sys->share_enum = data; + op->res.data = data; } static void @@ -561,7 +575,7 @@ vlc_smb2_open_share(stream_t *access, const char *url, if (sys->smb2 == NULL) { msg_Err(access, "smb2_init_context failed"); - goto error; + return -1; } smb2_url = smb2_parse_url(sys->smb2, url); @@ -587,64 +601,85 @@ vlc_smb2_open_share(stream_t *access, const char *url, smb2_set_password(sys->smb2, password); smb2_set_domain(sys->smb2, domain ? domain : ""); + struct vlc_smb2_op op = VLC_SMB2_OP(access, sys->smb2); int err = smb2_connect_share_async(sys->smb2, smb2_url->server, share, - username, smb2_generic_cb, access); + username, smb2_generic_cb, &op); if (err < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_connect_share_async", err); + VLC_SMB2_SET_ERROR(&op, "smb2_connect_share_async", err); goto error; } - if (vlc_smb2_mainloop(access, sys->smb2, false) != 0) + if (vlc_smb2_mainloop(&op, false) != 0) goto error; sys->smb2_connected = true; vlc_smb2_print_addr(access); + vlc_smb2_op_reset(&op, sys->smb2); + struct smb2_stat_64 smb2_stat; int ret; if (do_enum) - ret = smb2_share_enum_async(sys->smb2, smb2_share_enum_cb, access); + ret = smb2_share_enum_async(sys->smb2, smb2_open_cb, &op); else { - struct smb2_stat_64 smb2_stat; if (smb2_stat_async(sys->smb2, smb2_url->path, &smb2_stat, - smb2_generic_cb, access) < 0) - VLC_SMB2_SET_ERROR(access, "smb2_stat_async", 1); + smb2_generic_cb, &op) < 0) + VLC_SMB2_SET_ERROR(&op, "smb2_stat_async", 1); - if (vlc_smb2_mainloop(access, sys->smb2, false) != 0) + if (vlc_smb2_mainloop(&op, false) != 0) goto error; if (smb2_stat.smb2_type == SMB2_TYPE_FILE) { + vlc_smb2_op_reset(&op, sys->smb2); + sys->smb2_size = smb2_stat.smb2_size; ret = smb2_open_async(sys->smb2, smb2_url->path, O_RDONLY, - smb2_open_cb, access); + smb2_open_cb, &op); } else if (smb2_stat.smb2_type == SMB2_TYPE_DIRECTORY) + { + vlc_smb2_op_reset(&op, sys->smb2); + ret = smb2_opendir_async(sys->smb2, smb2_url->path, - smb2_opendir_cb, access); + smb2_open_cb, &op); + } else { msg_Err(access, "smb2_stat_cb: file type not handled"); - sys->error_status = 1; + op.error_status = 1; goto error; } } if (ret < 0) { - VLC_SMB2_SET_ERROR(access, "smb2_open*_async", 1); + VLC_SMB2_SET_ERROR(&op, "smb2_open*_async", 1); goto error; } - if (vlc_smb2_mainloop(access, sys->smb2, false) != 0) + if (vlc_smb2_mainloop(&op, false) != 0) goto error; + + if (do_enum) + sys->share_enum = op.res.data; + else if (smb2_stat.smb2_type == SMB2_TYPE_FILE) + sys->smb2fh = op.res.data; + else if (smb2_stat.smb2_type == SMB2_TYPE_DIRECTORY) + sys->smb2dir = op.res.data; + else + vlc_assert_unreachable(); + smb2_destroy_url(smb2_url); return 0; error: if (smb2_url != NULL) smb2_destroy_url(smb2_url); + + sys->error_status = op.error_status; + if (sys->smb2 != NULL) { if (sys->smb2_connected)