From 112b3fa92266ab36dbffa2abf66034203f66b2ce Mon Sep 17 00:00:00 2001 From: Yclept Nemo Date: Fri, 22 Jun 2018 23:02:07 -0400 Subject: stream_smb: locking to bypass libsmbclient issues Thread-unsafe libsmbclient is likely to crash when used simultaneously across threads. For example, by: mpv "smb://...mkv" --sub-file "smb://...srt" Work around this by locking all calls to this library under a single global mutex. This is a temporary solution. When the libsmbclient bug [1] is fixed, switch to the code from branch [2] which uses a new api to create per-thread smb contexts. Fixes [3]. [1] https://bugzilla.samba.org/show_bug.cgi?id=11413 [2] https://github.com/orbisvicis/mpv/tree/smbclient_threaded_api [3] https://github.com/mpv-player/mpv/issues/5936 --- stream/stream_smb.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/stream/stream_smb.c b/stream/stream_smb.c index 4376f71ee6..822ffdbfb0 100644 --- a/stream/stream_smb.c +++ b/stream/stream_smb.c @@ -21,6 +21,7 @@ #include #include +#include #include "common/msg.h" #include "stream.h" @@ -31,6 +32,8 @@ #error GPL only #endif +static pthread_mutex_t smb_lock = PTHREAD_MUTEX_INITIALIZER; + struct priv { int fd; }; @@ -46,8 +49,10 @@ static int control(stream_t *s, int cmd, void *arg) { struct priv *p = s->priv; switch(cmd) { case STREAM_CTRL_GET_SIZE: { + pthread_mutex_lock(&smb_lock); off_t size = smbc_lseek(p->fd,0,SEEK_END); smbc_lseek(p->fd,s->pos,SEEK_SET); + pthread_mutex_unlock(&smb_lock); if(size != (off_t)-1) { *(int64_t *)arg = size; return 1; @@ -60,7 +65,10 @@ static int control(stream_t *s, int cmd, void *arg) { static int seek(stream_t *s,int64_t newpos) { struct priv *p = s->priv; - if(smbc_lseek(p->fd,newpos,SEEK_SET)<0) { + pthread_mutex_lock(&smb_lock); + off_t size = smbc_lseek(p->fd,newpos,SEEK_SET); + pthread_mutex_unlock(&smb_lock); + if(size<0) { return 0; } return 1; @@ -68,7 +76,9 @@ static int seek(stream_t *s,int64_t newpos) { static int fill_buffer(stream_t *s, char* buffer, int max_len){ struct priv *p = s->priv; + pthread_mutex_lock(&smb_lock); int r = smbc_read(p->fd,buffer,max_len); + pthread_mutex_unlock(&smb_lock); return (r <= 0) ? -1 : r; } @@ -77,7 +87,9 @@ static int write_buffer(stream_t *s, char* buffer, int len) { int r; int wr = 0; while (wr < len) { + pthread_mutex_lock(&smb_lock); r = smbc_write(p->fd,buffer,len); + pthread_mutex_unlock(&smb_lock); if (r <= 0) return -1; wr += r; @@ -88,7 +100,9 @@ static int write_buffer(stream_t *s, char* buffer, int len) { static void close_f(stream_t *s){ struct priv *p = s->priv; + pthread_mutex_lock(&smb_lock); smbc_close(p->fd); + pthread_mutex_unlock(&smb_lock); } static int open_f (stream_t *stream) @@ -110,13 +124,17 @@ static int open_f (stream_t *stream) return STREAM_ERROR; } + pthread_mutex_lock(&smb_lock); err = smbc_init(smb_auth_fn, 1); + pthread_mutex_unlock(&smb_lock); if (err < 0) { MP_ERR(stream, "Cannot init the libsmbclient library: %d\n",err); return STREAM_ERROR; } + pthread_mutex_lock(&smb_lock); fd = smbc_open(filename, m,0644); + pthread_mutex_unlock(&smb_lock); if (fd < 0) { MP_ERR(stream, "Could not open from LAN: '%s'\n", filename); return STREAM_ERROR; @@ -124,8 +142,10 @@ static int open_f (stream_t *stream) len = 0; if(!write) { + pthread_mutex_lock(&smb_lock); len = smbc_lseek(fd,0,SEEK_END); smbc_lseek (fd, 0, SEEK_SET); + pthread_mutex_unlock(&smb_lock); } if(len > 0 || write) { stream->seekable = true; -- cgit v1.2.3