[Spice-devel] [PATCH spice-server 10/30] Move RedsWebSocket to header

Pavel Grunt pgrunt at redhat.com
Fri Nov 25 10:21:26 UTC 2016


On Thu, 2016-11-24 at 11:12 -0500, Frediano Ziglio wrote:
> > 
> > Hi Frediano,
> > 
> > Thanks for the review, and all the hard work to tighten the code.
> > 
> > I've reviewed all 30 patches, and have done a quick dry run test,
> > and it
> > still seems to work for my use case - thanks!
> > 
> > I have to confess I didn't have the time for as detailed a review
> > as
> > perhaps it calls for; the PING implementation looks correct, but I
> > have
> > not tested it.
> > 
> > The only thing that did catch my eye was this patch.  It really
> > seems
> > like it should be combined with the 'Propagate some variable'
> > patch.
> > This patch feels like the first half of the overall job.  With
> > that
> > said, the net result looks correct to me, so I won't object to a
> > push as
> > it stands.
> > 
> 
> Yes, most of these patches could be squashed in some way.
> 
> > So, you can consider the series Acked by me.
> > 
> > Cheers,
> > 
> > Jeremy
> > 
> 
> We were discussing different things about websockets and spice-
> server:
> - use some external library like libwebsockets?
Can be an improvement (from the maintenance perspective), may be
overkill (and the work "was done").

> - is Qemu going to provide a TLS/websocket library for us? Not in
> the
>   near future;
It is not just about qemu - there are tools like XSpice, x11spice that
are working inside a machine (bare metal). (And we have the replay
utility which can be used for testing)

> - Qemu options. Currently for VNC there is a websocket option that
> enable
>   websockets on a different port. You can also specify the port.
>   But I like the idea to use the same port.

me too, it is very convenient from the client perspective

>  I would propose a websocket=same
or wsport and wssport (secure)
>   option (currently same required) so can be compatible in the
> future
>   if somebody wants to have a different port. Currently VNC use a
> single
>   port for TLS or no TLS, simply when TLS is enabled only encrypted
>   connections are accepted. I honestly prefer having 2 ports one
> encrypted
>   and the other not encrypted;
yes
> - avoid changing reds.c? Doing all in reds-stream.c seems a right
> approach
>   for consistency. Looks like not so easy. Was proposed by Pavel but
> I
>   agree could be an improvement.

- we also discussed that there are tools like websockify "translating"
tcp to websockets - my feeling is that it is not as efficient as a
direct websocket connection - I don't have numbers. I wonder if such
tool could work with the spice unix connection instead of tcp,
performance could be better (again i have no numbers but it would be 1
tcp connection instead of 2)

Personally I like the idea of providing the websocket
Pavel

