Quite rare case, can only happen with congestion, buffers very low and some space left in the former packet. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- server/websocket.c | 77 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/server/websocket.c b/server/websocket.c index ff0f550..4af3748 100644 --- a/server/websocket.c +++ b/server/websocket.c @@ -74,6 +74,8 @@ struct RedsWebSocket { websocket_frame_t read_frame; guint64 write_remainder; + guint8 write_header[WEBSOCKET_MAX_HEADER_SIZE]; + guint8 write_header_pos, write_header_len; void *raw_stream; websocket_read_cb_t raw_read; @@ -360,22 +362,59 @@ static void constrain_iov(struct iovec *iov, int iovcnt, } } +static int send_data_header_left(RedsWebSocket *ws) +{ + /* send the pending header */ + /* this can be tested capping the length with MIN with a small size like 3 */ + int rc = ws->raw_write(ws->raw_stream, ws->write_header + ws->write_header_pos, + ws->write_header_len - ws->write_header_pos); + if (rc <= 0) { + return rc; + } + ws->write_header_pos += rc; + + /* if header was sent now we can send data */ + if (ws->write_header_pos >= ws->write_header_len) { + int used = 1; + ws->write_remainder = extract_length(ws->write_header + used, &used); + return ws->write_header_len; + } + + /* otherwise try to send the rest later */ + errno = EAGAIN; + return -1; +} + +static int send_data_header(RedsWebSocket *ws, guint64 len) +{ + /* if we don't have a pending header fill it */ + if (ws->write_header_pos >= ws->write_header_len) { + ws->write_header_pos = 0; + ws->write_header_len = fill_header(ws->write_header, len); + } + + return send_data_header_left(ws); +} /* Write a WebSocket frame with the enclosed data out. */ int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt) { - guint8 header[WEBSOCKET_MAX_HEADER_SIZE]; guint64 len; - int rc = -1; + int rc; struct iovec *iov_out; int iov_out_cnt; int i; - int header_len; if (ws->closed) { errno = EPIPE; return -1; } + if (ws->write_header_pos < ws->write_header_len) { + rc = send_data_header_left(ws); + if (rc <= 0) { + return rc; + } + } if (ws->write_remainder > 0) { constrain_iov((struct iovec *) iov, iovcnt, &iov_out, &iov_out_cnt, ws->write_remainder); rc = ws->raw_writev(ws->raw_stream, iov_out, iov_out_cnt); @@ -397,23 +436,24 @@ int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt) iov_out[i + 1] = iov[i]; } - memset(header, 0, sizeof(header)); - header_len = fill_header(header, len); - iov_out[0].iov_len = header_len; - iov_out[0].iov_base = header; + ws->write_header_pos = 0; + ws->write_header_len = fill_header(ws->write_header, len); + 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); free(iov_out); if (rc <= 0) { return rc; } - rc -= header_len; - /* TODO this in theory can happen if we can't write the header */ - if (SPICE_UNLIKELY(rc < 0)) { - ws->closed = TRUE; - errno = EPIPE; + /* this can happen if we can't write the header */ + if (SPICE_UNLIKELY(rc < ws->write_header_len)) { + ws->write_header_pos = ws->write_header_len - rc; + errno = EAGAIN; return -1; } + ws->write_header_pos = ws->write_header_len; + rc -= ws->write_header_len; /* Key point: if we did not write out all the data, remember how much more data the client is expecting, and write that data without @@ -425,9 +465,7 @@ int websocket_writev(RedsWebSocket *ws, const struct iovec *iov, int iovcnt) int websocket_write(RedsWebSocket *ws, const void *buf, size_t len) { - guint8 header[WEBSOCKET_MAX_HEADER_SIZE]; int rc; - int header_len; if (ws->closed) { errno = EPIPE; @@ -435,18 +473,11 @@ int websocket_write(RedsWebSocket *ws, const void *buf, size_t len) } if (ws->write_remainder == 0) { - header_len = fill_header(header, len); - rc = ws->raw_write(ws->raw_stream, header, header_len); + rc = send_data_header(ws, len); if (rc <= 0) { return rc; } - if (rc != header_len) { - /* TODO - In theory, we can handle this case. In practice, - it does not occur, and does not seem to be worth - the code complexity */ - errno = EPIPE; - return -1; - } + len = ws->write_remainder; } else { len = MIN(ws->write_remainder, len); } -- 2.7.4 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/spice-devel