[Spice-devel] [PATCH spice-gtk 4/5] Add NBD channel

Hans de Goede hdegoede at redhat.com
Sat Jun 8 07:35:52 PDT 2013


Hi,

Looks good, ack.

Regards,

Hans


On 06/05/2013 05:39 PM, Marc-André Lureau wrote:
> This channel implements the NBD protocol and the port events defined by
> Spice protocol.
> ---
>   doc/reference/spice-gtk-docs.xml     |   1 +
>   doc/reference/spice-gtk-sections.txt |  18 ++
>   doc/reference/spice-gtk.types        |   3 +-
>   gtk/Makefile.am                      |  16 +-
>   gtk/channel-nbd.c                    | 425 +++++++++++++++++++++++++++++++++++
>   gtk/channel-nbd.h                    |  88 ++++++++
>   gtk/map-file                         |   5 +
>   gtk/spice-channel.c                  |   6 +
>   gtk/spice-client.h                   |   1 +
>   gtk/spice-glib-sym-file              |   4 +
>   10 files changed, 564 insertions(+), 3 deletions(-)
>   create mode 100644 gtk/channel-nbd.c
>   create mode 100644 gtk/channel-nbd.h
>
> diff --git a/doc/reference/spice-gtk-docs.xml b/doc/reference/spice-gtk-docs.xml
> index 4a9a3cf..b7cea5a 100644
> --- a/doc/reference/spice-gtk-docs.xml
> +++ b/doc/reference/spice-gtk-docs.xml
> @@ -37,6 +37,7 @@
>         <xi:include href="xml/channel-smartcard.xml"/>
>         <xi:include href="xml/channel-usbredir.xml"/>
>         <xi:include href="xml/channel-port.xml"/>
> +      <xi:include href="xml/channel-nbd.xml"/>
>       </chapter>
>
>       <chapter>
> diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
> index b15e4bb..111f51f 100644
> --- a/doc/reference/spice-gtk-sections.txt
> +++ b/doc/reference/spice-gtk-sections.txt
> @@ -425,3 +425,21 @@ SPICE_PORT_CHANNEL_GET_CLASS
>   SpicePortChannelPrivate
>   </SECTION>
>
> +<SECTION>
> +<FILE>channel-nbd</FILE>
> +<TITLE>SpiceNbdChannel</TITLE>
> +SpiceNbdChannel
> +SpiceNbdChannelClass
> +<SUBSECTION>
> +<SUBSECTION Standard>
> +SPICE_NBD_CHANNEL
> +SPICE_IS_NBD_CHANNEL
> +SPICE_TYPE_NBD_CHANNEL
> +spice_nbd_channel_get_type
> +SPICE_NBD_CHANNEL_CLASS
> +SPICE_IS_NBD_CHANNEL_CLASS
> +SPICE_NBD_CHANNEL_GET_CLASS
> +<SUBSECTION Private>
> +SpiceNbdChannelPrivate
> +</SECTION>
> +
> diff --git a/doc/reference/spice-gtk.types b/doc/reference/spice-gtk.types
> index 2f52845..29741fe 100644
> --- a/doc/reference/spice-gtk.types
> +++ b/doc/reference/spice-gtk.types
> @@ -42,4 +42,5 @@ spice_usbredir_channel_get_type
>   spice_usb_device_get_type
>   spice_usb_device_manager_get_type
>   spice_usb_device_widget_get_type
> -spice_port_channel_get_type
> \ No newline at end of file
> +spice_port_channel_get_type
> +spice_nbd_channel_get_type
> \ No newline at end of file
> diff --git a/gtk/Makefile.am b/gtk/Makefile.am
> index 1932b46..7998262 100644
> --- a/gtk/Makefile.am
> +++ b/gtk/Makefile.am
> @@ -76,6 +76,7 @@ SPICE_COMMON_CPPFLAGS =						\
>   	-DUSB_IDS=\""$(USB_IDS)"\"				\
>   	-DSPICE_DISABLE_ABORT					\
>   	-I$(top_srcdir)						\
> +	-I$(srcdir)/nbd						\
>   	$(COMMON_CFLAGS)					\
>   	$(PIXMAN_CFLAGS)					\
>   	$(CELT051_CFLAGS)					\
> @@ -179,6 +180,7 @@ libspice_client_glib_2_0_la_LDFLAGS =	\
>   libspice_client_glib_2_0_la_LIBADD =					\
>   	$(top_builddir)/spice-common/common/libspice-common.la		\
>   	$(top_builddir)/spice-common/common/libspice-common-client.la	\
> +	nbd/libnbd.la							\
>   	$(GLIB2_LIBS)							\
>   	$(GIO_LIBS)							\
>   	$(GOBJECT2_LIBS)						\
> @@ -229,6 +231,7 @@ libspice_client_glib_2_0_la_SOURCES =			\
>   	gio-coroutine.h					\
>   							\
>   	channel-base.c					\
> +	channel-nbd.c					\
>   	channel-cursor.c				\
>   	channel-display.c				\
>   	channel-display-priv.h				\
> @@ -447,11 +450,19 @@ spice-marshal.c: spice-marshal.txt
>   spice-marshal.h: spice-marshal.txt
>   	$(AM_V_GEN)glib-genmarshal --header $< > $@ || (rm -f $@ && exit 1)
>
> -spice-glib-enums.c: spice-channel.h channel-inputs.h spice-session.h
> +SPICE_GLIB_ENUMS_FILES =			\
> +	channel-nbd.h				\
> +	channel-inputs.h			\
> +	spice-channel.h				\
> +	spice-session.h				\
> +	$(NULL)
> +
> +spice-glib-enums.c: $(SPICE_GLIB_ENUMS_FILES)
>   	$(AM_V_GEN)glib-mkenums --fhead "#include <glib-object.h>\n" \
>   			--fhead "#include \"spice-glib-enums.h\"\n\n" \
>   			--fprod "\n#include \"spice-session.h\"\n" \
>   			--fprod "\n#include \"spice-channel.h\"\n" \
> +			--fprod "\n#include \"channel-nbd.h\"\n" \
>   			--fprod "\n#include \"channel-inputs.h\"\n" \
>   			--vhead "static const G at Type@Value _ at enum_name@_values[] = {" \
>   			--vprod "  { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \
> @@ -466,7 +477,7 @@ spice-glib-enums.c: spice-channel.h channel-inputs.h spice-session.h
>   			--vtail "  return type;\n}\n\n" \
>   		$^ > $@
>
> -spice-glib-enums.h: spice-channel.h channel-inputs.h spice-session.h
> +spice-glib-enums.h: $(SPICE_GLIB_ENUMS_FILES)
>   	$(AM_V_GEN)glib-mkenums --fhead "#ifndef SPICE_GLIB_ENUMS_H\n" \
>   			--fhead "#define SPICE_GLIB_ENUMS_H\n\n" \
>   			--fhead "G_BEGIN_DECLS\n\n" \
> @@ -589,6 +600,7 @@ glib_introspection_files =				\
>   	spice-glib-enums.c				\
>   	spice-option.c					\
>   	spice-util.c					\
> +	channel-nbd.c					\
>   	channel-cursor.c				\
>   	channel-display.c				\
>   	channel-inputs.c				\
> diff --git a/gtk/channel-nbd.c b/gtk/channel-nbd.c
> new file mode 100644
> index 0000000..e5978fd
> --- /dev/null
> +++ b/gtk/channel-nbd.c
> @@ -0,0 +1,425 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> +   Copyright (C) 2013 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 "spice-client.h"
> +#include "spice-common.h"
> +#include "spice-channel-priv.h"
> +#include "spice-marshal.h"
> +#include "glib-compat.h"
> +#include "nbd/nbd.h"
> +#include "vmcstream.h"
> +
> +/**
> + * SECTION:channel-nbd
> + * @short_description: blockdevice communication channel
> + * @title: Block device Channel
> + * @section_id:
> + * @see_also: #SpiceChannel
> + * @stability: Stable
> + * @include: channel-nbd.h
> + *
> + * The "nbd" channel exports block device to a Spice server, using the
> + * Network Block Device protocol. This is mainly useful to redirect
> + * ISO images to a CD device for example.
> + *
> + * As of today, the implementation allows read-only operations.
> + *
> + * Since: 0.20
> + */
> +
> +#define SPICE_NBD_CHANNEL_GET_PRIVATE(obj)                                  \
> +    (G_TYPE_INSTANCE_GET_PRIVATE((obj), SPICE_TYPE_NBD_CHANNEL, SpiceNbdChannelPrivate))
> +
> +struct _SpiceNbdChannelPrivate {
> +    NbdServer *server;
> +
> +    gboolean pending_update;
> +    gboolean pending_session;
> +    NbdServerSession *session;
> +
> +    GCancellable *cancellable;
> +    NbdExport *export;
> +    SpiceVmcStream *stream;
> +};
> +
> +G_DEFINE_TYPE(SpiceNbdChannel, spice_nbd_channel, SPICE_TYPE_PORT_CHANNEL)
> +
> +/* Properties */
> +enum {
> +    PROP_0,
> +
> +    PROP_NBD_FILE,
> +    PROP_NBD_OPENED,
> +};
> +
> +static void spice_nbd_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg);
> +static void update_nbd_session(SpiceNbdChannel *self);
> +
> +static void
> +session_closed(GObject *source_object,
> +               GAsyncResult *res,
> +               gpointer user_data)
> +{
> +    SpiceNbdChannel *self = user_data;
> +    SpiceNbdChannelPrivate *c = self->priv;
> +    GError *error = NULL;
> +
> +    CHANNEL_DEBUG(self, "session closed");
> +
> +    if (!nbd_server_session_close_finish(c->session, res, &error)) {
> +        g_warning("%s", error->message);
> +        g_clear_error(&error);
> +    }
> +
> +    g_clear_object(&c->session);
> +    g_object_notify(G_OBJECT(self), "nbd-opened");
> +
> +    c->pending_update = FALSE;
> +    update_nbd_session(self);
> +}
> +
> +static void port_event(SpiceNbdChannel *self, gint event)
> +{
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    CHANNEL_DEBUG(self, "port event:%d pending:%d", event, c->pending_update);
> +    if (event != SPICE_PORT_EVENT_OPENED ||
> +        !c->pending_update)
> +        return;
> +
> +    if (c->session)
> +        nbd_server_session_close_async(c->session,
> +                                       NULL,
> +                                       session_closed,
> +                                       self);
> +    else {
> +        c->pending_update = FALSE;
> +        update_nbd_session(self);
> +    }
> +
> +}
> +
> +static void spice_nbd_channel_init(SpiceNbdChannel *channel)
> +{
> +    SpiceNbdChannelPrivate *c = SPICE_NBD_CHANNEL_GET_PRIVATE(channel);
> +
> +    channel->priv = c;
> +
> +    c->stream = spice_vmc_stream_new(SPICE_CHANNEL(channel));
> +    c->server = nbd_server_new();
> +    c->cancellable = g_cancellable_new();
> +}
> +
> +/**
> + * spice_nbd_channel_get_file:
> + * @channel: a %SpiceNbdChannel
> + *
> + * Returns the %GFile that has been set with
> + * spice_nbd_channel_set_file_async().
> + *
> + * Returns: (transfer none): The associated %GFile or %NULL.
> + **/
> +GFile* spice_nbd_channel_get_file(SpiceNbdChannel *self)
> +{
> +    GFile *file = NULL;
> +
> +    g_return_val_if_fail(SPICE_IS_NBD_CHANNEL(self), NULL);
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    if (c->export)
> +        file = nbd_export_get_file(c->export);
> +
> +    return file;
> +}
> +
> +static void spice_nbd_get_property(GObject    *object,
> +                                   guint       prop_id,
> +                                   GValue     *value,
> +                                   GParamSpec *pspec)
> +{
> +    g_return_if_fail(SPICE_IS_NBD_CHANNEL(object));
> +    SpiceNbdChannel *self = SPICE_NBD_CHANNEL(object);
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    switch (prop_id) {
> +    case PROP_NBD_FILE:
> +        g_value_set_object(value, spice_nbd_channel_get_file(self));
> +        break;
> +    case PROP_NBD_OPENED:
> +        g_value_set_boolean(value, !!c->session);
> +        break;
> +    default:
> +        G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
> +        break;
> +    }
> +}
> +
> +static void spice_nbd_channel_finalize(GObject *object)
> +{
> +    SpiceNbdChannelPrivate *c = SPICE_NBD_CHANNEL(object)->priv;
> +
> +    g_clear_object(&c->export);
> +    g_clear_object(&c->server);
> +    g_clear_object(&c->session);
> +    g_clear_object(&c->cancellable);
> +
> +    G_OBJECT_CLASS(spice_nbd_channel_parent_class)->finalize(object);
> +}
> +
> +static void
> +session_ready(GObject *source_object,
> +              GAsyncResult *res,
> +              gpointer user_data)
> +{
> +    SpiceNbdChannel *self = user_data;
> +    SpiceNbdChannelPrivate *c = self->priv;
> +    GError *error = NULL;
> +
> +    g_warn_if_fail(c->session == NULL);
> +    c->session = nbd_server_session_new_finish(res, &error);
> +    CHANNEL_DEBUG(self, "New NBD session %p", c->session);
> +    c->pending_session = FALSE;
> +
> +    if (!c->session) {
> +        if (error)
> +            g_warning("%s", error->message);
> +        g_clear_error(&error);
> +    } else
> +        g_object_notify(G_OBJECT(self), "nbd-opened");
> +}
> +
> +static void update_nbd_session(SpiceNbdChannel *self)
> +{
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    if (spice_channel_get_state(SPICE_CHANNEL(self)) != SPICE_CHANNEL_STATE_READY ||
> +        !c->export ||
> +        c->pending_update ||
> +        c->pending_session)
> +        return;
> +
> +    if (c->session) {
> +        g_message("PORTEVENT");
> +        spice_port_event(SPICE_PORT_CHANNEL(self), SPICE_PORT_EVENT_BREAK);
> +        c->pending_update = TRUE;
> +        return;
> +    }
> +
> +    c->pending_session = TRUE;
> +    nbd_server_session_new(c->server,
> +                           G_IO_STREAM(c->stream), c->export,
> +                           c->cancellable, session_ready, self);
> +}
> +
> +static void spice_nbd_channel_up(SpiceChannel *channel)
> +{
> +    SpiceNbdChannel *self = SPICE_NBD_CHANNEL(channel);
> +
> +    update_nbd_session(self);
> +}
> +
> +static void spice_nbd_channel_class_init(SpiceNbdChannelClass *klass)
> +{
> +    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
> +    SpiceChannelClass *channel_class = SPICE_CHANNEL_CLASS(klass);
> +
> +    gobject_class->finalize     = spice_nbd_channel_finalize;
> +    gobject_class->get_property = spice_nbd_get_property;
> +    channel_class->handle_msg   = spice_nbd_handle_msg;
> +    channel_class->channel_up   = spice_nbd_channel_up;
> +
> +    g_signal_override_class_handler("port-event",
> +                                    SPICE_TYPE_NBD_CHANNEL,
> +                                    G_CALLBACK(port_event));
> +
> +    g_object_class_install_property
> +        (gobject_class, PROP_NBD_FILE,
> +         g_param_spec_string("nbd-file",
> +                             "file",
> +                             "Associated block device file",
> +                             NULL,
> +                             G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
> +
> +    g_object_class_install_property
> +        (gobject_class, PROP_NBD_OPENED,
> +         g_param_spec_boolean("nbd-opened",
> +                              "opened",
> +                              "Session opened",
> +                              FALSE,
> +                              G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
> +
> +    g_type_class_add_private(klass, sizeof(SpiceNbdChannelPrivate));
> +}
> +
> +static void
> +export_ready(GObject *source_object,
> +             GAsyncResult *res,
> +             gpointer user_data)
> +{
> +    GError *error = NULL;
> +    GSimpleAsyncResult *simple = user_data;
> +    SpiceNbdChannel *self = SPICE_NBD_CHANNEL(g_async_result_get_source_object(G_ASYNC_RESULT(simple)));
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    NbdExport *export = nbd_export_new_finish(res, &error);
> +    CHANNEL_DEBUG(self, "set export %p", export);
> +    if (!export) {
> +        g_simple_async_result_take_error(simple, error);
> +        goto end;
> +    }
> +
> +    if (c->export)
> +        nbd_server_remove_export(c->server, c->export);
> +
> +    nbd_server_add_export(c->server, export);
> +
> +    g_clear_object(&c->export);
> +    c->export = export;
> +    g_object_notify(G_OBJECT(self), "nbd-file");
> +
> +    update_nbd_session(self);
> +    g_simple_async_result_set_op_res_gboolean(simple, TRUE);
> +
> +end:
> +    g_simple_async_result_complete(simple);
> +    g_object_unref(simple);
> +    g_object_unref(self);
> +}
> +
> +/**
> + * spice_nbd_set_file_async:
> + * @channel: a #SpiceNbdChannel
> + * @file: the block device image file
> + * @flags: open options
> + * @cancellable: (allow-none): optional GCancellable object, NULL to ignore
> + * @callback: (scope async): callback to call when the request is satisfied
> + * @user_data: (closure): the data to pass to callback function
> + *
> + * Update the @file image associated with @channel.
> + *
> + * The caller is responsible to finish any previous call, no
> + * concurrent call will be permitted.
> + **/
> +void
> +spice_nbd_channel_set_file_async(SpiceNbdChannel *self,
> +                                 GFile *file, SpiceNbdOpenFlags flags,
> +                                 GCancellable *cancellable,
> +                                 GAsyncReadyCallback callback,
> +                                 gpointer user_data)
> +{
> +    GSimpleAsyncResult *simple;
> +
> +    g_return_if_fail(SPICE_IS_NBD_CHANNEL(self));
> +    g_return_if_fail(!file || G_IS_FILE(file));
> +
> +    SpiceNbdChannelPrivate *c = self->priv;
> +
> +    if (c->pending_session) {
> +        g_simple_async_report_error_in_idle(G_OBJECT (self),
> +                                            callback,
> +                                            user_data,
> +                                            SPICE_CLIENT_ERROR,
> +                                            SPICE_CLIENT_ERROR_FAILED,
> +                                            "Channel has already a pending session");
> +        return;
> +    }
> +
> +    simple = g_simple_async_result_new(G_OBJECT(self),
> +                                       callback,
> +                                       user_data,
> +                                       spice_nbd_channel_set_file_async);
> +
> +    CHANNEL_DEBUG(self, "set file %p 0x%X", file, flags);
> +
> +    if (!file) {
> +        g_clear_object(&c->export);
> +        g_object_notify(G_OBJECT(self), "nbd-file");
> +
> +        update_nbd_session(self);
> +
> +        g_simple_async_result_set_op_res_gboolean(simple, TRUE);
> +        g_simple_async_result_complete_in_idle(simple);
> +        g_object_unref(simple);
> +    } else
> +        nbd_export_new("", file, flags, cancellable, export_ready, simple);
> +}
> +
> +/**
> + * spice_nbd_set_file_finish:
> + * @channel: a #SpiceNbdChannel
> + * @result: a #GAsyncResult
> + * @error: a #GError location to store the error occurring, or %NULL
> + * to ignore
> + *
> + * Finishes an asynchronous file read operation started with
> + * spice_nbd_set_file_async().
> + *
> + * Returns: %TRUE on success.
> + **/
> +gboolean
> +spice_nbd_channel_set_file_finish(SpiceNbdChannel *self,
> +                                  GAsyncResult *result,
> +                                  GError **error)
> +{
> +    GSimpleAsyncResult *simple;
> +
> +    g_return_val_if_fail(SPICE_IS_NBD_CHANNEL(self), FALSE);
> +    g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
> +    g_return_val_if_fail(g_simple_async_result_is_valid(result,
> +                                                        G_OBJECT(self),
> +                                                        spice_nbd_channel_set_file_async),
> +                         FALSE);
> +
> +    simple = (GSimpleAsyncResult *)result;
> +
> +    if (g_simple_async_result_propagate_error(simple, error))
> +        return FALSE;
> +
> +    return g_simple_async_result_get_op_res_gboolean(simple);
> +}
> +
> +/* coroutine context */
> +static void nbd_handle_msg(SpiceChannel *channel, SpiceMsgIn *in)
> +{
> +    SpiceNbdChannel *self = SPICE_NBD_CHANNEL(channel);
> +    SpiceNbdChannelPrivate *c = self->priv;
> +    int size;
> +    uint8_t *buf;
> +
> +    buf = spice_msg_in_raw(in, &size);
> +
> +    spice_vmc_input_stream_co_data(
> +        SPICE_VMC_INPUT_STREAM(g_io_stream_get_input_stream(G_IO_STREAM(c->stream))),
> +        buf, size);
> +}
> +
> +
> +/* coroutine context */
> +static void spice_nbd_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg)
> +{
> +    int type = spice_msg_in_type(msg);
> +    SpiceChannelClass *parent_class;
> +
> +    parent_class = SPICE_CHANNEL_CLASS(spice_nbd_channel_parent_class);
> +
> +    if (type == SPICE_MSG_SPICEVMC_DATA)
> +        nbd_handle_msg(channel, msg);
> +    else if (parent_class->handle_msg)
> +        parent_class->handle_msg(channel, msg);
> +    else
> +        g_return_if_reached();
> +}
> diff --git a/gtk/channel-nbd.h b/gtk/channel-nbd.h
> new file mode 100644
> index 0000000..2cb2d7a
> --- /dev/null
> +++ b/gtk/channel-nbd.h
> @@ -0,0 +1,88 @@
> +/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
> +/*
> +   Copyright (C) 2013 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 __SPICE_CLIENT_NBD_CHANNEL_H__
> +#define __SPICE_CLIENT_NBD_CHANNEL_H__
> +
> +#include <gio/gio.h>
> +#include "spice-client.h"
> +#include "channel-port.h"
> +
> +G_BEGIN_DECLS
> +
> +#define SPICE_TYPE_NBD_CHANNEL            (spice_nbd_channel_get_type())
> +#define SPICE_NBD_CHANNEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), SPICE_TYPE_NBD_CHANNEL, SpiceNbdChannel))
> +#define SPICE_NBD_CHANNEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), SPICE_TYPE_NBD_CHANNEL, SpiceNbdChannelClass))
> +#define SPICE_IS_NBD_CHANNEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), SPICE_TYPE_NBD_CHANNEL))
> +#define SPICE_IS_NBD_CHANNEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), SPICE_TYPE_NBD_CHANNEL))
> +#define SPICE_NBD_CHANNEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), SPICE_TYPE_NBD_CHANNEL, SpiceNbdChannelClass))
> +
> +typedef struct _SpiceNbdChannel SpiceNbdChannel;
> +typedef struct _SpiceNbdChannelClass SpiceNbdChannelClass;
> +typedef struct _SpiceNbdChannelPrivate SpiceNbdChannelPrivate;
> +
> +/**
> + * SpiceNbdOpenFlags:
> + *
> + **/
> +typedef enum
> +{
> +    SPICE_NBD_OPEN_NONE = 0,
> +
> +    SPICE_NBD_OPEN_READWRITE = 1 << 0,
> +} SpiceNbdOpenFlags;
> +
> +/**
> + * SpiceNbdChannel:
> + *
> + * The #SpiceNbdChannel struct is opaque and should not be accessed directly.
> + */
> +struct _SpiceNbdChannel {
> +    SpicePortChannel parent;
> +
> +    /*< private >*/
> +    SpiceNbdChannelPrivate *priv;
> +    /* Do not add fields to this struct */
> +};
> +
> +/**
> + * SpiceNbdChannelClass:
> + * @parent_class: Parent class.
> + *
> + * Class structure for #SpiceNbdChannel.
> + */
> +struct _SpiceNbdChannelClass {
> +    SpicePortChannelClass parent_class;
> +
> +    /*< private >*/
> +    /* Do not add fields to this struct */
> +};
> +
> +GType spice_nbd_channel_get_type(void);
> +
> +void spice_nbd_channel_set_file_async(SpiceNbdChannel *channel,
> +                                      GFile *file, SpiceNbdOpenFlags flags,
> +                                      GCancellable *cancellable,
> +                                      GAsyncReadyCallback callback,
> +                                      gpointer user_data);
> +gboolean spice_nbd_channel_set_file_finish(SpiceNbdChannel *channel,
> +                                           GAsyncResult *result, GError **error);
> +GFile* spice_nbd_channel_get_file(SpiceNbdChannel *channel);
> +
> +G_END_DECLS
> +
> +#endif /* __SPICE_CLIENT_NBD_CHANNEL_H__ */
> diff --git a/gtk/map-file b/gtk/map-file
> index 558a4d7..053372a 100644
> --- a/gtk/map-file
> +++ b/gtk/map-file
> @@ -3,6 +3,11 @@ global:
>   spice_audio_get;
>   spice_audio_get_type;
>   spice_audio_new;
> +spice_nbd_channel_get_type;
> +spice_nbd_open_flags_get_type;
> +spice_nbd_channel_set_file_async;
> +spice_nbd_channel_set_file_finish;
> +spice_nbd_channel_get_file;
>   spice_channel_connect;
>   spice_channel_destroy;
>   spice_channel_disconnect;
> diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
> index 0a32d6c..5630741 100644
> --- a/gtk/spice-channel.c
> +++ b/gtk/spice-channel.c
> @@ -1882,6 +1882,7 @@ static const char *to_string[] = {
>       [ SPICE_CHANNEL_SMARTCARD ] = "smartcard",
>       [ SPICE_CHANNEL_USBREDIR ] = "usbredir",
>       [ SPICE_CHANNEL_PORT ] = "port",
> +    [ SPICE_CHANNEL_NBD ] = "nbd",
>   };
>
>   const gchar* spice_channel_type_to_string(gint type)
> @@ -1924,6 +1925,7 @@ gchar *spice_channel_supported_string(void)
>   #ifdef USE_USBREDIR
>                        spice_channel_type_to_string(SPICE_CHANNEL_USBREDIR),
>   #endif
> +                     spice_channel_type_to_string(SPICE_CHANNEL_NBD),
>                        NULL);
>   }
>
> @@ -1988,6 +1990,10 @@ SpiceChannel *spice_channel_new(SpiceSession *s, int type, int id)
>           break;
>       }
>   #endif
> +    case SPICE_CHANNEL_NBD: {
> +        gtype = SPICE_TYPE_NBD_CHANNEL;
> +        break;
> +    }
>       case SPICE_CHANNEL_PORT:
>           gtype = SPICE_TYPE_PORT_CHANNEL;
>           break;
> diff --git a/gtk/spice-client.h b/gtk/spice-client.h
> index 730d11a..5b9b01b 100644
> --- a/gtk/spice-client.h
> +++ b/gtk/spice-client.h
> @@ -41,6 +41,7 @@
>   #include "channel-smartcard.h"
>   #include "channel-usbredir.h"
>   #include "channel-port.h"
> +#include "channel-nbd.h"
>
>   #include "smartcard-manager.h"
>   #include "usb-device-manager.h"
> diff --git a/gtk/spice-glib-sym-file b/gtk/spice-glib-sym-file
> index 5a580d6..269a675 100644
> --- a/gtk/spice-glib-sym-file
> +++ b/gtk/spice-glib-sym-file
> @@ -1,6 +1,10 @@
>   spice_audio_get
>   spice_audio_get_type
>   spice_audio_new
> +spice_nbd_channel_get_type
> +spice_nbd_open_flags_get_type
> +spice_nbd_set_file_async
> +spice_nbd_set_file_finish
>   spice_channel_connect
>   spice_channel_destroy
>   spice_channel_disconnect
>


More information about the Spice-devel mailing list