> 
> Frediano
> 
> > On 11/21/2016 06:51 AM, Frediano Ziglio wrote:
> > > Intention is to make private in websockets.c and reduce
> > > changes in reds-stream.c
> > > ---
> > >  server/reds-stream.c | 40 ++++---------------------------------
> > > ---
> > >  server/websocket.c   | 42 ++++++++++++++++++++++++++++++++++---
> > > -----
> > >  server/websocket.h   | 24 +++++++++++++++++-------
> > >  3 files changed, 55 insertions(+), 51 deletions(-)
> > > 
> > > diff --git a/server/reds-stream.c b/server/reds-stream.c
> > > index b59586b..bf0cbbe 100644
> > > --- a/server/reds-stream.c
> > > +++ b/server/reds-stream.c
> > > @@ -78,17 +78,6 @@ typedef struct RedsSASL {
> > >  } RedsSASL;
> > >  #endif
> > >  
> > > -typedef struct {
> > > -    int closed;
> > > -
> > > -    websocket_frame_t read_frame;
> > > -    guint64 write_remainder;
> > > -
> > > -    ssize_t (*raw_read)(RedsStream *s, void *buf, size_t
> > > nbyte);
> > > -    ssize_t (*raw_write)(RedsStream *s, const void *buf, size_t
> > > nbyte);
> > > -    ssize_t (*raw_writev)(RedsStream *s, const struct iovec
> > > *iov, int
> > > iovcnt);
> > > -} RedsWebSocket;
> > > -
> > >  struct RedsStreamPrivate {
> > >      SSL *ssl;
> > >  
> > > @@ -1151,39 +1140,17 @@ error:
> > >  
> > >  static ssize_t stream_websocket_read(RedsStream *s, void *buf,
> > > size_t
> > >  size)
> > >  {
> > > -    int rc;
> > > -
> > > -    if (s->priv->ws->closed)
> > > -        return 0;
> > > -
> > > -    rc = websocket_read((void *)s, buf, size, &s->priv->ws-
> > > >read_frame,
> > > -        (websocket_write_cb_t) s->priv->ws->raw_read,
> > > -        (websocket_write_cb_t) s->priv->ws->raw_write);
> > > -
> > > -    if (rc == 0)
> > > -        s->priv->ws->closed = 1;
> > > -
> > > -    return rc;
> > > +    return websocket_read(s->priv->ws, buf, size);
> > >  }
> > >  
> > >  static ssize_t stream_websocket_write(RedsStream *s, const void
> > > *buf,
> > >  size_t size)
> > >  {
> > > -    if (s->priv->ws->closed) {
> > > -        errno = EPIPE;
> > > -        return -1;
> > > -    }
> > > -    return websocket_write((void *)s, buf, size,
> > > &s->priv->ws->write_remainder,
> > > -        (websocket_write_cb_t) s->priv->ws->raw_write);
> > > +    return websocket_write(s->priv->ws, buf, size);
> > >  }
> > >  
> > >  static ssize_t stream_websocket_writev(RedsStream *s, const
> > > struct iovec
> > >  *iov, int iovcnt)
> > >  {
> > > -    if (s->priv->ws->closed) {
> > > -        errno = EPIPE;
> > > -        return -1;
> > > -    }
> > > -    return websocket_writev((void *)s, (struct iovec *) iov,
> > > iovcnt,
> > > &s->priv->ws->write_remainder,
> > > -        (websocket_writev_cb_t) s->priv->ws->raw_writev);
> > > +    return websocket_writev(s->priv->ws, (struct iovec *) iov,
> > > iovcnt);
> > >  }
> > >  
> > >  /*
> > > @@ -1232,6 +1199,7 @@ bool reds_stream_is_websocket(RedsStream
> > > *stream,
> > > unsigned char *buf, int len)
> > >          if (rc == strlen(outbuf)) {
> > >              stream->priv->ws = spice_malloc0(sizeof(*stream-
> > > >priv->ws));
> > >  
> > > +            stream->priv->ws->raw_stream = stream;
> > >              stream->priv->ws->raw_read = stream->priv->read;
> > >              stream->priv->ws->raw_write = stream->priv->write;
> > >  
> > > diff --git a/server/websocket.c b/server/websocket.c
> > > index 1379487..533fc06 100644
> > > --- a/server/websocket.c
> > > +++ b/server/websocket.c
> > > @@ -216,20 +216,29 @@ static int relay_data(guint8* buf, size_t
> > > size,
> > > websocket_frame_t *frame)
> > >      return n;
> > >  }
> > >  
> > > -int websocket_read(void *opaque, guchar *buf, int size,
> > > websocket_frame_t
> > > *frame,
> > > -                    websocket_read_cb_t read_cb,
> > > -                    websocket_write_cb_t write_cb)
> > > +int websocket_read(RedsWebSocket *ws, guchar *buf, int size)
> > >  {
> > >      int n = 0;
> > >      int rc;
> > > +    websocket_frame_t *frame = &ws->read_frame;
> > > +    void *opaque = ws->raw_stream;
> > > +    websocket_read_cb_t read_cb = (websocket_read_cb_t) ws-
> > > >raw_read;
> > > +    websocket_write_cb_t write_cb = (websocket_write_cb_t) ws-
> > > >raw_write;
> > > +
> > > +    if (ws->closed) {
> > > +        return 0;
> > > +    }
> > >  
> > >      while (size > 0) {
> > >          if (! frame->frame_ready) {
> > > -            rc = read_cb(opaque, frame->header + frame-
> > > >header_pos,
> > > frame_bytes_needed(frame));
> > > +            rc = read_cb(ws->raw_stream, frame->header +
> > > frame->header_pos, frame_bytes_needed(frame));
> > >              if (rc <= 0) {
> > >                  if (n > 0 && rc == -1 && (errno == EINTR ||
> > > errno ==
> > >                  EAGAIN))
> > >                      return n;
> > >  
> > > +                if (rc == 0) {
> > > +                    ws->closed = TRUE;
> > > +                }
> > >                  return rc;
> > >              }
> > >              frame->header_pos += rc;
> > > @@ -238,6 +247,7 @@ int websocket_read(void *opaque, guchar
> > > *buf, int size,
> > > websocket_frame_t *frame
> > >          } else if (frame->type == CLOSE_FRAME) {
> > >              websocket_ack_close(opaque, write_cb);
> > >              websocket_clear_frame(frame);
> > > +            ws->closed = TRUE;
> > >              return 0;
> > >          } else if (frame->type == BINARY_FRAME) {
> > >              rc = read_cb(opaque, buf, MIN(size, frame-
> > > >expected_len -
> > >              frame->relayed));
> > > @@ -245,6 +255,9 @@ int websocket_read(void *opaque, guchar
> > > *buf, int size,
> > > websocket_frame_t *frame
> > >                  if (n > 0 && rc == -1 && (errno == EINTR ||
> > > errno ==
> > >                  EAGAIN))
> > >                      return n;
> > >  
> > > +                if (rc == 0) {
> > > +                    ws->closed = TRUE;
> > > +                }
> > >                  return rc;
> > >              }
> > >  
> > > @@ -323,8 +336,7 @@ static void constrain_iov(struct iovec *iov,
> > > int
> > > iovcnt,
> > >  
> > >  
> > >  /* Write a WebSocket frame with the enclosed data out. */
> > > -int websocket_writev(void *opaque, struct iovec *iov, int
> > > iovcnt, guint64
> > > *remainder,
> > > -         websocket_writev_cb_t writev_cb)
> > > +int websocket_writev(RedsWebSocket *ws, struct iovec *iov, int
> > > iovcnt)
> > >  {
> > >      guint8 header[WEBSOCKET_MAX_HEADER_SIZE];
> > >      guint64 len;
> > > @@ -333,7 +345,14 @@ int websocket_writev(void *opaque, struct
> > > iovec *iov,
> > > int iovcnt, guint64 *remai
> > >      int iov_out_cnt;
> > >      int i;
> > >      int header_len;
> > > +    void *opaque = ws->raw_stream;
> > > +    websocket_writev_cb_t writev_cb = (websocket_writev_cb_t)
> > > ws->raw_writev;
> > > +    guint64 *remainder = &ws->write_remainder;
> > >  
> > > +    if (ws->closed) {
> > > +        errno = EPIPE;
> > > +        return -1;
> > > +    }
> > >      if (*remainder > 0) {
> > >          constrain_iov(iov, iovcnt, &iov_out, &iov_out_cnt,
> > > *remainder);
> > >          rc = writev_cb(opaque, iov_out, iov_out_cnt);
> > > @@ -376,12 +395,19 @@ int websocket_writev(void *opaque, struct
> > > iovec *iov,
> > > int iovcnt, guint64 *remai
> > >      return rc;
> > >  }
> > >  
> > > -int websocket_write(void *opaque, const guchar *buf, int len,
> > > guint64
> > > *remainder,
> > > -         websocket_write_cb_t write_cb)
> > > +int websocket_write(RedsWebSocket *ws, const guchar *buf, int
> > > len)
> > >  {
> > >      guint8 header[WEBSOCKET_MAX_HEADER_SIZE];
> > >      int rc;
> > >      int header_len;
> > > +    void *opaque = ws->raw_stream;
> > > +    websocket_write_cb_t write_cb = (websocket_write_cb_t) ws-
> > > >raw_write;
> > > +    guint64 *remainder = &ws->write_remainder;
> > > +
> > > +    if (ws->closed) {
> > > +        errno = EPIPE;
> > > +        return -1;
> > > +    }
> > >  
> > >      if (*remainder == 0) {
> > >          header_len = fill_header(header, len);
> > > diff --git a/server/websocket.h b/server/websocket.h
> > > index 2306492..2eb3431 100644
> > > --- a/server/websocket.h
> > > +++ b/server/websocket.h
> > > @@ -17,6 +17,8 @@
> > >  
> > >  #define WEBSOCKET_MAX_HEADER_SIZE (1 + 9 + 4)
> > >  
> > > +struct RedsStream;
> > > +
> > >  typedef struct {
> > >      int type;
> > >      int masked;
> > > @@ -32,14 +34,22 @@ typedef ssize_t (*websocket_read_cb_t)(void
> > > *opaque,
> > > const void *buf, size_t nby
> > >  typedef ssize_t (*websocket_write_cb_t)(void *opaque, const
> > > void *buf,
> > >  size_t nbyte);
> > >  typedef ssize_t (*websocket_writev_cb_t)(void *opaque, struct
> > > iovec *iov,
> > >  int iovcnt);
> > >  
> > > +typedef struct {
> > > +    int closed;
> > > +
> > > +    websocket_frame_t read_frame;
> > > +    guint64 write_remainder;
> > > +
> > > +    struct RedsStream *raw_stream;
> > > +    ssize_t (*raw_read)(struct RedsStream *s, void *buf, size_t
> > > nbyte);
> > > +    ssize_t (*raw_write)(struct RedsStream *s, const void *buf,
> > > size_t
> > > nbyte);
> > > +    ssize_t (*raw_writev)(struct RedsStream *s, const struct
> > > iovec *iov,
> > > int iovcnt);
> > > +} RedsWebSocket;
> > > +
> > >  bool websocket_is_start(gchar *buf);
> > >  void websocket_create_reply(gchar *buf, gchar *outbuf);
> > > -int websocket_read(void *opaque, guchar *buf, int len,
> > > websocket_frame_t
> > > *frame,
> > > -         websocket_read_cb_t read_cb,
> > > -         websocket_write_cb_t write_cb);
> > > -int websocket_write(void *opaque, const guchar *buf, int len,
> > > guint64
> > > *remainder,
> > > -         websocket_write_cb_t write_cb);
> > > -int websocket_writev(void *opaque, struct iovec *iov, int
> > > iovcnt, guint64
> > > *remainder,
> > > -         websocket_writev_cb_t writev_cb);
> > > +int websocket_read(RedsWebSocket *ws, guchar *buf, int len);
> > > +int websocket_write(RedsWebSocket *ws, const guchar *buf, int
> > > len);
> > > +int websocket_writev(RedsWebSocket *ws, struct iovec *iov, int
> > > iovcnt);
> > >  void websocket_ack_close(void *opaque, websocket_write_cb_t
> > > write_cb);
> > >  


More information about the Spice-devel mailing list