[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