[Spice-devel] [PATCH 18/22] Convert existing std::runtime_error to the new Error classes

Christophe de Dinechin christophe at dinechin.org
Wed Feb 28 15:43:21 UTC 2018


From: Christophe de Dinechin <dinechin at redhat.com>

Appropriate error classes been created for the existing messages:
- ProtocolError: handles the various kinds of protocol-related errors
- MessageDataError: a form of protocol error where we want to report
  what was read and what was expected (e.g. message length error,
  version error, etc)

Signed-off-by: Christophe de Dinechin <dinechin at redhat.com>
---
 include/spice-streaming-agent/errors.hpp | 28 ++++++++++++++++++++++++++++
 src/errors.cpp                           | 12 ++++++++++++
 src/mjpeg-fallback.cpp                   | 10 ++++++----
 src/spice-streaming-agent.cpp            | 25 ++++++++++---------------
 src/unittests/test-mjpeg-fallback.cpp    |  4 ++--
 5 files changed, 58 insertions(+), 21 deletions(-)

diff --git a/include/spice-streaming-agent/errors.hpp b/include/spice-streaming-agent/errors.hpp
index 72e9910..870a0fd 100644
--- a/include/spice-streaming-agent/errors.hpp
+++ b/include/spice-streaming-agent/errors.hpp
@@ -60,6 +60,34 @@ public:
     ReadError(const char *msg, int saved_errno): IOError(msg, saved_errno) {}
 };
 
+class ProtocolError : public ReadError
+{
+public:
+    ProtocolError(const char *msg, int saved_errno = 0): ReadError(msg, saved_errno) {}
+};
+
+class MessageDataError : public ProtocolError
+{
+public:
+    MessageDataError(const char *msg, size_t received, size_t expected, int saved_errno = 0)
+        : ProtocolError(msg, saved_errno), received(received), expected(expected) {}
+    int format_message(char *buffer, size_t size) const noexcept override;
+protected:
+    size_t received;
+    size_t expected;
+};
+
+class OptionError : public Error
+{
+public:
+    OptionError(const char *msg, const char *option, const char *value)
+        : Error(msg), option(option), value(value) {}
+    int format_message(char *buffer, size_t size) const noexcept override;
+protected:
+    const char *option;
+    const char *value;
+};
+
 }} // namespace spice::streaming_agent
 
 #endif // SPICE_STREAMING_AGENT_ERRORS_HPP
diff --git a/src/errors.cpp b/src/errors.cpp
index ff25142..4dc45e4 100644
--- a/src/errors.cpp
+++ b/src/errors.cpp
@@ -59,4 +59,16 @@ int WriteError::format_message(char *buffer, size_t size) const noexcept
     return append_strerror(buffer, size, written);
 }
 
+int MessageDataError::format_message(char *buffer, size_t size) const noexcept
+{
+    int written = snprintf(buffer, size, "%s (received %zu, expected %zu)",
+                           what(), received, expected);
+    return append_strerror(buffer, size, written);
+}
+
+int OptionError::format_message(char *buffer, size_t size) const noexcept
+{
+    return snprintf(buffer, size, "%s ('%s' is not a valid %s)", what(), value, option);
+}
+
 }} // namespace spice::streaming_agent
diff --git a/src/mjpeg-fallback.cpp b/src/mjpeg-fallback.cpp
index 5758893..1a98535 100644
--- a/src/mjpeg-fallback.cpp
+++ b/src/mjpeg-fallback.cpp
@@ -7,6 +7,8 @@
 #include <config.h>
 #include "mjpeg-fallback.hpp"
 
+#include <spice-streaming-agent/errors.hpp>
+
 #include <cstring>
 #include <exception>
 #include <stdexcept>
@@ -59,7 +61,7 @@ MjpegFrameCapture::MjpegFrameCapture(const MjpegSettings& settings):
 {
     dpy = XOpenDisplay(NULL);
     if (!dpy)
-        throw std::runtime_error("Unable to initialize X11");
+        throw Error("unable to initialize X11");
 }
 
 MjpegFrameCapture::~MjpegFrameCapture()
@@ -157,16 +159,16 @@ void MjpegPlugin::ParseOptions(const ConfigureOption *options)
             try {
                 settings.fps = stoi(value);
             } catch (const std::exception &e) {
-                throw std::runtime_error("Invalid value '" + value + "' for option 'framerate'.");
+                throw OptionError("invalid mjpeg framerate", options->value, "mjpeg framerate");
             }
         } else if (name == "mjpeg.quality") {
             try {
                 settings.quality = stoi(value);
             } catch (const std::exception &e) {
-                throw std::runtime_error("Invalid value '" + value + "' for option 'mjpeg.quality'.");
+                throw OptionError("invalid mjpeg quality", options->value, "mjpeg quality");
             }
         } else {
-            throw std::runtime_error("Invalid option '" + name + "'.");
+            throw OptionError("invalid option name", options->name, "mjpeg option name");
         }
     }
 }
