lib/nfs/Manager: add method MakeConnection()

This uses the libnfs function nfs_parse_url_dir() which means MPD
gains support for the libnfs arguments like "version".

Closes https://github.com/MusicPlayerDaemon/MPD/issues/2039
This commit is contained in:
Max Kellermann
2024-05-06 16:46:40 +02:00
parent 9947d3e67f
commit 9384bff6f9
9 changed files with 112 additions and 31 deletions

View File

@@ -26,12 +26,16 @@ extern "C" {
#include <nfsc/libnfs-raw-nfs.h>
}
#include <fmt/core.h>
#include <cassert>
#include <string>
#include <sys/stat.h>
#include <fcntl.h>
using std::string_view_literals::operator""sv;
class NfsStorage final
: public Storage, NfsLease {
@@ -39,9 +43,16 @@ class NfsStorage final
INITIAL, CONNECTING, READY, DELAY,
};
const std::string base;
/**
* The full configured URL (with all arguemnts). This is used
* to reconnect.
*/
const std::string url;
const std::string server, export_name;
/**
* The base URL for building file URLs (without arguments).
*/
const std::string base;
NfsConnection *connection;
@@ -50,18 +61,20 @@ class NfsStorage final
Mutex mutex;
Cond cond;
State state = State::INITIAL;
State state = State::CONNECTING;
std::exception_ptr last_exception;
public:
NfsStorage(EventLoop &_loop, const char *_base,
std::string_view _server, std::string_view _export_name)
:base(_base),
server(_server),
export_name(_export_name),
defer_connect(_loop, BIND_THIS_METHOD(OnDeferredConnect)),
reconnect_timer(_loop, BIND_THIS_METHOD(OnReconnectTimer)) {
nfs_init(_loop);
NfsStorage(const char *_url, NfsConnection &_connection)
:url(_url),
base(fmt::format("nfs://{}{}"sv, _connection.GetServer(), _connection.GetExportName())),
connection(&_connection),
defer_connect(_connection.GetEventLoop(), BIND_THIS_METHOD(OnDeferredConnect)),
reconnect_timer(_connection.GetEventLoop(), BIND_THIS_METHOD(OnReconnectTimer))
{
BlockingCall(GetEventLoop(), [this](){
connection->AddLease(*this);
});
}
~NfsStorage() override {
@@ -142,7 +155,7 @@ private:
assert(GetEventLoop().IsInside());
try {
connection = &nfs_get_connection(server, export_name);
connection = &nfs_make_connection(url.c_str());
} catch (...) {
SetState(State::DELAY, std::current_exception());
reconnect_timer.Schedule(std::chrono::minutes(10));
@@ -394,20 +407,20 @@ NfsStorage::OpenDirectory(std::string_view uri_utf8)
static std::unique_ptr<Storage>
CreateNfsStorageURI(EventLoop &event_loop, const char *base)
{
const char *p = StringAfterPrefixCaseASCII(base, "nfs://");
if (p == nullptr)
if (!StringStartsWithCaseASCII(base, "nfs://"sv))
return nullptr;
const char *slash = std::strchr(p, '/');
if (slash == nullptr)
throw std::runtime_error("Malformed nfs:// URI");
nfs_init(event_loop);
const std::string_view server{p, slash}, mount{slash};
try {
auto &connection = nfs_make_connection(base);
nfs_set_base(connection.GetServer(), connection.GetExportName());
nfs_set_base(server, mount);
return std::make_unique<NfsStorage>(event_loop, base,
server, mount);
return std::make_unique<NfsStorage>(base, connection);
} catch (...) {
nfs_finish();
throw;
}
}
static constexpr const char *nfs_prefixes[] = { "nfs://", nullptr };