From f6dc9bcad691c7cc7ef77bf0f92b8b5161cdf32f Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 20 Jul 2020 21:10:58 +0200 Subject: [PATCH] */smbclient: use the new API with SMBCCTX parameter As a side effect, the input plugin closes the SMB/CIFS connection after closing the file. This solves one part of https://github.com/MusicPlayerDaemon/MPD/issues/916 --- NEWS | 1 + src/input/plugins/SmbclientInputPlugin.cxx | 20 ++++----- src/lib/smbclient/Context.hxx | 40 +++++++++++++++++ .../plugins/SmbclientNeighborPlugin.cxx | 43 +++++++++++-------- src/storage/plugins/SmbclientStorage.cxx | 31 +++++++------ 5 files changed, 93 insertions(+), 42 deletions(-) diff --git a/NEWS b/NEWS index 00a676eb7..661a143f1 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ ver 0.22 (not yet released) - curl: support "charset" parameter in URI fragment - ffmpeg: allow partial reads - io_uring: new plugin for local files on Linux (using liburing) + - smbclient: close unused SMB/CIFS connections * archive - iso9660: support seeking * database diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index 9f4a148d2..08e918748 100644 --- a/src/input/plugins/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -31,15 +31,15 @@ class SmbclientInputStream final : public InputStream { SmbclientContext ctx; - int fd; + SMBCFILE *const handle; public: SmbclientInputStream(const char *_uri, Mutex &_mutex, SmbclientContext &&_ctx, - int _fd, const struct stat &st) + SMBCFILE *_handle, const struct stat &st) :InputStream(_uri, _mutex), - ctx(std::move(_ctx)), fd(_fd) + ctx(std::move(_ctx)), handle(_handle) { seekable = true; size = st.st_size; @@ -48,7 +48,7 @@ public: ~SmbclientInputStream() override { const std::lock_guard lock(smbclient_mutex); - smbc_close(fd); + ctx.Close(handle); } /* virtual methods from InputStream */ @@ -89,18 +89,18 @@ input_smbclient_open(const char *uri, const std::lock_guard protect(smbclient_mutex); - int fd = smbc_open(uri, O_RDONLY, 0); - if (fd < 0) + SMBCFILE *handle = ctx.OpenReadOnly(uri); + if (handle == nullptr) throw MakeErrno("smbc_open() failed"); struct stat st; - if (smbc_fstat(fd, &st) < 0) + if (ctx.Stat(handle, st) < 0) throw MakeErrno("smbc_fstat() failed"); return std::make_unique (std::make_unique(uri, mutex, std::move(ctx), - fd, st)); + handle, st)); } size_t @@ -112,7 +112,7 @@ SmbclientInputStream::Read(std::unique_lock &, { const ScopeUnlock unlock(mutex); const std::lock_guard lock(smbclient_mutex); - nbytes = smbc_read(fd, ptr, read_size); + nbytes = ctx.Read(handle, ptr, read_size); } if (nbytes < 0) @@ -131,7 +131,7 @@ SmbclientInputStream::Seek(std::unique_lock &, { const ScopeUnlock unlock(mutex); const std::lock_guard lock(smbclient_mutex); - result = smbc_lseek(fd, new_offset, SEEK_SET); + result = ctx.Seek(handle, new_offset); } if (result < 0) diff --git a/src/lib/smbclient/Context.hxx b/src/lib/smbclient/Context.hxx index 7d4c59f88..c892ddcc7 100644 --- a/src/lib/smbclient/Context.hxx +++ b/src/lib/smbclient/Context.hxx @@ -54,6 +54,46 @@ public: * Throws on error. */ static SmbclientContext New(); + + SMBCFILE *Open(const char *fname, int flags, mode_t mode) noexcept { + return smbc_getFunctionOpen(ctx)(ctx, fname, flags, mode); + } + + SMBCFILE *OpenReadOnly(const char *fname) noexcept { + return Open(fname, O_RDONLY, 0); + } + + ssize_t Read(SMBCFILE *file, void *buf, size_t count) noexcept { + return smbc_getFunctionRead(ctx)(ctx, file, buf, count); + } + + off_t Seek(SMBCFILE *file, off_t offset, int whence=SEEK_SET) noexcept { + return smbc_getFunctionLseek(ctx)(ctx, file, offset, whence); + } + + int Stat(const char *fname, struct stat &st) noexcept { + return smbc_getFunctionStat(ctx)(ctx, fname, &st); + } + + int Stat(SMBCFILE *file, struct stat &st) noexcept { + return smbc_getFunctionFstat(ctx)(ctx, file, &st); + } + + void Close(SMBCFILE *file) noexcept { + smbc_getFunctionClose(ctx)(ctx, file); + } + + SMBCFILE *OpenDirectory(const char *fname) noexcept { + return smbc_getFunctionOpendir(ctx)(ctx, fname); + } + + void CloseDirectory(SMBCFILE *dir) noexcept { + smbc_getFunctionClosedir(ctx)(ctx, dir); + } + + const struct smbc_dirent *ReadDirectory(SMBCFILE *dir) noexcept { + return smbc_getFunctionReaddir(ctx)(ctx, dir); + } }; #endif diff --git a/src/neighbor/plugins/SmbclientNeighborPlugin.cxx b/src/neighbor/plugins/SmbclientNeighborPlugin.cxx index b51a0b39b..ad944b003 100644 --- a/src/neighbor/plugins/SmbclientNeighborPlugin.cxx +++ b/src/neighbor/plugins/SmbclientNeighborPlugin.cxx @@ -19,6 +19,7 @@ #include "SmbclientNeighborPlugin.hxx" #include "lib/smbclient/Init.hxx" +#include "lib/smbclient/Context.hxx" #include "lib/smbclient/Domain.hxx" #include "lib/smbclient/Mutex.hxx" #include "neighbor/NeighborPlugin.hxx" @@ -56,6 +57,8 @@ class SmbclientNeighborExplorer final : public NeighborExplorer { } }; + SmbclientContext ctx = SmbclientContext::New(); + Thread thread; mutable Mutex mutex; @@ -66,7 +69,7 @@ class SmbclientNeighborExplorer final : public NeighborExplorer { bool quit; public: - explicit SmbclientNeighborExplorer(NeighborListener &_listener) noexcept + explicit SmbclientNeighborExplorer(NeighborListener &_listener) :NeighborExplorer(_listener), thread(BIND_THIS_METHOD(ThreadFunc)) {} @@ -125,21 +128,24 @@ ReadServer(NeighborExplorer::List &list, const smbc_dirent &e) noexcept } static void -ReadServers(NeighborExplorer::List &list, const char *uri) noexcept; +ReadServers(SmbclientContext &ctx, const char *uri, + NeighborExplorer::List &list) noexcept; static void -ReadWorkgroup(NeighborExplorer::List &list, const std::string &name) noexcept +ReadWorkgroup(SmbclientContext &ctx, const std::string &name, + NeighborExplorer::List &list) noexcept { std::string uri = "smb://" + name; - ReadServers(list, uri.c_str()); + ReadServers(ctx, uri.c_str(), list); } static void -ReadEntry(NeighborExplorer::List &list, const smbc_dirent &e) noexcept +ReadEntry(SmbclientContext &ctx, const smbc_dirent &e, + NeighborExplorer::List &list) noexcept { switch (e.smbc_type) { case SMBC_WORKGROUP: - ReadWorkgroup(list, std::string(e.name, e.namelen)); + ReadWorkgroup(ctx, std::string(e.name, e.namelen), list); break; case SMBC_SERVER: @@ -149,20 +155,21 @@ ReadEntry(NeighborExplorer::List &list, const smbc_dirent &e) noexcept } static void -ReadServers(NeighborExplorer::List &list, int fd) noexcept +ReadServers(SmbclientContext &ctx, SMBCFILE *handle, + NeighborExplorer::List &list) noexcept { - smbc_dirent *e; - while ((e = smbc_readdir(fd)) != nullptr) - ReadEntry(list, *e); + while (auto e = ctx.ReadDirectory(handle)) + ReadEntry(ctx, *e, list); } static void -ReadServers(NeighborExplorer::List &list, const char *uri) noexcept +ReadServers(SmbclientContext &ctx, const char *uri, + NeighborExplorer::List &list) noexcept { - int fd = smbc_opendir(uri); - if (fd >= 0) { - ReadServers(list, fd); - smbc_closedir(fd); + SMBCFILE *handle = ctx.OpenDirectory(uri); + if (handle != nullptr) { + ReadServers(ctx, handle, list); + ctx.CloseDirectory(handle); } else FormatErrno(smbclient_domain, "smbc_opendir('%s') failed", uri); @@ -170,11 +177,11 @@ ReadServers(NeighborExplorer::List &list, const char *uri) noexcept gcc_pure static NeighborExplorer::List -DetectServers() noexcept +DetectServers(SmbclientContext &ctx) noexcept { NeighborExplorer::List list; const std::lock_guard protect(smbclient_mutex); - ReadServers(list, "smb://"); + ReadServers(ctx, "smb://", list); return list; } @@ -198,7 +205,7 @@ SmbclientNeighborExplorer::Run() noexcept { const ScopeUnlock unlock(mutex); - found = DetectServers(); + found = DetectServers(ctx); } const auto found_before_begin = found.before_begin(); diff --git a/src/storage/plugins/SmbclientStorage.cxx b/src/storage/plugins/SmbclientStorage.cxx index f65c1efc1..0069d7045 100644 --- a/src/storage/plugins/SmbclientStorage.cxx +++ b/src/storage/plugins/SmbclientStorage.cxx @@ -34,14 +34,17 @@ #include class SmbclientDirectoryReader final : public StorageDirectoryReader { + SmbclientContext &ctx; const std::string base; - const unsigned handle; + SMBCFILE *const handle; const char *name; public: - SmbclientDirectoryReader(std::string &&_base, unsigned _handle) - :base(std::move(_base)), handle(_handle) {} + SmbclientDirectoryReader(SmbclientContext &_ctx, + std::string &&_base, + SMBCFILE *_handle) noexcept + :ctx(_ctx), base(std::move(_base)), handle(_handle) {} ~SmbclientDirectoryReader() override; @@ -85,13 +88,13 @@ SmbclientStorage::MapToRelativeUTF8(std::string_view uri_utf8) const noexcept } static StorageFileInfo -GetInfo(const char *path) +GetInfo(SmbclientContext &ctx, const char *path) { struct stat st; { const std::lock_guard protect(smbclient_mutex); - if (smbc_stat(path, &st) != 0) + if (ctx.Stat(path, st) != 0) throw MakeErrno("Failed to access file"); } @@ -114,7 +117,7 @@ StorageFileInfo SmbclientStorage::GetInfo(std::string_view uri_utf8, [[maybe_unused]] bool follow) { const std::string mapped = MapUTF8(uri_utf8); - return ::GetInfo(mapped.c_str()); + return ::GetInfo(ctx, mapped.c_str()); } std::unique_ptr @@ -122,16 +125,17 @@ SmbclientStorage::OpenDirectory(std::string_view uri_utf8) { std::string mapped = MapUTF8(uri_utf8); - int handle; + SMBCFILE *handle; { const std::lock_guard protect(smbclient_mutex); - handle = smbc_opendir(mapped.c_str()); - if (handle < 0) + handle = ctx.OpenDirectory(mapped.c_str()); + if (handle == nullptr) throw MakeErrno("Failed to open directory"); } - return std::make_unique(std::move(mapped), + return std::make_unique(ctx, + std::move(mapped), handle); } @@ -147,7 +151,7 @@ SkipNameFS(const char *name) noexcept SmbclientDirectoryReader::~SmbclientDirectoryReader() { const std::lock_guard lock(smbclient_mutex); - smbc_close(handle); + ctx.CloseDirectory(handle); } const char * @@ -155,8 +159,7 @@ SmbclientDirectoryReader::Read() noexcept { const std::lock_guard protect(smbclient_mutex); - struct smbc_dirent *e; - while ((e = smbc_readdir(handle)) != nullptr) { + while (auto e = ctx.ReadDirectory(handle)) { name = e->name; if (!SkipNameFS(name)) return name; @@ -169,7 +172,7 @@ StorageFileInfo SmbclientDirectoryReader::GetInfo([[maybe_unused]] bool follow) { const std::string path = PathTraitsUTF8::Build(base, name); - return ::GetInfo(path.c_str()); + return ::GetInfo(ctx, path.c_str()); } static std::unique_ptr