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@xxxxxxxxxx> --- 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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel