[Spice-devel] [PATCH spice-server 21/23] websocket: Handle text data

Frediano Ziglio fziglio at redhat.com
Tue Jun 25 16:11:45 UTC 2019


Allows to specify and get frame type.
Type and flags are returned calling websocket_read and returned
calling websocket_write or websocket_writev.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 server/red-stream.c           | 12 +++++++++---
 server/tests/test-websocket.c |  6 ++++--
 server/websocket.c            | 28 ++++++++++++++++++----------
 server/websocket.h            | 20 +++++++++++++++++---
 4 files changed, 48 insertions(+), 18 deletions(-)

diff --git a/server/red-stream.c b/server/red-stream.c
index 1e0103b08..04be3af37 100644
--- a/server/red-stream.c
+++ b/server/red-stream.c
@@ -1163,17 +1163,23 @@ error:
 
 static ssize_t stream_websocket_read(RedStream *s, void *buf, size_t size)
 {
-    return websocket_read(s->priv->ws, buf, size);
+    unsigned flags;
+    int len;
+
+    do {
+        len = websocket_read(s->priv->ws, buf, size, &flags);
+    } while (len == 0 && flags != 0);
+    return len;
 }
 
 static ssize_t stream_websocket_write(RedStream *s, const void *buf, size_t size)
 {
-    return websocket_write(s->priv->ws, buf, size);
+    return websocket_write(s->priv->ws, buf, size, WEBSOCKET_BINARY_FINAL);
 }
 
 static ssize_t stream_websocket_writev(RedStream *s, const struct iovec *iov, int iovcnt)
 {
-    return websocket_writev(s->priv->ws, (struct iovec *) iov, iovcnt);
+    return websocket_writev(s->priv->ws, (struct iovec *) iov, iovcnt, WEBSOCKET_BINARY_FINAL);
 }
 
 /*
diff --git a/server/tests/test-websocket.c b/server/tests/test-websocket.c
index 6596c27ef..120a522f1 100644
--- a/server/tests/test-websocket.c
+++ b/server/tests/test-websocket.c
@@ -220,6 +220,7 @@ handle_client(int new_sock)
 
     char buffer[4096];
     size_t to_send = 0;
+    unsigned ws_flags = WEBSOCKET_BINARY_FINAL;
     while (!got_term) {
         int events = 0;
         if (sizeof(buffer) > to_send) {
@@ -231,7 +232,8 @@ handle_client(int new_sock)
         events = wait_for(new_sock, events);
         if (events & POLLIN) {
             assert(sizeof(buffer) > to_send);
-            int size = websocket_read(ws, (void *) (buffer + to_send), sizeof(buffer) - to_send);
+            int size = websocket_read(ws, (void *) (buffer + to_send), sizeof(buffer) - to_send,
+                                      &ws_flags);
 
             if (size < 0) {
                 if (errno == EIO) {
@@ -254,7 +256,7 @@ handle_client(int new_sock)
         }
 
         if (events & POLLOUT) {
-            int size = websocket_write(ws, buffer, to_send);
+            int size = websocket_write(ws, buffer, to_send, ws_flags);
 
             if (size < 0) {
                 switch (errno) {
diff --git a/server/websocket.c b/server/websocket.c
index 514e72c96..e076645d3 100644
--- a/server/websocket.c
+++ b/server/websocket.c
@@ -313,12 +313,14 @@ static void relay_data(uint8_t* buf, size_t size, websocket_frame_t *frame)
     }
 }
 
-int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t size)
+int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t size, unsigned *flags)
 {
     int n = 0;
     int rc;
     websocket_frame_t *frame = &ws->read_frame;
 
+    *flags = 0;
+
     if (ws->closed || ws->close_pending) {
         /* this avoids infinite loop in the case connection is still open and we have
          * pending data */
@@ -355,13 +357,15 @@ int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t size)
             websocket_clear_frame(frame);
             send_pending_data(ws);
             return 0;
-        } else if (frame->type == BINARY_FRAME) {
+        } else if (frame->type == BINARY_FRAME || frame->type == TEXT_FRAME) {
             rc = ws->raw_read(ws->raw_stream, buf,
                               MIN(size, frame->expected_len - frame->relayed));
             if (rc <= 0) {
                 goto read_error;
             }
 
+            *flags = frame->type;
+
             relay_data(buf, rc, frame);
             n += rc;
             buf += rc;
@@ -406,6 +410,9 @@ int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t size)
         frame->relayed += rc;
         if (frame->relayed >= frame->expected_len) {
             websocket_clear_frame(frame);
+            if (n) {
+                break;
+            }
         }
     }
 
