Browse Source

smb2: use an operation struct for all operations

Instead of using the same context from the access_sys struct.

(cherry picked from commit 3b4a40e9e3)
Signed-off-by: Thomas Guillem <thomas@gllm.fr>
pull/135/head
Thomas Guillem 5 years ago
committed by Felix Paul Kühne
parent
commit
db782849f2
  1. 219
      modules/access/smb2.c

219
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)

Loading…
Cancel
Save