> Required to use them later in the Windows vsock path.
> 
> ga_channel_common_client_add() now takes ownership of client_ch on
> success only; on failure the caller keeps it and disposes of it via the
> new ga_channel_common_gio_destroy() helper.
> The Windows vsock path needs this: it has to release the CRT fd wrapper
> with qemu_close_socket_osfhandle() before channel teardown closes the
> SOCKET, so the caller must still own the channel on the error path.
> 
> Signed-off-by: Polina Vishneva <[email protected]>
> Message-ID: <[email protected]>
>
> diff --git a/qga/channel-common.h b/qga/channel-common.h
> new file mode 100644
> index 00000000000..8e82bf09099
> --- /dev/null
> +++ b/qga/channel-common.h
> @@ -0,0 +1,44 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * QEMU Guest Agent common GIOChannel lifecycle
> + *
> + * Copyright (c) 2026 Virtuozzo International GmbH.
> + */
> +#ifndef QGA_CHANNEL_COMMON_H
> +#define QGA_CHANNEL_COMMON_H
> +
> +#include "channel.h"
> +
> +typedef struct GAChannelCommon {
> +    GIOChannel *listen_channel;
> +    GIOChannel *client_channel;
> +    GAChannelMethod method;
> +    GAChannelCallback event_cb;
> +    gpointer user_data;
> +} GAChannelCommon;
> +
> +/* Common GIOChannel lifecycle (channel-common.c) */
> +void ga_channel_common_listen_close(GAChannelCommon *c);
> +
> +/* Start listening on a vsock "cid:port" path; returns an fd or -1. */
> +int ga_channel_common_vsock_listen(const char *path, Error **errp);
> +
> +/* Shut down and unref a GIOChannel not tracked by a GAChannelCommon. */
> +void ga_channel_common_gio_destroy(GIOChannel *ch);
> +
> +/*
> + * Takes ownership of client_ch on success only; on failure the caller keeps
> + * it and must dispose of it via ga_channel_common_gio_destroy().
> + */
> +int ga_channel_common_client_add(GAChannelCommon *c,
> +                                 GIOChannel *client_ch,
> +                                 GIOFunc event_fn, gpointer data);
> +void ga_channel_common_client_close(GAChannelCommon *c);
> +GIOStatus ga_channel_common_read(GAChannelCommon *c, gchar *buf,
> +                                 gsize size, gsize *count);
> +GIOStatus ga_channel_common_write_all(GAChannelCommon *c,
> +                                      const gchar *buf, gsize size);
> +void ga_channel_common_free(GAChannelCommon *c);
> +
> +#endif /* QGA_CHANNEL_COMMON_H */
> diff --git a/qga/channel-common.c b/qga/channel-common.c
> new file mode 100644
> index 00000000000..9732a194776
> --- /dev/null
> +++ b/qga/channel-common.c
> @@ -0,0 +1,115 @@
> +/*
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + *
> + * QEMU Guest Agent common GIOChannel lifecycle
> + *
> + * Copyright (c) 2026 Virtuozzo International GmbH.
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/sockets.h"
> +#include "channel-common.h"
> +
> +void ga_channel_common_gio_destroy(GIOChannel *ch)
> +{
> +    g_io_channel_shutdown(ch, true, NULL);
> +    g_io_channel_unref(ch);
> +}
> +
> +/* The vsock analogue of unix_listen(): returns a listening fd or -1. */
> +int ga_channel_common_vsock_listen(const char *path, Error **errp)
> +{
> +    SocketAddress *addr;
> +    char *addr_str;
> +    int fd;
> +
> +    addr_str = g_strdup_printf("vsock:%s", path);
> +    addr = socket_parse(addr_str, errp);
> +    g_free(addr_str);

Could use g_autofree here too

> +    if (!addr) {
> +        return -1;
> +    }
> +
> +    fd = socket_listen(addr, 1, errp);
> +    qapi_free_SocketAddress(addr);
> +    return fd;
> +}
> +
> +void ga_channel_common_listen_close(GAChannelCommon *c)
> +{
> +    g_assert(c->listen_channel);
> +    ga_channel_common_gio_destroy(c->listen_channel);
> +    c->listen_channel = NULL;
> +}
> +
> +int ga_channel_common_client_add(GAChannelCommon *c, GIOChannel *client_ch,
> +                                 GIOFunc event_fn, gpointer data)
> +{
> +    GError *err = NULL;
> +
> +    g_assert(c && !c->client_channel);
> +    g_io_channel_set_encoding(client_ch, NULL, &err);
> +    if (err != NULL) {
> +        g_warning("error setting channel encoding to binary");
> +        g_error_free(err);
> +        return -1;
> +    }
> +    g_io_add_watch(client_ch, G_IO_IN | G_IO_HUP, event_fn, data);
> +    c->client_channel = client_ch;
> +    return 0;
> +}
> +
> +void ga_channel_common_client_close(GAChannelCommon *c)
> +{
> +    g_assert(c->client_channel);
> +    ga_channel_common_gio_destroy(c->client_channel);
> +    c->client_channel = NULL;
> +}
> +
> +GIOStatus ga_channel_common_read(GAChannelCommon *c, gchar *buf,
> +                                 gsize size, gsize *count)
> +{
> +    return g_io_channel_read_chars(c->client_channel, buf, size, count, 
> NULL);
> +}
> +
> +GIOStatus ga_channel_common_write_all(GAChannelCommon *c,
> +                                      const gchar *buf, gsize size)
> +{
> +    GError *err = NULL;

g_error_free() is missing in this function.

Use g_auto?

-- 
Marc-AndrĂ© Lureau <[email protected]>


Reply via email to