[Spice-devel] [PATCH spice-gtk] Use an openssl BIO stream using GSocket

Hans de Goede hdegoede at redhat.com
Sun Feb 12 11:26:13 PST 2012


Looks good, ACK.

On 02/12/2012 07:04 PM, Marc-André Lureau wrote:
> Until now, the BIO object used by openssl to read&  write was using
> the socket fd directly. But the mainloop integration is done with
> GSocket.
>
> On Windows, the read/write events are cleared after
> g_socket_send()/receive() with private function
> _win32_unset_event_mask. If the glib functions aren't cleared, glib
> source will keep notifying of data available in or out. On Windows,
> this causes a busy loop when doing SSL_read() for example (glib
> POLL_IN data condition is reached and SSL_read() return needs data).
>
> Instead, openssl should read/write using GSocket methods.
> ---
>   gtk/Makefile.am     |    2 +
>   gtk/bio-gsocket.c   |  111 +++++++++++++++++++++++++++++++++++++++++++++++++++
>   gtk/bio-gsocket.h   |   30 ++++++++++++++
>   gtk/spice-channel.c |    9 ++--
>   gtk/spice-client.h  |    4 ++
>   gtk/spice-util.h    |    2 +-
>   6 files changed, 152 insertions(+), 6 deletions(-)
>   create mode 100644 gtk/bio-gsocket.c
>   create mode 100644 gtk/bio-gsocket.h
>
> diff --git a/gtk/Makefile.am b/gtk/Makefile.am
> index 9e6af17..788a145 100644
> --- a/gtk/Makefile.am
> +++ b/gtk/Makefile.am
> @@ -186,6 +186,8 @@ USB_ACL_HELPER_SRCS =
>   endif
>
>   libspice_client_glib_2_0_la_SOURCES =	\
> +	bio-gsocket.c			\
> +	bio-gsocket.h			\
>   	glib-compat.c			\
>   	glib-compat.h			\
>   	spice-audio.c			\
> diff --git a/gtk/bio-gsocket.c b/gtk/bio-gsocket.c
> new file mode 100644
> index 0000000..ce94afe
> --- /dev/null
> +++ b/gtk/bio-gsocket.c
> @@ -0,0 +1,111 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> +   Copyright (C) 2012 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see<http://www.gnu.org/licenses/>.
> +*/
> +
> +#include<string.h>
> +#include<glib.h>
> +
> +#include "spice-util.h"
> +#include "bio-gsocket.h"
> +
> +typedef struct bio_gsocket_method {
> +    BIO_METHOD method;
> +    GSocket *gsocket;
> +} bio_gsocket_method;
> +
> +#define BIO_GET_GSOCKET(bio)  (((bio_gsocket_method*)bio->method)->gsocket)
> +
> +static int bio_gsocket_bwrite(BIO *bio, const char *in, int inl)
> +{
> +    int ret;
> +    GError *error = NULL;
> +
> +    ret = g_socket_send(BIO_GET_GSOCKET(bio),
> +                        in, inl, NULL,&error);
> +    BIO_clear_retry_flags(bio);
> +
> +    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
> +        BIO_set_retry_write(bio);
> +    if (error != NULL) {
> +        g_warning("%s", error->message);
> +        g_clear_error(&error);
> +    }
> +
> +    return ret;
> +}
> +
> +static int bio_gsocket_bread(BIO *bio, char *out, int outl)
> +{
> +    int ret;
> +    GError *error = NULL;
> +
> +    ret = g_socket_receive(BIO_GET_GSOCKET(bio),
> +                           out, outl, NULL,&error);
> +    BIO_clear_retry_flags(bio);
> +
> +    if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
> +        BIO_set_retry_read(bio);
> +    else if (error != NULL) {
> +        g_warning("%s", error->message);
> +        g_clear_error(&error);
> +    }
> +
> +    return ret;
> +}
> +
> +static int bio_gsocket_destroy(BIO *bio)
> +{
> +    if (bio == NULL || bio->method == NULL)
> +        return 0;
> +
> +    SPICE_DEBUG("bio gsocket destroy");
> +    g_free(bio->method);
> +    bio->method = NULL;;
> +
> +    return 1;
> +}
> +
> +static int bio_gsocket_bputs(BIO *bio, const char *str)
> +{
> +    int n, ret;
> +
> +    n = strlen(str);
> +    ret = bio_gsocket_bwrite(bio, str, n);
> +
> +    return ret;
> +}
> +
> +G_GNUC_INTERNAL
> +BIO* bio_new_gsocket(GSocket *gsocket)
> +{
> +    BIO *bio = BIO_new_socket(g_socket_get_fd(gsocket), BIO_NOCLOSE);
> +
> +    bio_gsocket_method *bio_method = g_new(bio_gsocket_method, 1);
> +    bio_method->method = *bio->method;
> +    bio_method->gsocket = gsocket;
> +
> +    bio->method->destroy(bio);
> +    bio->method = (BIO_METHOD*)bio_method;
> +
> +    bio->method->bwrite = bio_gsocket_bwrite;
> +    bio->method->bread = bio_gsocket_bread;
> +    bio->method->bputs = bio_gsocket_bputs;
> +    bio->method->destroy = bio_gsocket_destroy;
> +
> +    return bio;
> +}
> +
> diff --git a/gtk/bio-gsocket.h b/gtk/bio-gsocket.h
> new file mode 100644
> index 0000000..7ee5e64
> --- /dev/null
> +++ b/gtk/bio-gsocket.h
> @@ -0,0 +1,30 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> +   Copyright (C) 2012 Red Hat, Inc.
> +
> +   This library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   This library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with this library; if not, see<http://www.gnu.org/licenses/>.
> +*/
> +#ifndef BIO_GSOCKET_H_
> +# define BIO_GSOCKET_H_
> +
> +#include<openssl/bio.h>
> +#include<gio/gio.h>
> +
> +G_BEGIN_DECLS
> +
> +BIO* bio_new_gsocket(GSocket *gsocket);
> +
> +G_END_DECLS
> +
> +#endif /* !BIO_GSOCKET_H_ */
> diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
> index de60363..afcee98 100644
> --- a/gtk/spice-channel.c
> +++ b/gtk/spice-channel.c
> @@ -21,6 +21,7 @@
>   #include "spice-channel-priv.h"
>   #include "spice-session-priv.h"
>   #include "spice-marshal.h"
> +#include "bio-gsocket.h"
>
>   #include<openssl/rsa.h>
>   #include<openssl/evp.h>
> @@ -2156,13 +2157,11 @@ reconnect:
>               g_critical("SSL_new failed");
>               goto cleanup;
>           }
> -        rc = SSL_set_fd(c->ssl, g_socket_get_fd(c->sock));
> -        if (rc<= 0) {
> -            g_critical("SSL_set_fd failed");
> -            goto cleanup;
> -        }
>
>
> +        BIO *bio = bio_new_gsocket(c->sock);
> +        SSL_set_bio(c->ssl, bio, bio);
> +
>           {
>               guint8 *pubkey;
>               guint pubkey_len;
> diff --git a/gtk/spice-client.h b/gtk/spice-client.h
> index e77c970..2d7c622 100644
> --- a/gtk/spice-client.h
> +++ b/gtk/spice-client.h
> @@ -45,6 +45,8 @@
>   #include "usb-device-manager.h"
>   #include "spice-audio.h"
>
> +G_BEGIN_DECLS
> +
>   #define SPICE_CLIENT_ERROR spice_client_error_quark()
>
>   /**
> @@ -60,4 +62,6 @@ typedef enum
>
>   GQuark spice_client_error_quark(void);
>
> +G_END_DECLS
> +
>   #endif /* __SPICE_CLIENT_CLIENT_H__ */
> diff --git a/gtk/spice-util.h b/gtk/spice-util.h
> index 5029bc1..aace4b6 100644
> --- a/gtk/spice-util.h
> +++ b/gtk/spice-util.h
> @@ -18,7 +18,7 @@
>   #ifndef SPICE_UTIL_H
>   #define SPICE_UTIL_H
>
> -#include<glib.h>
> +#include<glib-object.h>
>
>   G_BEGIN_DECLS
>


More information about the Spice-devel mailing list