io: Small updates in preparation for websocket changes

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 <brandon.carpenter@cypherpath.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Brandon Carpenter 2017-09-12 08:21:48 -07:00 committed by Daniel P. Berrange
parent a75d6f0761
commit eefa3d8ef6
1 changed files with 19 additions and 45 deletions

View File

@ -110,13 +110,11 @@
/* Magic 7-bit length to indicate use of 64-bit payload length */ /* Magic 7-bit length to indicate use of 64-bit payload length */
#define QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT 127 #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_FIN 0x80
#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE 0x0f
#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80 #define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK 0x80
#define QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN 0x7f #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; typedef struct QIOChannelWebsockHeader QIOChannelWebsockHeader;
@ -586,7 +584,7 @@ static void qio_channel_websock_encode(QIOChannelWebsock *ioc)
return; 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_OPCODE_BINARY_FRAME &
QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE); QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE);
if (ioc->rawoutput.offset < 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, static int qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
Error **errp) Error **errp)
{ {
unsigned char opcode, fin, has_mask; unsigned char opcode, fin, has_mask;
size_t header_size; size_t header_size;
@ -633,11 +631,9 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
return QIO_CHANNEL_ERR_BLOCK; return QIO_CHANNEL_ERR_BLOCK;
} }
fin = (header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN) >> fin = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_FIN;
QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_FIN;
opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE; opcode = header->b0 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE;
has_mask = (header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK) >> has_mask = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_HAS_MASK;
QIO_CHANNEL_WEBSOCK_HEADER_SHIFT_HAS_MASK;
payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN; payload_len = header->b1 & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_PAYLOAD_LEN;
if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) { if (opcode == QIO_CHANNEL_WEBSOCK_OPCODE_CLOSE) {
@ -655,7 +651,7 @@ static ssize_t qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
return -1; return -1;
} }
if (!has_mask) { if (!has_mask) {
error_setg(errp, "websocket frames must be masked"); error_setg(errp, "client websocket frames must be masked");
return -1; return -1;
} }
if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) { 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, static int qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
Error **errp) Error **errp)
{ {
size_t i; size_t i;
size_t payload_len; 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_reserve(&ioc->rawinput, payload_len);
buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len); buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len);
buffer_advance(&ioc->encinput, 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) { if (ret < 0) {
return ret; return ret;
} }
if (ret == 0 && if (ret == 0 && ioc->encinput.offset == 0) {
ioc->encinput.offset == 0) { ioc->io_eof = TRUE;
return 0; return 0;
} }
ioc->encinput.offset += ret; ioc->encinput.offset += ret;
@ -822,10 +818,6 @@ static ssize_t qio_channel_websock_read_wire(QIOChannelWebsock *ioc,
if (ret < 0) { if (ret < 0) {
return ret; return ret;
} }
if (ret == 0) {
ioc->io_eof = TRUE;
break;
}
} }
ret = qio_channel_websock_decode_payload(ioc, errp); ret = qio_channel_websock_decode_payload(ioc, errp);
@ -1090,14 +1082,12 @@ struct QIOChannelWebsockSource {
}; };
static gboolean static gboolean
qio_channel_websock_source_prepare(GSource *source, qio_channel_websock_source_check(GSource *source)
gint *timeout)
{ {
QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source;
GIOCondition cond = 0; GIOCondition cond = 0;
*timeout = -1;
if (wsource->wioc->rawinput.offset) { if (wsource->wioc->rawinput.offset || wsource->wioc->io_eof) {
cond |= G_IO_IN; cond |= G_IO_IN;
} }
if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) { if (wsource->wioc->rawoutput.offset < QIO_CHANNEL_WEBSOCK_MAX_BUFFER) {
@ -1108,19 +1098,11 @@ qio_channel_websock_source_prepare(GSource *source,
} }
static gboolean static gboolean
qio_channel_websock_source_check(GSource *source) qio_channel_websock_source_prepare(GSource *source,
gint *timeout)
{ {
QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; *timeout = -1;
GIOCondition cond = 0; return qio_channel_websock_source_check(source);
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;
} }
static gboolean static gboolean
@ -1130,17 +1112,9 @@ qio_channel_websock_source_dispatch(GSource *source,
{ {
QIOChannelFunc func = (QIOChannelFunc)callback; QIOChannelFunc func = (QIOChannelFunc)callback;
QIOChannelWebsockSource *wsource = (QIOChannelWebsockSource *)source; 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), return (*func)(QIO_CHANNEL(wsource->wioc),
(cond & wsource->condition), qio_channel_websock_source_check(source),
user_data); user_data);
} }