diff options
author | Max Kellermann <max@musicpd.org> | 2016-09-09 15:37:06 +0200 |
---|---|---|
committer | Max Kellermann <max@musicpd.org> | 2016-09-09 18:15:01 +0200 |
commit | fc7d3f64c007672e4c01172ccb1c46d083a8abd5 (patch) | |
tree | 3c72f16ee6cc919a17558678a1e270568182b8af /src/input | |
parent | 63ab7767a37a99b5651f32e067aeb5fcbb7bd033 (diff) |
input/Plugin: migrate open() from class Error to C++ exceptions
Diffstat (limited to 'src/input')
-rw-r--r-- | src/input/AsyncInputStream.cxx | 24 | ||||
-rw-r--r-- | src/input/InputPlugin.hxx | 7 | ||||
-rw-r--r-- | src/input/InputStream.hxx | 10 | ||||
-rw-r--r-- | src/input/LocalOpen.cxx | 28 | ||||
-rw-r--r-- | src/input/LocalOpen.hxx | 5 | ||||
-rw-r--r-- | src/input/Open.cxx | 30 | ||||
-rw-r--r-- | src/input/plugins/AlsaInputPlugin.cxx | 116 | ||||
-rw-r--r-- | src/input/plugins/ArchiveInputPlugin.cxx | 19 | ||||
-rw-r--r-- | src/input/plugins/ArchiveInputPlugin.hxx | 8 | ||||
-rw-r--r-- | src/input/plugins/CdioParanoiaInputPlugin.cxx | 40 | ||||
-rw-r--r-- | src/input/plugins/CurlInputPlugin.cxx | 92 | ||||
-rw-r--r-- | src/input/plugins/FfmpegInputPlugin.cxx | 9 | ||||
-rw-r--r-- | src/input/plugins/FileInputPlugin.cxx | 32 | ||||
-rw-r--r-- | src/input/plugins/FileInputPlugin.hxx | 9 | ||||
-rw-r--r-- | src/input/plugins/MmsInputPlugin.cxx | 3 | ||||
-rw-r--r-- | src/input/plugins/NfsInputPlugin.cxx | 26 | ||||
-rw-r--r-- | src/input/plugins/SmbclientInputPlugin.cxx | 23 |
17 files changed, 221 insertions, 260 deletions
diff --git a/src/input/AsyncInputStream.cxx b/src/input/AsyncInputStream.cxx index d1445579a..d5092e42e 100644 --- a/src/input/AsyncInputStream.cxx +++ b/src/input/AsyncInputStream.cxx @@ -81,6 +81,7 @@ AsyncInputStream::Resume() if (paused) { paused = false; + DoResume(); } } @@ -264,7 +265,12 @@ AsyncInputStream::DeferredResume() { const ScopeLock protect(mutex); - Resume(); + try { + Resume(); + } catch (...) { + postponed_exception = std::current_exception(); + cond.broadcast(); + } } void @@ -274,10 +280,16 @@ AsyncInputStream::DeferredSeek() if (seek_state != SeekState::SCHEDULED) return; - Resume(); + try { + Resume(); - seek_state = SeekState::PENDING; - buffer.Clear(); - paused = false; - DoSeek(seek_offset); + seek_state = SeekState::PENDING; + buffer.Clear(); + paused = false; + + DoSeek(seek_offset); + } catch (...) { + postponed_exception = std::current_exception(); + cond.broadcast(); + } } diff --git a/src/input/InputPlugin.hxx b/src/input/InputPlugin.hxx index 08a9d42fd..d33161c93 100644 --- a/src/input/InputPlugin.hxx +++ b/src/input/InputPlugin.hxx @@ -36,7 +36,6 @@ struct ConfigBlock; class InputStream; -class Error; struct Tag; struct InputPlugin { @@ -58,9 +57,11 @@ struct InputPlugin { */ void (*finish)(); + /** + * Throws std::runtime_error on error. + */ InputStream *(*open)(const char *uri, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); }; #endif diff --git a/src/input/InputStream.hxx b/src/input/InputStream.hxx index aabbc8ef5..d93784991 100644 --- a/src/input/InputStream.hxx +++ b/src/input/InputStream.hxx @@ -115,16 +115,17 @@ public: * Opens a new input stream. You may not access it until the "ready" * flag is set. * + * Throws std::runtime_error on error. + * * @param mutex a mutex that is used to protect this object; must be * locked before calling any of the public methods * @param cond a cond that gets signalled when the state of * this object changes; may be nullptr if the caller doesn't want to get * notifications - * @return an #InputStream object on success, nullptr on error + * @return an #InputStream object on success */ gcc_nonnull_all - static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond, - Error &error); + static InputStreamPtr Open(const char *uri, Mutex &mutex, Cond &cond); /** * Just like Open(), but waits for the stream to become ready. @@ -132,8 +133,7 @@ public: */ gcc_nonnull_all static InputStreamPtr OpenReady(const char *uri, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); /** * The absolute URI which was used to open this stream. diff --git a/src/input/LocalOpen.cxx b/src/input/LocalOpen.cxx index 58bf57ee2..f5b66e96d 100644 --- a/src/input/LocalOpen.cxx +++ b/src/input/LocalOpen.cxx @@ -27,7 +27,7 @@ #endif #include "fs/Path.hxx" -#include "util/Error.hxx" +#include "system/Error.hxx" #include <assert.h> @@ -36,20 +36,24 @@ #endif InputStreamPtr -OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) +OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond) { - assert(!error.IsDefined()); + InputStreamPtr is; - InputStreamPtr is(OpenFileInputStream(path, mutex, cond, error)); #ifdef ENABLE_ARCHIVE - if (is == nullptr && error.IsDomain(errno_domain) && - error.GetCode() == ENOTDIR) { - /* ENOTDIR means this may be a path inside an archive - file */ - Error error2; - is.reset(OpenArchiveInputStream(path, mutex, cond, error2)); - if (is == nullptr && error2.IsDefined()) - error = std::move(error2); + try { +#endif + is = OpenFileInputStream(path, mutex, cond); +#ifdef ENABLE_ARCHIVE + } catch (const std::system_error &e) { + if (IsPathNotFound(e)) { + /* ENOTDIR means this may be a path inside an archive + file */ + is = OpenArchiveInputStream(path, mutex, cond); + if (!is) + throw; + } else + throw; } #endif diff --git a/src/input/LocalOpen.hxx b/src/input/LocalOpen.hxx index 787c644b3..3b8e95997 100644 --- a/src/input/LocalOpen.hxx +++ b/src/input/LocalOpen.hxx @@ -26,13 +26,14 @@ class Path; class Mutex; class Cond; -class Error; /** * Open a "local" file. This is a wrapper for the input plugins * "file" and "archive". + * + * Throws std::runtime_error on error. */ InputStreamPtr -OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); +OpenLocalInputStream(Path path, Mutex &mutex, Cond &cond); #endif diff --git a/src/input/Open.cxx b/src/input/Open.cxx index 9d52541bb..53afb5a7b 100644 --- a/src/input/Open.cxx +++ b/src/input/Open.cxx @@ -28,51 +28,51 @@ #include "fs/AllocatedPath.hxx" #include "util/Error.hxx" +#include <stdexcept> + InputStreamPtr InputStream::Open(const char *url, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (PathTraitsUTF8::IsAbsolute(url)) { + Error error; const auto path = AllocatedPath::FromUTF8(url, error); if (path.IsNull()) - return nullptr; + throw std::runtime_error(error.GetMessage()); - return OpenLocalInputStream(path, - mutex, cond, error); + return OpenLocalInputStream(path, mutex, cond); } input_plugins_for_each_enabled(plugin) { InputStream *is; - is = plugin->open(url, mutex, cond, error); + is = plugin->open(url, mutex, cond); if (is != nullptr) { is = input_rewind_open(is); return InputStreamPtr(is); - } else if (error.IsDefined()) - return nullptr; + } } - error.Set(input_domain, "Unrecognized URI"); - return nullptr; + throw std::runtime_error("Unrecognized URI"); } InputStreamPtr InputStream::OpenReady(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { - auto is = Open(uri, mutex, cond, error); - if (is == nullptr) - return nullptr; + auto is = Open(uri, mutex, cond); bool success; { const ScopeLock protect(mutex); is->WaitReady(); + + Error error; success = is->Check(error); + if (!success) + throw std::runtime_error(error.GetMessage()); } if (!success) diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx index 05098966a..70c6979d5 100644 --- a/src/input/plugins/AlsaInputPlugin.cxx +++ b/src/input/plugins/AlsaInputPlugin.cxx @@ -30,6 +30,7 @@ #include "../AsyncInputStream.hxx" #include "util/Domain.hxx" #include "util/Error.hxx" +#include "util/RuntimeError.hxx" #include "util/StringCompare.hxx" #include "util/ReusableArray.hxx" #include "util/ScopeExit.hxx" @@ -102,8 +103,7 @@ public: snd_pcm_close(capture_handle); } - static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond, - Error &error); + static InputStream *Create(const char *uri, Mutex &mutex, Cond &cond); protected: /* virtual methods from AsyncInputStream */ @@ -120,8 +120,7 @@ protected: private: static snd_pcm_t *OpenDevice(const char *device, int rate, - snd_pcm_format_t format, int channels, - Error &error); + snd_pcm_format_t format, int channels); void Pause() { AsyncInputStream::Pause(); @@ -143,8 +142,7 @@ private: }; inline InputStream * -AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond, - Error &error) +AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond) { const char *device = StringAfterPrefix(uri, "alsa://"); if (device == nullptr) @@ -160,10 +158,7 @@ AlsaInputStream::Create(const char *uri, Mutex &mutex, Cond &cond, snd_pcm_format_t format = default_format; int channels = default_channels; - snd_pcm_t *handle = OpenDevice(device, rate, format, channels, - error); - if (handle == nullptr) - return nullptr; + snd_pcm_t *handle = OpenDevice(device, rate, format, channels); int frame_size = snd_pcm_format_width(format) / 8 * channels; return new AlsaInputStream(io_thread_get(), @@ -242,47 +237,40 @@ AlsaInputStream::Recover(int err) return err; } -static bool +static void ConfigureCapture(snd_pcm_t *capture_handle, - int rate, snd_pcm_format_t format, int channels, - Error &error) + int rate, snd_pcm_format_t format, int channels) { int err; snd_pcm_hw_params_t *hw_params; - if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) { - error.Format(alsa_input_domain, "Cannot allocate hardware parameter structure (%s)", snd_strerror(err)); - return false; - } + if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0) + throw FormatRuntimeError("Cannot allocate hardware parameter structure (%s)", + snd_strerror(err)); AtScopeExit(hw_params) { snd_pcm_hw_params_free(hw_params); }; - if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) { - error.Format(alsa_input_domain, "Cannot initialize hardware parameter structure (%s)", snd_strerror(err)); - return false; - } + if ((err = snd_pcm_hw_params_any(capture_handle, hw_params)) < 0) + throw FormatRuntimeError("Cannot initialize hardware parameter structure (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { - error.Format(alsa_input_domain, "Cannot set access type (%s)", snd_strerror (err)); - return false; - } + if ((err = snd_pcm_hw_params_set_access(capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) + throw FormatRuntimeError("Cannot set access type (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) { - error.Format(alsa_input_domain, "Cannot set sample format (%s)", snd_strerror (err)); - return false; - } + if ((err = snd_pcm_hw_params_set_format(capture_handle, hw_params, format)) < 0) + throw FormatRuntimeError("Cannot set sample format (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) { - error.Format(alsa_input_domain, "Cannot set channels (%s)", snd_strerror (err)); - return false; - } + if ((err = snd_pcm_hw_params_set_channels(capture_handle, hw_params, channels)) < 0) + throw FormatRuntimeError("Cannot set channels (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, rate, 0)) < 0) { - error.Format(alsa_input_domain, "Cannot set sample rate (%s)", snd_strerror (err)); - return false; - } + if ((err = snd_pcm_hw_params_set_rate(capture_handle, hw_params, rate, 0)) < 0) + throw FormatRuntimeError("Cannot set sample rate (%s)", + snd_strerror(err)); /* period needs to be big enough so that poll() doesn't fire too often, * but small enough that buffer overruns don't occur if Read() is not @@ -293,17 +281,13 @@ ConfigureCapture(snd_pcm_t *capture_handle, snd_pcm_uframes_t period = read_buffer_size * 2; int direction = -1; if ((err = snd_pcm_hw_params_set_period_size_near(capture_handle, hw_params, - &period, &direction)) < 0) { - error.Format(alsa_input_domain, "Cannot set period size (%s)", - snd_strerror(err)); - return false; - } + &period, &direction)) < 0) + throw FormatRuntimeError("Cannot set period size (%s)", + snd_strerror(err)); - if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) { - error.Format(alsa_input_domain, "Cannot set parameters (%s)", - snd_strerror(err)); - return false; - } + if ((err = snd_pcm_hw_params(capture_handle, hw_params)) < 0) + throw FormatRuntimeError("Cannot set parameters (%s)", + snd_strerror(err)); snd_pcm_sw_params_t *sw_params; @@ -315,37 +299,31 @@ ConfigureCapture(snd_pcm_t *capture_handle, }; if ((err = snd_pcm_sw_params_set_start_threshold(capture_handle, sw_params, - period)) < 0) { - error.Format(alsa_input_domain, - "unable to set start threshold (%s)", snd_strerror(err)); - return false; - } - - if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) { - error.Format(alsa_input_domain, - "unable to install sw params (%s)", snd_strerror(err)); - return false; - } + period)) < 0) + throw FormatRuntimeError("unable to set start threshold (%s)", + snd_strerror(err)); - return true; + if ((err = snd_pcm_sw_params(capture_handle, sw_params)) < 0) + throw FormatRuntimeError("unable to install sw params (%s)", + snd_strerror(err)); } inline snd_pcm_t * AlsaInputStream::OpenDevice(const char *device, - int rate, snd_pcm_format_t format, int channels, - Error &error) + int rate, snd_pcm_format_t format, int channels) { snd_pcm_t *capture_handle; int err; if ((err = snd_pcm_open(&capture_handle, device, - SND_PCM_STREAM_CAPTURE, 0)) < 0) { - error.Format(alsa_input_domain, "Failed to open device: %s (%s)", device, snd_strerror(err)); - return nullptr; - } + SND_PCM_STREAM_CAPTURE, 0)) < 0) + throw FormatRuntimeError("Failed to open device: %s (%s)", + device, snd_strerror(err)); - if (!ConfigureCapture(capture_handle, rate, format, channels, error)) { + try { + ConfigureCapture(capture_handle, rate, format, channels); + } catch (...) { snd_pcm_close(capture_handle); - return nullptr; + throw; } snd_pcm_prepare(capture_handle); @@ -356,9 +334,9 @@ AlsaInputStream::OpenDevice(const char *device, /*######################### Plugin Functions ##############################*/ static InputStream * -alsa_input_open(const char *uri, Mutex &mutex, Cond &cond, Error &error) +alsa_input_open(const char *uri, Mutex &mutex, Cond &cond) { - return AlsaInputStream::Create(uri, mutex, cond, error); + return AlsaInputStream::Create(uri, mutex, cond); } const struct InputPlugin input_plugin_alsa = { diff --git a/src/input/plugins/ArchiveInputPlugin.cxx b/src/input/plugins/ArchiveInputPlugin.cxx index 590155d0e..3e307bfcc 100644 --- a/src/input/plugins/ArchiveInputPlugin.cxx +++ b/src/input/plugins/ArchiveInputPlugin.cxx @@ -25,14 +25,18 @@ #include "archive/ArchivePlugin.hxx" #include "archive/ArchiveFile.hxx" #include "../InputPlugin.hxx" +#include "../InputStream.hxx" #include "fs/Path.hxx" #include "Log.hxx" #include "util/ScopeExit.hxx" +#include "util/Error.hxx" + +#include <stdexcept> #include <stdlib.h> -InputStream * -OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) +InputStreamPtr +OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond) { const ArchivePlugin *arplug; @@ -57,22 +61,21 @@ OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error) return nullptr; } + Error error; auto file = archive_file_open(arplug, Path::FromFS(archive), error); - if (file == nullptr) { - return nullptr; - } + if (file == nullptr) + throw std::runtime_error(error.GetMessage()); AtScopeExit(file) { file->Close(); }; - return file->OpenStream(filename, mutex, cond, error); + return InputStreamPtr(file->OpenStream(filename, mutex, cond)); } static InputStream * input_archive_open(gcc_unused const char *filename, - gcc_unused Mutex &mutex, gcc_unused Cond &cond, - gcc_unused Error &error) + gcc_unused Mutex &mutex, gcc_unused Cond &cond) { /* dummy method; use OpenArchiveInputStream() instead */ diff --git a/src/input/plugins/ArchiveInputPlugin.hxx b/src/input/plugins/ArchiveInputPlugin.hxx index 68d369206..b248dd277 100644 --- a/src/input/plugins/ArchiveInputPlugin.hxx +++ b/src/input/plugins/ArchiveInputPlugin.hxx @@ -20,15 +20,15 @@ #ifndef MPD_INPUT_ARCHIVE_HXX #define MPD_INPUT_ARCHIVE_HXX -class InputStream; +#include "input/Ptr.hxx" + class Path; class Mutex; class Cond; -class Error; extern const struct InputPlugin input_plugin_archive; -InputStream * -OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond, Error &error); +InputStreamPtr +OpenArchiveInputStream(Path path, Mutex &mutex, Cond &cond); #endif diff --git a/src/input/plugins/CdioParanoiaInputPlugin.cxx b/src/input/plugins/CdioParanoiaInputPlugin.cxx index c9a3067f0..f06d01a10 100644 --- a/src/input/plugins/CdioParanoiaInputPlugin.cxx +++ b/src/input/plugins/CdioParanoiaInputPlugin.cxx @@ -127,7 +127,7 @@ struct cdio_uri { }; static bool -parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error) +parse_cdio_uri(struct cdio_uri *dest, const char *src) { if (!StringStartsWith(src, "cdda://")) return false; @@ -160,10 +160,8 @@ parse_cdio_uri(struct cdio_uri *dest, const char *src, Error &error) char *endptr; dest->track = strtoul(track, &endptr, 10); - if (*endptr != 0) { - error.Set(cdio_domain, "Malformed track number"); - return false; - } + if (*endptr != 0) + throw std::runtime_error("Malformed track number"); if (endptr == track) /* play the whole CD */ @@ -187,35 +185,28 @@ cdio_detect_device(void) static InputStream * input_cdio_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { struct cdio_uri parsed_uri; - if (!parse_cdio_uri(&parsed_uri, uri, error)) + if (!parse_cdio_uri(&parsed_uri, uri)) return nullptr; /* get list of CD's supporting CD-DA */ const AllocatedPath device = parsed_uri.device[0] != 0 ? AllocatedPath::FromFS(parsed_uri.device) : cdio_detect_device(); - if (device.IsNull()) { - error.Set(cdio_domain, - "Unable find or access a CD-ROM drive with an audio CD in it."); - return nullptr; - } + if (device.IsNull()) + throw std::runtime_error("Unable find or access a CD-ROM drive with an audio CD in it."); /* Found such a CD-ROM with a CD-DA loaded. Use the first drive in the list. */ const auto cdio = cdio_open(device.c_str(), DRIVER_UNKNOWN); - if (cdio == nullptr) { - error.Set(cdio_domain, "Failed to open CD drive"); - return nullptr; - } + if (cdio == nullptr) + throw std::runtime_error("Failed to open CD drive"); const auto drv = cdio_cddap_identify_cdio(cdio, 1, nullptr); if (drv == nullptr) { - error.Set(cdio_domain, "Unable to identify audio CD disc."); cdio_destroy(cdio); - return nullptr; + throw std::runtime_error("Unable to identify audio CD disc."); } cdda_verbose_set(drv, CDDA_MESSAGE_FORGETIT, CDDA_MESSAGE_FORGETIT); @@ -223,12 +214,12 @@ input_cdio_open(const char *uri, if (0 != cdio_cddap_open(drv)) { cdio_cddap_close_no_free_cdio(drv); cdio_destroy(cdio); - error.Set(cdio_domain, "Unable to open disc."); - return nullptr; + throw std::runtime_error("Unable to open disc."); } bool reverse_endian; - switch (data_bigendianp(drv)) { + const int be = data_bigendianp(drv); + switch (be) { case -1: LogDebug(cdio_domain, "drive returns unknown audio data"); reverse_endian = default_reverse_endian; @@ -245,11 +236,10 @@ input_cdio_open(const char *uri, break; default: - error.Format(cdio_domain, "Drive returns unknown data type %d", - data_bigendianp(drv)); cdio_cddap_close_no_free_cdio(drv); cdio_destroy(cdio); - return nullptr; + throw FormatRuntimeError("Drive returns unknown data type %d", + be); } lsn_t lsn_from, lsn_to; diff --git a/src/input/plugins/CurlInputPlugin.cxx b/src/input/plugins/CurlInputPlugin.cxx index 38375d2f6..2d1df3a26 100644 --- a/src/input/plugins/CurlInputPlugin.cxx +++ b/src/input/plugins/CurlInputPlugin.cxx @@ -32,6 +32,7 @@ #include "util/ASCII.hxx" #include "util/StringUtil.hxx" #include "util/NumberParser.hxx" +#include "util/RuntimeError.hxx" #include "util/Error.hxx" #include "util/Domain.hxx" #include "Log.hxx" @@ -78,17 +79,18 @@ struct CurlInputStream final : public AsyncInputStream { CURL_MAX_BUFFERED, CURL_RESUME_AT), request_headers(nullptr), - icy(new IcyInputStream(this)) {} + icy(new IcyInputStream(this)) { + InitEasy(); + } ~CurlInputStream(); CurlInputStream(const CurlInputStream &) = delete; CurlInputStream &operator=(const CurlInputStream &) = delete; - static InputStream *Open(const char *url, Mutex &mutex, Cond &cond, - Error &error); + static InputStream *Open(const char *url, Mutex &mutex, Cond &cond); - bool InitEasy(Error &error); + void InitEasy(); /** * Frees the current "libcurl easy" handle, and everything @@ -201,7 +203,7 @@ public: curl_multi_cleanup(multi); } - bool Add(CurlInputStream *c, Error &error); + void Add(CurlInputStream *c); void Remove(CurlInputStream *c); /** @@ -355,41 +357,39 @@ CurlSocket::OnSocketReady(unsigned flags) /** * Runs in the I/O thread. No lock needed. + * + * Throws std::runtime_error on error. */ -inline bool -CurlMulti::Add(CurlInputStream *c, Error &error) +inline void +CurlMulti::Add(CurlInputStream *c) { assert(io_thread_inside()); assert(c != nullptr); assert(c->easy != nullptr); CURLMcode mcode = curl_multi_add_handle(multi, c->easy); - if (mcode != CURLM_OK) { - error.Format(curlm_domain, mcode, - "curl_multi_add_handle() failed: %s", - curl_multi_strerror(mcode)); - return false; - } + if (mcode != CURLM_OK) + throw FormatRuntimeError("curl_multi_add_handle() failed: %s", + curl_multi_strerror(mcode)); InvalidateSockets(); - return true; } /** * Call input_curl_easy_add() in the I/O thread. May be called from * any thread. Caller must not hold a mutex. + * + * Throws std::runtime_error on error. */ -static bool -input_curl_easy_add_indirect(CurlInputStream *c, Error &error) +static void +input_curl_easy_add_indirect(CurlInputStream *c) { assert(c != nullptr); assert(c->easy != nullptr); - bool result; - BlockingCall(io_thread_get(), [c, &error, &result](){ - result = curl_multi->Add(c, error); + BlockingCall(io_thread_get(), [c](){ + curl_multi->Add(c); }); - return result; } inline void @@ -727,14 +727,12 @@ input_curl_writefunction(void *ptr, size_t size, size_t nmemb, void *stream) return c.DataReceived(ptr, size); } -bool -CurlInputStream::InitEasy(Error &error) +void +CurlInputStream::InitEasy() { easy = curl_easy_init(); - if (easy == nullptr) { - error.Set(curl_domain, "curl_easy_init() failed"); - return false; - } + if (easy == nullptr) + throw std::runtime_error("curl_easy_init() failed"); curl_easy_setopt(easy, CURLOPT_PRIVATE, (void *)this); curl_easy_setopt(easy, CURLOPT_USERAGENT, @@ -773,19 +771,14 @@ CurlInputStream::InitEasy(Error &error) curl_easy_setopt(easy, CURLOPT_SSL_VERIFYHOST, verify_host ? 2l : 0l); CURLcode code = curl_easy_setopt(easy, CURLOPT_URL, GetURI()); - if (code != CURLE_OK) { - error.Format(curl_domain, code, - "curl_easy_setopt() failed: %s", - curl_easy_strerror(code)); - return false; - } + if (code != CURLE_OK) + throw FormatRuntimeError("curl_easy_setopt() failed: %s", + curl_easy_strerror(code)); request_headers = nullptr; request_headers = curl_slist_append(request_headers, "Icy-Metadata: 1"); curl_easy_setopt(easy, CURLOPT_HTTPHEADER, request_headers); - - return true; } void @@ -809,11 +802,11 @@ CurlInputStream::DoSeek(offset_type new_offset) return; } - Error error; - if (!InitEasy(postponed_error)) { + try { + InitEasy(); + } catch (...) { mutex.lock(); - PostponeError(std::move(error)); - return; + throw; } /* send the "Range" header */ @@ -823,10 +816,11 @@ CurlInputStream::DoSeek(offset_type new_offset) curl_easy_setopt(easy, CURLOPT_RANGE, range); } - if (!input_curl_easy_add_indirect(this, error)) { + try { + input_curl_easy_add_indirect(this); + } catch (...) { mutex.lock(); - PostponeError(std::move(error)); - return; + throw; } mutex.lock(); @@ -834,27 +828,29 @@ CurlInputStream::DoSeek(offset_type new_offset) } inline InputStream * -CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond, - Error &error) +CurlInputStream::Open(const char *url, Mutex &mutex, Cond &cond) { CurlInputStream *c = new CurlInputStream(url, mutex, cond); - if (!c->InitEasy(error) || !input_curl_easy_add_indirect(c, error)) { + + try { + c->InitEasy(); + input_curl_easy_add_indirect(c); + } catch (...) { delete c; - return nullptr; + throw; } return c->icy; } static InputStream * -input_curl_open(const char *url, Mutex &mutex, Cond &cond, - Error &error) +input_curl_open(const char *url, Mutex &mutex, Cond &cond) { if (memcmp(url, "http://", 7) != 0 && memcmp(url, "https://", 8) != 0) return nullptr; - return CurlInputStream::Open(url, mutex, cond, error); + return CurlInputStream::Open(url, mutex, cond); } const struct InputPlugin input_plugin_curl = { diff --git a/src/input/plugins/FfmpegInputPlugin.cxx b/src/input/plugins/FfmpegInputPlugin.cxx index 1eb91f421..ab189c490 100644 --- a/src/input/plugins/FfmpegInputPlugin.cxx +++ b/src/input/plugins/FfmpegInputPlugin.cxx @@ -84,8 +84,7 @@ input_ffmpeg_init(gcc_unused const ConfigBlock &block) static InputStream * input_ffmpeg_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "gopher://") && !StringStartsWith(uri, "rtp://") && @@ -97,10 +96,8 @@ input_ffmpeg_open(const char *uri, AVIOContext *h; auto result = avio_open(&h, uri, AVIO_FLAG_READ); - if (result != 0) { - SetFfmpegError(error, result); - return nullptr; - } + if (result != 0) + throw MakeFfmpegError(result); return new FfmpegInputStream(uri, mutex, cond, h); } diff --git a/src/input/plugins/FileInputPlugin.cxx b/src/input/plugins/FileInputPlugin.cxx index 1d5eaf90e..6fb816423 100644 --- a/src/input/plugins/FileInputPlugin.cxx +++ b/src/input/plugins/FileInputPlugin.cxx @@ -21,18 +21,15 @@ #include "FileInputPlugin.hxx" #include "../InputStream.hxx" #include "../InputPlugin.hxx" -#include "util/Error.hxx" -#include "util/Domain.hxx" #include "fs/Path.hxx" #include "fs/FileInfo.hxx" #include "fs/io/FileReader.hxx" #include "system/FileDescriptor.hxx" +#include "util/RuntimeError.hxx" #include <sys/stat.h> #include <fcntl.h> -static constexpr Domain file_domain("file"); - class FileInputStream final : public InputStream { FileReader reader; @@ -56,38 +53,31 @@ public: bool Seek(offset_type offset, Error &error) override; }; -InputStream * +InputStreamPtr OpenFileInputStream(Path path, - Mutex &mutex, Cond &cond, - Error &error) -try { + Mutex &mutex, Cond &cond) +{ FileReader reader(path); const FileInfo info = reader.GetFileInfo(); - if (!info.IsRegular()) { - error.Format(file_domain, "Not a regular file: %s", - path.c_str()); - return nullptr; - } + if (!info.IsRegular()) + throw FormatRuntimeError("Not a regular file: %s", + path.c_str()); #ifdef POSIX_FADV_SEQUENTIAL posix_fadvise(reader.GetFD().Get(), (off_t)0, info.GetSize(), POSIX_FADV_SEQUENTIAL); #endif - return new FileInputStream(path.ToUTF8().c_str(), - std::move(reader), info.GetSize(), - mutex, cond); -} catch (const std::exception &e) { - error.Set(std::current_exception()); - return nullptr; + return InputStreamPtr(new FileInputStream(path.ToUTF8().c_str(), + std::move(reader), info.GetSize(), + mutex, cond)); } static InputStream * input_file_open(gcc_unused const char *filename, - gcc_unused Mutex &mutex, gcc_unused Cond &cond, - gcc_unused Error &error) + gcc_unused Mutex &mutex, gcc_unused Cond &cond) { /* dummy method; use OpenFileInputStream() instead */ diff --git a/src/input/plugins/FileInputPlugin.hxx b/src/input/plugins/FileInputPlugin.hxx index b508c9900..c967d84d6 100644 --- a/src/input/plugins/FileInputPlugin.hxx +++ b/src/input/plugins/FileInputPlugin.hxx @@ -20,17 +20,16 @@ #ifndef MPD_INPUT_FILE_HXX #define MPD_INPUT_FILE_HXX -class InputStream; +#include "input/Ptr.hxx" + class Path; class Mutex; class Cond; -class Error; extern const struct InputPlugin input_plugin_file; -InputStream * +InputStreamPtr OpenFileInputStream(Path path, - Mutex &mutex, Cond &cond, - Error &error); + Mutex &mutex, Cond &cond); #endif diff --git a/src/input/plugins/MmsInputPlugin.cxx b/src/input/plugins/MmsInputPlugin.cxx index 25af267e1..9649cc85f 100644 --- a/src/input/plugins/MmsInputPlugin.cxx +++ b/src/input/plugins/MmsInputPlugin.cxx @@ -72,8 +72,7 @@ MmsInputStream::Open(Error &error) static InputStream * input_mms_open(const char *url, - Mutex &mutex, Cond &cond, - gcc_unused Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(url, "mms://") && !StringStartsWith(url, "mmsh://") && diff --git a/src/input/plugins/NfsInputPlugin.cxx b/src/input/plugins/NfsInputPlugin.cxx index b2a9c8c30..ddacf317f 100644 --- a/src/input/plugins/NfsInputPlugin.cxx +++ b/src/input/plugins/NfsInputPlugin.cxx @@ -57,10 +57,10 @@ public: DeferClose(); } - bool Open(Error &error) { + void Open() { assert(!IsReady()); - return NfsFileReader::Open(GetURI(), error); + NfsFileReader::Open(GetURI()); } private: @@ -119,17 +119,10 @@ NfsInputStream::DoResume() reconnect_on_resume = false; reconnecting = true; - mutex.unlock(); - NfsFileReader::Close(); - - Error error; - bool success = NfsFileReader::Open(GetURI(), error); - mutex.lock(); + ScopeUnlock unlock(mutex); - if (!success) { - postponed_error = std::move(error); - cond.broadcast(); - } + NfsFileReader::Close(); + NfsFileReader::Open(GetURI()); return; } @@ -229,16 +222,17 @@ input_nfs_finish() static InputStream * input_nfs_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "nfs://")) return nullptr; NfsInputStream *is = new NfsInputStream(uri, mutex, cond); - if (!is->Open(error)) { + try { + is->Open(); + } catch (...) { delete is; - return nullptr; + throw; } return is; diff --git a/src/input/plugins/SmbclientInputPlugin.cxx b/src/input/plugins/SmbclientInputPlugin.cxx index d74afa828..7eea671f0 100644 --- a/src/input/plugins/SmbclientInputPlugin.cxx +++ b/src/input/plugins/SmbclientInputPlugin.cxx @@ -24,6 +24,7 @@ #include "../InputStream.hxx" #include "../InputPlugin.hxx" #include "PluginUnavailable.hxx" +#include "system/Error.hxx" #include "util/StringCompare.hxx" #include "util/Error.hxx" @@ -85,8 +86,7 @@ input_smbclient_init(gcc_unused const ConfigBlock &block) static InputStream * input_smbclient_open(const char *uri, - Mutex &mutex, Cond &cond, - Error &error) + Mutex &mutex, Cond &cond) { if (!StringStartsWith(uri, "smb://")) return nullptr; @@ -94,33 +94,30 @@ input_smbclient_open(const char *uri, const ScopeLock protect(smbclient_mutex); SMBCCTX *ctx = smbc_new_context(); - if (ctx == nullptr) { - error.SetErrno("smbc_new_context() failed"); - return nullptr; - } + if (ctx == nullptr) + throw MakeErrno("smbc_new_context() failed"); SMBCCTX *ctx2 = smbc_init_context(ctx); if (ctx2 == nullptr) { - error.SetErrno("smbc_init_context() failed"); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_init_context() failed"); } ctx = ctx2; int fd = smbc_open(uri, O_RDONLY, 0); if (fd < 0) { - error.SetErrno("smbc_open() failed"); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_open() failed"); } struct stat st; if (smbc_fstat(fd, &st) < 0) { - error.SetErrno("smbc_fstat() failed"); - smbc_close(fd); + int e = errno; smbc_free_context(ctx, 1); - return nullptr; + throw MakeErrno(e, "smbc_fstat() failed"); } return new SmbclientInputStream(uri, mutex, cond, ctx, fd, st); |