From 977ae916454f470780f7562b61c98718e2d0d49c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Wed, 20 Dec 2017 17:56:47 +0100 Subject: [PATCH 07/42] io: Small updates in preparation for websocket changes RH-Author: Daniel P. Berrange Message-id: <20171220175702.29663-6-berrange@redhat.com> Patchwork-id: 78459 O-Subject: [RHV-7.5 qemu-kvm-rhev PATCH v2 05/20] io: Small updates in preparation for websocket changes Bugzilla: 1518649 RH-Acked-by: John Snow RH-Acked-by: Jeffrey Cody RH-Acked-by: Miroslav Rezanina From: Brandon Carpenter Gets rid of unnecessary bit shifting and performs proper EOF checking to avoid a large number of repeated calls to recvmsg() when a client abruptly terminates a connection (bug fix). Signed-off-by: Brandon Carpenter Signed-off-by: Daniel P. Berrange (cherry picked from commit eefa3d8ef649f9055611361e2201cca49f8c3433) Signed-off-by: Miroslav Rezanina --- io/channel-websock.c | 64 ++++++++++++++++------------------------------------ 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/io/channel-websock.c b/io/channel-websock.c index 2258557..4e5afb2 100644 --- a/io/channel-websock.c +++ b/io/channel-websock.c @@ -110,13 +110,11 @@ /* Magic 7-bit length to indicate use of 64-bit payload length */ #define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127 -/* Bitmasks & shifts for accessing header fields */ +/* Bitmasks for accessing header fields */ #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f -#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN 7 -#define QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK 7 typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader; @@ -586,7 +584,7 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) return; } - header.ws.b0 = (1 << QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN) | + header.ws.b0 = QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN | (QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); if (ioc->rawoutput.offset < @@ -613,8 +611,8 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc) } -static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, - Error **errp) +static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc, + Error **errp) { unsigned char opcode, fin, has_mask; size_t header_size; @@ -633,11 +631,9 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, return QIO_CHANNEL_ERR_BLOCK; } - fin = (header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN) >> - QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN; + fin = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN; opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE; - has_mask = (header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK) >> - QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK; + has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK; payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { @@ -655,7 +651,7 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, return -1; } if (!has_mask) { - error_setg(errp, "websocket frames must be masked"); + error_setg(errp, "client websocket frames must be masked"); return -1; } if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { @@ -687,8 +683,8 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc, } -static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, - Error **errp) +static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, + Error **errp) { size_t i; size_t payload_len; @@ -729,7 +725,7 @@ static ssize_t qio_channel_websock_decode_payload(QIOChannelWebsock *ioc, buffer_reserve(&ioc->rawinput, payload_len); buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); buffer_advance(&ioc->encinput, payload_len); - return payload_len; + return 0; } @@ -809,8 +805,8 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc, if (ret < 0) { return ret; } - if (ret == 0 && - ioc->encinput.offset == 0) { + if (ret == 0 && ioc->encinput.offset == 0) { + ioc->io_eof = TRUE; return 0; } ioc->encinput.offset += ret; @@ -822,10 +818,6 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc, if (ret < 0) { return ret; } - if (ret == 0) { - ioc->io_eof = TRUE; - break; - } } ret = qio_channel_websock_decode_payload(ioc, errp); @@ -1090,14 +1082,12 @@ struct QIOChannelWebsockSource { }; static gboolean -qio_channel_websock_source_prepare(GSource *source, - gint *timeout) +qio_channel_websock_source_check(GSource *source) { QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; GIOCondition cond = 0; - *timeout = -1; - if (wsource->wioc->rawinput.offset) { + if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) { cond |= G_IO_IN; } if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { @@ -1108,19 +1098,11 @@ qio_channel_websock_source_prepare(GSource *source, } static gboolean -qio_channel_websock_source_check(GSource *source) +qio_channel_websock_source_prepare(GSource *source, + gint *timeout) { - QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; - GIOCondition cond = 0; - - if (wsource->wioc->rawinput.offset) { - cond |= G_IO_IN; - } - if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { - cond |= G_IO_OUT; - } - - return cond & wsource->condition; + *timeout = -1; + return qio_channel_websock_source_check(source); } static gboolean @@ -1130,17 +1112,9 @@ qio_channel_websock_source_dispatch(GSource *source, { QIOChannelFunc func = (QIOChannelFunc)callback; QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; - GIOCondition cond = 0; - - if (wsource->wioc->rawinput.offset) { - cond |= G_IO_IN; - } - if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { - cond |= G_IO_OUT; - } return (*func)(QIO_CHANNEL(wsource->wioc), - (cond & wsource->condition), + qio_channel_websock_source_check(source), user_data); } -- 1.8.3.1