Commit eefa3d8e authored by Brandon Carpenter's avatar Brandon Carpenter Committed by Daniel P. Berrangé
Browse files

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: default avatarBrandon Carpenter <brandon.carpenter@cypherpath.com>
Signed-off-by: default avatarDaniel P. Berrange <berrange@redhat.com>
parent a75d6f07
Loading
Loading
Loading
Loading
+19 −45
Original line number Diff line number Diff line
@@ -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,7 +611,7 @@ 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)
{
    unsigned char opcode, fin, has_mask;
@@ -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,7 +683,7 @@ 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)
{
    size_t i;
@@ -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);
}