[Spice-devel] [PATCH v2 22/24] Throw exception in case of write failure

Christophe de Dinechin christophe at dinechin.org
Wed Feb 21 17:46:34 UTC 2018


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

This also introduces the spice::streaming_error::Error class, which we can reuse
later as a base class for all agent-specific errors. This class provides a
formatted 'message()' class that returns a string, making it easier to format
errors without allocating memory at throw-time.

Signed-off-by: Christophe de Dinechin <dinechin at redhat.com>
---
 src/spice-streaming-agent.cpp | 65 ++++++++++++++++++++++++-------------------
 1 file changed, 36 insertions(+), 29 deletions(-)

diff --git a/src/spice-streaming-agent.cpp b/src/spice-streaming-agent.cpp
index 4aae2cb..a789aad 100644
--- a/src/spice-streaming-agent.cpp
+++ b/src/spice-streaming-agent.cpp
@@ -59,15 +59,30 @@ static uint64_t get_time(void)
 
 }
 
+class Error : public std::runtime_error
+{
+public:
+    Error(const char *msg): runtime_error(msg) {}
+    virtual std::string message() { return what(); }
+};
+
 class Stream
 {
     typedef std::set<SpiceVideoCodecType> codecs_t;
 
 public:
-    class WriteError : public std::runtime_error
+    class WriteError final : public Error
     {
     public:
-        WriteError(const char *msg): runtime_error(msg) {}
+        WriteError(const char *msg, const char *operation, int saved_errno)
+            : Error(msg), operation(operation), saved_errno(saved_errno) {}
+        std::string message()
+        {
+            return Error::message() + " in " + operation + ": " + strerror(saved_errno);
+        }
+    private:
+        const char *operation;
+        int saved_errno;
     };
 
 public:
@@ -95,18 +110,11 @@ public:
     int read_command(bool blocking);
 
     template <typename Message, typename ...PayloadArgs>
-    bool send(PayloadArgs... payload)
+    void send(PayloadArgs... payload)
     {
         Message message(payload...);
         std::lock_guard<std::mutex> stream_guard(mutex);
-        size_t expected = message.size(payload...);
-        size_t written = message.write(*this, payload...);
-        bool result = written == expected;
-        if (!result) {
-            syslog(LOG_ERR, "sent only %zu bytes out of %zu", written, expected);
-            throw WriteError("Unable to write complete packet");
-        }
-        return result;
+        message.write(*this, payload...);
     }
 
     size_t write_all(const char *what, const void *buf, const size_t len);
@@ -151,9 +159,9 @@ struct FormatMessage : Message<StreamMsgFormat, FormatMessage>
     {
         return StreamMsgFormat{ .width = w, .height = h, .codec = c, .padding1 = {} };
     }
-    size_t write(Stream &stream, unsigned w, unsigned h, uint8_t c)
+    void write(Stream &stream, unsigned w, unsigned h, uint8_t c)
     {
-        return stream.write_all("FormatMessage", this, sizeof(message_t));
+        stream.write_all("FormatMessage", this, sizeof(message_t));
     }
 };
 
@@ -170,10 +178,10 @@ struct FrameMessage : Message<StreamMsgData, FrameMessage>
     {
         return StreamMsgData();
     }
-    size_t write(Stream &stream, const void *frame, size_t length)
+    void write(Stream &stream, const void *frame, size_t length)
     {
-        return stream.write_all("FrameMessage header", this, sizeof(message_t))
-            +  stream.write_all("FrameMessage frame", frame, length);
+        stream.write_all("FrameMessage header", this, sizeof(message_t));
+        stream.write_all("FrameMessage frame", frame, length);
     }
 };
 
@@ -208,11 +216,11 @@ struct X11CursorMessage : Message<StreamMsgCursorSet, X11CursorMessage>
             .data = { }
         };
     }
-    size_t write(Stream &stream, XFixesCursorImage *cursor)
+    void write(Stream &stream, XFixesCursorImage *cursor)
     {
         unsigned pixel_size = pixel_count(cursor) * sizeof(uint32_t);
-        return stream.write_all("X11CursorMessage header", this, sizeof(message_t))
-            +  stream.write_all("X11CursorMessage pixels", pixels.get(), pixel_size);
+        stream.write_all("X11CursorMessage header", this, sizeof(message_t));
+        stream.write_all("X11CursorMessage pixels", pixels.get(), pixel_size);
     }
     void fill_pixels(XFixesCursorImage *cursor)
     {
@@ -329,9 +337,7 @@ void X11CursorThread::cursor_changes()
         }
 
         last_serial = cursor->cursor_serial;
-        if (!stream.send<X11CursorMessage>(cursor)) {
-            syslog(LOG_WARNING, "FAILED to send cursor\n");
-        }
+        stream.send<X11CursorMessage>(cursor);
     }
 }
 
@@ -462,7 +468,7 @@ size_t Stream::write_all(const char *what, const void *buf, const size_t len)
                 continue;
             }
             syslog(LOG_ERR, "write %s failed - %m", what);
-            return l;
+            throw WriteError("streaming agent write failed", what, errno);
         }
         written += l;
     }
@@ -553,16 +559,13 @@ void ConcreteAgent::CaptureLoop(Stream &stream, FrameLog &frame_log)
 
                 syslog(LOG_DEBUG, "wXh %uX%u  codec=%u\n", width, height, codec);
 
-                if (!stream.send<FormatMessage>(width, height, codec))
-                    throw std::runtime_error("FAILED to send format message");
+                stream.send<FormatMessage>(width, height, codec);
             }
             if (frame_log) {
                 frame_log.dump(frame.buffer, frame.buffer_size);
             }
-            if (!stream.send<FrameMessage>(frame.buffer, frame.buffer_size)) {
-                syslog(LOG_ERR, "FAILED to send a frame\n");
-                break;
-            }
+            stream.send<FrameMessage>(frame.buffer, frame.buffer_size);
+
             //usleep(1);
             if (stream.read_command(false) < 0) {
                 syslog(LOG_ERR, "FAILED to read command\n");
@@ -640,6 +643,10 @@ int main(int argc, char* argv[])
         FrameLog frame_log(log_filename, log_binary);
         agent.CaptureLoop(streamfd, frame_log);
     }
+    catch (Error &err) {
+        syslog(LOG_ERR, "%s\n", err.message().c_str());
+        ret = EXIT_FAILURE;
+    }
     catch (std::exception &err) {
         syslog(LOG_ERR, "%s\n", err.what());
         ret = EXIT_FAILURE;
-- 
2.13.5 (Apple Git-94)



More information about the Spice-devel mailing list