diff --git a/src/spice-streaming-agent.cpp b/src/spice-streaming-agent.cpp
index 9048935..35e65bb 100644
--- a/src/spice-streaming-agent.cpp
+++ b/src/spice-streaming-agent.cpp
@@ -67,7 +67,7 @@ public:
     {
         streamfd = open(name, O_RDWR);
         if (streamfd < 0) {
-            throw std::runtime_error("failed to open streaming device");
+            throw IOError("failed to open streaming device", errno);
         }
     }
     ~Stream()
@@ -352,13 +352,11 @@ void Stream::handle_stream_start_stop(uint32_t len)
     uint8_t msg[256];
 
     if (len >= sizeof(msg)) {
-        throw std::runtime_error("msg size (" + std::to_string(len) + ") is too long "
-                                 "(longer than " + std::to_string(sizeof(msg)) + ")");
+        throw MessageDataError("message is too long", len, sizeof(msg));
     }
     int n = read(streamfd, &msg, len);
     if (n != (int) len) {
-        throw std::runtime_error("read command from device FAILED -- read " + std::to_string(n) +
-                                 " expected " + std::to_string(len));
+        throw MessageDataError("read start/stop command from device failed", n, len, errno);
     }
     is_streaming = (msg[0] != 0); /* num_codecs */
     syslog(LOG_INFO, "GOT START_STOP message -- request to %s streaming\n",
@@ -374,12 +372,11 @@ void Stream::handle_stream_capabilities(uint32_t len)
     uint8_t caps[STREAM_MSG_CAPABILITIES_MAX_BYTES];
 
     if (len > sizeof(caps)) {
-        throw std::runtime_error("capability message too long");
+        throw MessageDataError("capability message too long", len, sizeof(caps));
     }
     int n = read(streamfd, caps, len);
     if (n != (int) len) {
-        throw std::runtime_error("read command from device FAILED -- read " + std::to_string(n) +
-                                 " expected " + std::to_string(len));
+        throw MessageDataError("read capabilities from device failed", n, len, errno);
     }
 
     // we currently do not support extensions so just reply so
@@ -389,7 +386,7 @@ void Stream::handle_stream_capabilities(uint32_t len)
 void Stream::handle_stream_error(uint32_t len)
 {
     // TODO read message and use it
-    throw std::runtime_error("got an error message from server");
+    throw ProtocolError("got an error message from server");
 }
 
 void Stream::read_command_from_device()
@@ -400,12 +397,10 @@ void Stream::read_command_from_device()
     std::lock_guard<std::mutex> stream_guard(mutex);
     n = read(streamfd, &hdr, sizeof(hdr));
     if (n != sizeof(hdr)) {
-        throw std::runtime_error("read command from device FAILED -- read " + std::to_string(n) +
-                                 " expected " + std::to_string(sizeof(hdr)));
+        throw MessageDataError("read command from device failed", n, sizeof(hdr), errno);
     }
     if (hdr.protocol_version != STREAM_DEVICE_PROTOCOL) {
-        throw std::runtime_error("BAD VERSION " + std::to_string(hdr.protocol_version) +
-                                 " (expected is " + std::to_string(STREAM_DEVICE_PROTOCOL) + ")");
+        throw MessageDataError("bad protocol version", hdr.protocol_version, STREAM_DEVICE_PROTOCOL);
     }
 
     switch (hdr.type) {
@@ -416,7 +411,7 @@ void Stream::read_command_from_device()
     case STREAM_TYPE_START_STOP:
         return handle_stream_start_stop(hdr.size);
     }
-    throw std::runtime_error("UNKNOWN msg of type " + std::to_string(hdr.type));
+    throw MessageDataError("unknown message type", hdr.type, 0);
 }
 
 int Stream::read_command(bool blocking)
@@ -507,7 +502,7 @@ void ConcreteAgent::CaptureLoop(Stream &stream, FrameLog &frame_log)
 
         std::unique_ptr<FrameCapture> capture(GetBestFrameCapture(stream.client_codecs()));
         if (!capture) {
-            throw std::runtime_error("cannot find a suitable capture system");
+            throw Error("cannot find a suitable capture system");
         }
 
         while (!quit_requested && stream.streaming_requested()) {
diff --git a/src/unittests/test-mjpeg-fallback.cpp b/src/unittests/test-mjpeg-fallback.cpp
index 4a152fe..704decd 100644
--- a/src/unittests/test-mjpeg-fallback.cpp
+++ b/src/unittests/test-mjpeg-fallback.cpp
@@ -35,7 +35,7 @@ SCENARIO("test parsing mjpeg plugin options", "[mjpeg][options]") {
             THEN("ParseOptions throws an exception") {
                 REQUIRE_THROWS_WITH(
                     plugin.ParseOptions(options.data()),
-                    "Invalid option 'wakaka'."
+                    "invalid option name"
                 );
             }
         }
@@ -50,7 +50,7 @@ SCENARIO("test parsing mjpeg plugin options", "[mjpeg][options]") {
             THEN("ParseOptions throws an exception") {
                 REQUIRE_THROWS_WITH(
                     plugin.ParseOptions(options.data()),
-                    "Invalid value 'toot' for option 'mjpeg.quality'."
+                    "invalid mjpeg quality"
                 );
             }
         }
-- 
2.13.5 (Apple Git-94)



More information about the Spice-devel mailing list