@@ -421,12 +428,13 @@ read_error:
     return rc;
 }
 
-static int fill_header(uint8_t *header, uint64_t len)
+static int fill_header(uint8_t *header, uint64_t len, uint8_t type)
 {
     int used = 0;
     int i;
 
-    header[0] = FIN_FLAG | BINARY_FRAME;
+    type &= TYPE_MASK;
+    header[0] = FIN_FLAG | (type ? type : BINARY_FRAME);
     used++;
 
     header[1] = 0;
@@ -497,14 +505,14 @@ static int send_data_header_left(RedsWebSocket *ws)
     return -1;
 }
 
-static int send_data_header(RedsWebSocket *ws, uint64_t len)
+static int send_data_header(RedsWebSocket *ws, uint64_t len, uint8_t type)
 {
     spice_assert(ws->write_header_pos >= ws->write_header_len);
     spice_assert(ws->write_remainder == 0);
 
     /* fill a new header */
     ws->write_header_pos = 0;
-    ws->write_header_len = fill_header(ws->write_header, len);
+    ws->write_header_len = fill_header(ws->write_header, len, type);
 
     return send_data_header_left(ws);
 }
@@ -557,7 +565,7 @@ static int send_pending_data(RedsWebSocket *ws)
 }
 
 /* Write a WebSocket frame with the enclosed data out. */
-int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt)
+int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt, unsigned flags)
 {
     uint64_t len;
     int rc;
@@ -595,7 +603,7 @@ int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt)
     }
 
     ws->write_header_pos = 0;
-    ws->write_header_len = fill_header(ws->write_header, len);
+    ws->write_header_len = fill_header(ws->write_header, len, flags);
     iov_out[0].iov_len = ws->write_header_len;
     iov_out[0].iov_base = ws->write_header;
     rc = ws->raw_writev(ws->raw_stream, iov_out, iov_out_cnt);
@@ -622,7 +630,7 @@ int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt)
     return rc;
 }
 
-int websocket_write(RedsWebSocket *ws, const void *buf, size_t len)
+int websocket_write(RedsWebSocket *ws, const void *buf, size_t len, unsigned flags)
 {
     int rc;
 
@@ -636,7 +644,7 @@ int websocket_write(RedsWebSocket *ws, const void *buf, size_t len)
         return rc;
     }
     if (ws->write_remainder == 0) {
-        rc = send_data_header(ws, len);
+        rc = send_data_header(ws, len, flags);
         if (rc <= 0) {
             return rc;
         }
diff --git a/server/websocket.h b/server/websocket.h
index b586e3035..22120d939 100644
--- a/server/websocket.h
+++ b/server/websocket.h
@@ -21,9 +21,23 @@ typedef ssize_t (*websocket_writev_cb_t)(void *opaque, struct iovec *iov, int io
 
 typedef struct RedsWebSocket RedsWebSocket;
 
+enum {
+    WEBSOCKET_TEXT = 1,
+    WEBSOCKET_BINARY= 2,
+    WEBSOCKET_FINAL = 0x80,
+    WEBSOCKET_TEXT_FINAL = WEBSOCKET_TEXT | WEBSOCKET_FINAL,
+    WEBSOCKET_BINARY_FINAL = WEBSOCKET_BINARY | WEBSOCKET_FINAL,
+};
+
 RedsWebSocket *websocket_new(const void *buf, size_t len, void *stream, websocket_read_cb_t read_cb,
                              websocket_write_cb_t write_cb, websocket_writev_cb_t writev_cb);
 void websocket_free(RedsWebSocket *ws);
-int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t len);
-int websocket_write(RedsWebSocket *ws, const void *buf, size_t len);
-int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt);
+
+/**
+ * Read data from websocket.
+ * Can return 0 in case client sent an empty text/binary data, check
+ * flags to detect this.
+ */
+int websocket_read(RedsWebSocket *ws, uint8_t *buf, size_t len, unsigned *flags);
+int websocket_write(RedsWebSocket *ws, const void *buf, size_t len, unsigned flags);
+int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt, unsigned flags);
-- 
2.20.1



More information about the Spice-devel mailing list