qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Daniel P. Berrange" <berrange@redhat.com>
To: Brandon Carpenter <brandon.carpenter@cypherpath.com>
Cc: qemu-devel@nongnu.org
Subject: Re: [Qemu-devel] [PATCH v2 6/6] io: Reply to ping frames
Date: Mon, 11 Sep 2017 18:37:43 +0100	[thread overview]
Message-ID: <20170911173743.GV21444@redhat.com> (raw)
In-Reply-To: <20170908173801.15205-7-brandon.carpenter@cypherpath.com>

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 <brandon.carpenter@cypherpath.com>
> ---
>  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 :|

  parent reply	other threads:[~2017-09-11 17:37 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-07-24 18:42 [Qemu-devel] [PATCH] io: Improve websocket support by becoming more RFC compliant Brandon Carpenter
2017-07-24 18:15 ` [Qemu-devel] [PATCH] io: Always remove an old channel watch before adding a new one Brandon Carpenter
2017-07-24 21:22   ` Paolo Bonzini
2017-07-25  8:36   ` Daniel P. Berrange
2017-09-08 16:18     ` Brandon Carpenter
2017-09-08 16:22       ` Daniel P. Berrange
2017-09-08 17:37   ` [Qemu-devel] [PATCH v2 0/6] Update websocket code to more fully support the RFC Brandon Carpenter
2017-09-08 18:01     ` Eric Blake
2017-09-08 18:11       ` Brandon Carpenter
2017-09-08 18:15         ` Eric Blake
2017-09-08 17:37   ` [Qemu-devel] [PATCH v2 1/6] io: Always remove an old channel watch before adding a new one Brandon Carpenter
2017-07-25  8:38 ` [Qemu-devel] [PATCH] io: Improve websocket support by becoming more RFC compliant Daniel P. Berrange
2017-07-25 15:59   ` Brandon Carpenter
2017-09-08 17:37 ` [Qemu-devel] [PATCH v2 2/6] io: Small updates in preparation for websocket changes Brandon Carpenter
2017-09-08 17:37 ` [Qemu-devel] [PATCH v2 3/6] io: Add support for fragmented websocket binary frames Brandon Carpenter
2017-09-08 17:37 ` [Qemu-devel] [PATCH v2 4/6] io: Allow empty websocket payload Brandon Carpenter
2017-09-08 17:38 ` [Qemu-devel] [PATCH v2 5/6] io: Ignore websocket PING and PONG frames Brandon Carpenter
2017-09-11  8:38   ` Daniel P. Berrange
2017-09-11  9:04     ` Daniel P. Berrange
2017-09-08 17:38 ` [Qemu-devel] [PATCH v2 6/6] io: Reply to ping frames Brandon Carpenter
2017-09-11  8:50   ` Daniel P. Berrange
2017-09-11 17:03     ` Brandon Carpenter
2017-09-11 17:10       ` Daniel P. Berrange
2017-09-11 19:04         ` Brandon Carpenter
2017-09-12  8:57           ` Daniel P. Berrange
2017-09-11 17:37   ` Daniel P. Berrange [this message]
2017-09-11 17:43     ` Brandon Carpenter
2017-09-12  9:01       ` Daniel P. Berrange
2017-09-12 15:29         ` Brandon Carpenter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170911173743.GV21444@redhat.com \
    --to=berrange@redhat.com \
    --cc=brandon.carpenter@cypherpath.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).