qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v2 6/6] io: Reply to ping frames


From: Daniel P. Berrange
Subject: Re: [Qemu-devel] [PATCH v2 6/6] io: Reply to ping frames
Date: Mon, 11 Sep 2017 18:37:43 +0100
User-agent: Mutt/1.8.3 (2017-05-23)

On Fri, Sep 08, 2017 at 10:38:01AM -0700, Brandon Carpenter wrote:
> Add an immediate ping reply (pong) to the outgoing stream when a ping
> is received. Unsolicited pongs are ignored.
> 
> Signed-off-by: Brandon Carpenter <address@hidden>
> ---
>  io/channel-websock.c | 50 ++++++++++++++++++++++++++++++++------------------
>  1 file changed, 32 insertions(+), 18 deletions(-)
> 
> diff --git a/io/channel-websock.c b/io/channel-websock.c
> index 50387050d5..175f17ce6b 100644
> --- a/io/channel-websock.c
> +++ b/io/channel-websock.c
> @@ -479,7 +479,8 @@ static gboolean 
> qio_channel_websock_handshake_io(QIOChannel *ioc,
>  }
>  
>  
> -static void qio_channel_websock_encode(QIOChannelWebsock *ioc)
> +static void qio_channel_websock_encode_buffer(QIOChannelWebsock *ioc,
> +                                              uint8_t opcode, Buffer *buffer)
>  {
>      size_t header_size;
>      union {
> @@ -487,33 +488,37 @@ static void 
> qio_channel_websock_encode(QIOChannelWebsock *ioc)
>          QIOChannelWebsockHeader ws;
>      } header;
>  
> -    if (!ioc->rawoutput.offset) {
> -        return;
> -    }
> -
>      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 <
> +        (opcode & QIO_CHANNEL_WEBSOCK_HEADER_FIELD_OPCODE);
> +    if (buffer->offset <
>          QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_7_BIT) {
> -        header.ws.b1 = (uint8_t)ioc->rawoutput.offset;
> +        header.ws.b1 = (uint8_t)buffer->offset;
>          header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_7_BIT;
> -    } else if (ioc->rawoutput.offset <
> +    } else if (buffer->offset <
>                 QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_THRESHOLD_16_BIT) {
>          header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_16_BIT;
> -        header.ws.u.s16.l16 = cpu_to_be16((uint16_t)ioc->rawoutput.offset);
> +        header.ws.u.s16.l16 = cpu_to_be16((uint16_t)buffer->offset);
>          header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_16_BIT;
>      } else {
>          header.ws.b1 = QIO_CHANNEL_WEBSOCK_PAYLOAD_LEN_MAGIC_64_BIT;
> -        header.ws.u.s64.l64 = cpu_to_be64(ioc->rawoutput.offset);
> +        header.ws.u.s64.l64 = cpu_to_be64(buffer->offset);
>          header_size = QIO_CHANNEL_WEBSOCK_HEADER_LEN_64_BIT;
>      }
>      header_size -= QIO_CHANNEL_WEBSOCK_HEADER_LEN_MASK;
>  
> -    buffer_reserve(&ioc->encoutput, header_size + ioc->rawoutput.offset);
> +    buffer_reserve(&ioc->encoutput, header_size + buffer->offset);
>      buffer_append(&ioc->encoutput, header.buf, header_size);
> -    buffer_append(&ioc->encoutput, ioc->rawoutput.buffer,
> -                  ioc->rawoutput.offset);
> +    buffer_append(&ioc->encoutput, buffer->buffer, buffer->offset);
> +}
> +
> +
> +static void qio_channel_websock_encode(QIOChannelWebsock *ioc)
> +{
> +    if (!ioc->rawoutput.offset) {
> +        return;
> +    }
> +    qio_channel_websock_encode_buffer(ioc,
> +            QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME, &ioc->rawoutput);
>      buffer_reset(&ioc->rawoutput);
>  }
>  
> @@ -558,7 +563,7 @@ static int 
> qio_channel_websock_decode_header(QIOChannelWebsock *ioc,
>      /* Websocket frame sanity check:
>       * * Fragmentation is only supported for binary frames.
>       * * All frames sent by a client MUST be masked.
> -     * * Only binary encoding is supported.
> +     * * Only binary and ping/pong encoding is supported.
>       */
>      if (!fin) {
>          if (opcode != QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) {
> @@ -619,6 +624,11 @@ static int 
> qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
>           * for purpose of unmasking, except at end of payload
>           */
>          if (ioc->encinput.offset < ioc->payload_remain) {
> +            /* Wait for the entire payload before processing control frames
> +             * because the payload will most likely be echoed back. */
> +            if (ioc->opcode & QIO_CHANNEL_WEBSOCK_CONTROL_OPCODE_MASK) {
> +                return QIO_CHANNEL_ERR_BLOCK;
> +            }
>              payload_len = ioc->encinput.offset - (ioc->encinput.offset % 4);
>          } else {
>              payload_len = ioc->payload_remain;
> @@ -641,13 +651,17 @@ static int 
> qio_channel_websock_decode_payload(QIOChannelWebsock *ioc,
>          }
>      }
>  
> -    /* Drop the payload of ping/pong packets */
>      if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_BINARY_FRAME) {
>          if (payload_len) {
> +            /* binary frames are passed on */
>              buffer_reserve(&ioc->rawinput, payload_len);
>              buffer_append(&ioc->rawinput, ioc->encinput.buffer, payload_len);
>          }
> -    }
> +    } else if (ioc->opcode == QIO_CHANNEL_WEBSOCK_OPCODE_PING) {
> +        /* ping frames produce an immediate pong reply */
> +        qio_channel_websock_encode_buffer(ioc,
> +                QIO_CHANNEL_WEBSOCK_OPCODE_PONG, &ioc->encinput);
> +    }   /* pong frames are ignored */

BTW, replying to the PING here is going to scramble the protocol if
the PING contains payload data. At the time qio_channel_websock_decode_header
is run, 'encinput' is only guaranteed to contain enough data to decode the
header.  You might be lucky and have some bytes from the payload already
read off the wire and stored in 'encinput', but equally you might have
nothing.  So you can not access 'encinput' here for your PONG reply
payload.

Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



reply via email to

[Prev in Thread] Current Thread [Next in Thread]