Blame src/libqmi-glib/qmi-endpoint-qmux.c

Packit Service ac8c34
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
Packit Service ac8c34
/*
Packit Service ac8c34
 * libqmi-glib -- GLib/GIO based library to control QMI devices
Packit Service ac8c34
 *
Packit Service ac8c34
 * This library is free software; you can redistribute it and/or
Packit Service ac8c34
 * modify it under the terms of the GNU Lesser General Public
Packit Service ac8c34
 * License as published by the Free Software Foundation; either
Packit Service ac8c34
 * version 2 of the License, or (at your option) any later version.
Packit Service ac8c34
 *
Packit Service ac8c34
 * This library is distributed in the hope that it will be useful,
Packit Service ac8c34
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service ac8c34
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service ac8c34
 * Lesser General Public License for more details.
Packit Service ac8c34
 *
Packit Service ac8c34
 * You should have received a copy of the GNU Lesser General Public
Packit Service ac8c34
 * License along with this library; if not, write to the
Packit Service ac8c34
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Packit Service ac8c34
 * Boston, MA 02110-1301 USA.
Packit Service ac8c34
 *
Packit Service ac8c34
 * Copyright (C) 2012 Lanedo GmbH
Packit Service ac8c34
 * Copyright (C) 2012-2017 Aleksander Morgado <aleksander@aleksander.es>
Packit Service ac8c34
 * Copyright (C) 2019 Eric Caruso <ejcaruso@chromium.org>
Packit Service ac8c34
 */
Packit Service ac8c34
Packit Service ac8c34
#include <errno.h>
Packit Service ac8c34
#include <fcntl.h>
Packit Service ac8c34
#include <gio/gio.h>
Packit Service ac8c34
#include <gio/gunixinputstream.h>
Packit Service ac8c34
#include <gio/gunixoutputstream.h>
Packit Service ac8c34
#include <gio/gunixsocketaddress.h>
Packit Service ac8c34
#include <string.h>
Packit Service ac8c34
#include <sys/stat.h>
Packit Service ac8c34
#include <sys/types.h>
Packit Service ac8c34
Packit Service ac8c34
#include "qmi-endpoint-qmux.h"
Packit Service ac8c34
#include "qmi-ctl.h"
Packit Service ac8c34
#include "qmi-errors.h"
Packit Service ac8c34
#include "qmi-error-types.h"
Packit Service ac8c34
Packit Service ac8c34
G_DEFINE_TYPE (QmiEndpointQmux, qmi_endpoint_qmux, QMI_TYPE_ENDPOINT)
Packit Service ac8c34
Packit Service ac8c34
struct _QmiEndpointQmuxPrivate {
Packit Service ac8c34
    /* I/O streams */
Packit Service ac8c34
    gint fd;
Packit Service ac8c34
    GInputStream *istream;
Packit Service ac8c34
    GOutputStream *ostream;
Packit Service ac8c34
    GSource *input_source;
Packit Service ac8c34
Packit Service ac8c34
    /* Proxy socket */
Packit Service ac8c34
    gchar *proxy_path;
Packit Service ac8c34
    GSocketClient *socket_client;
Packit Service ac8c34
    GSocketConnection *socket_connection;
Packit Service ac8c34
Packit Service ac8c34
    /* Control client */
Packit Service ac8c34
    QmiClientCtl *client_ctl;
Packit Service ac8c34
};
Packit Service ac8c34
Packit Service ac8c34
#define BUFFER_SIZE 2048
Packit Service ac8c34
#define MAX_SPAWN_RETRIES 10
Packit Service ac8c34
Packit Service ac8c34
static void destroy_iostream (QmiEndpointQmux *self);
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
input_ready_cb (GInputStream *istream,
Packit Service ac8c34
                QmiEndpointQmux *self)
Packit Service ac8c34
{
Packit Service ac8c34
    guint8 buffer[BUFFER_SIZE];
Packit Service ac8c34
    GError *error = NULL;
Packit Service ac8c34
    gssize r;
Packit Service ac8c34
Packit Service ac8c34
    r = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (istream),
Packit Service ac8c34
                                                  buffer,
Packit Service ac8c34
                                                  BUFFER_SIZE,
Packit Service ac8c34
                                                  NULL,
Packit Service ac8c34
                                                  &error);
Packit Service ac8c34
    if (r < 0) {
Packit Service ac8c34
        g_warning ("Error reading from istream: %s", error ? error->message : "unknown");
Packit Service ac8c34
        if (error)
Packit Service ac8c34
            g_error_free (error);
Packit Service ac8c34
        /* Hang up the endpoint */
Packit Service ac8c34
        g_signal_emit_by_name (QMI_ENDPOINT (self), QMI_ENDPOINT_SIGNAL_HANGUP);
Packit Service ac8c34
        return G_SOURCE_REMOVE;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    if (r == 0) {
Packit Service ac8c34
        /* HUP! */
Packit Service ac8c34
        g_warning ("Cannot read from istream: connection broken");
Packit Service ac8c34
        g_signal_emit_by_name (QMI_ENDPOINT (self), QMI_ENDPOINT_SIGNAL_HANGUP);
Packit Service ac8c34
        return G_SOURCE_REMOVE;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    /* else, r > 0 */
Packit Service ac8c34
    qmi_endpoint_add_message (QMI_ENDPOINT (self), buffer, r);
Packit Service ac8c34
    return G_SOURCE_CONTINUE;
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
typedef struct {
Packit Service ac8c34
    gboolean      use_proxy;
Packit Service ac8c34
    guint         spawn_retries;
Packit Service ac8c34
} QmuxDeviceOpenContext;
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
qmux_device_open_context_free (QmuxDeviceOpenContext *ctx)
Packit Service ac8c34
{
Packit Service ac8c34
    g_slice_free (QmuxDeviceOpenContext, ctx);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
endpoint_open_finish (QmiEndpoint   *self,
Packit Service ac8c34
                      GAsyncResult  *res,
Packit Service ac8c34
                      GError       **error)
Packit Service ac8c34
{
Packit Service ac8c34
    return g_task_propagate_boolean (G_TASK (res), error);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
internal_proxy_open_ready (QmiClientCtl *client_ctl,
Packit Service ac8c34
                           GAsyncResult *res,
Packit Service ac8c34
                           GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiMessageCtlInternalProxyOpenOutput *output;
Packit Service ac8c34
    GError *error = NULL;
Packit Service ac8c34
Packit Service ac8c34
    /* Check result of the async operation */
Packit Service ac8c34
    output = qmi_client_ctl_internal_proxy_open_finish (client_ctl, res, &error);
Packit Service ac8c34
    if (!output) {
Packit Service ac8c34
        g_task_return_error (task, error);
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    /* Check result of the QMI operation */
Packit Service ac8c34
    if (!qmi_message_ctl_internal_proxy_open_output_get_result (output, &error)) {
Packit Service ac8c34
        g_task_return_error (task, error);
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        qmi_message_ctl_internal_proxy_open_output_unref (output);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    qmi_message_ctl_internal_proxy_open_output_unref (output);
Packit Service ac8c34
    g_task_return_boolean (task, TRUE);
Packit Service ac8c34
    g_object_unref (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
setup_proxy (GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    QmiMessageCtlInternalProxyOpenInput *input;
Packit Service ac8c34
    QmiFile *file;
Packit Service ac8c34
Packit Service ac8c34
    self = g_task_get_source_object (task);
Packit Service ac8c34
Packit Service ac8c34
    g_object_get (self, QMI_ENDPOINT_FILE, &file, NULL);
Packit Service ac8c34
    input = qmi_message_ctl_internal_proxy_open_input_new ();
Packit Service ac8c34
    qmi_message_ctl_internal_proxy_open_input_set_device_path (input, qmi_file_get_path (file), NULL);
Packit Service ac8c34
    qmi_client_ctl_internal_proxy_open (self->priv->client_ctl,
Packit Service ac8c34
                                        input,
Packit Service ac8c34
                                        5,
Packit Service ac8c34
                                        g_task_get_cancellable (task),
Packit Service ac8c34
                                        (GAsyncReadyCallback)internal_proxy_open_ready,
Packit Service ac8c34
                                        task);
Packit Service ac8c34
    qmi_message_ctl_internal_proxy_open_input_unref (input);
Packit Service ac8c34
    g_object_unref (file);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
setup_iostream (GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    QmuxDeviceOpenContext *ctx;
Packit Service ac8c34
Packit Service ac8c34
    self = g_task_get_source_object (task);
Packit Service ac8c34
    ctx = g_task_get_task_data (task);
Packit Service ac8c34
Packit Service ac8c34
    /* Check in/out streams */
Packit Service ac8c34
    if (!self->priv->istream || !self->priv->ostream) {
Packit Service ac8c34
        destroy_iostream (self);
Packit Service ac8c34
        g_task_return_new_error (task,
Packit Service ac8c34
                                 QMI_CORE_ERROR,
Packit Service ac8c34
                                 QMI_CORE_ERROR_FAILED,
Packit Service ac8c34
                                 "Cannot get input/output streams");
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    /* Setup input events */
Packit Service ac8c34
    self->priv->input_source = g_pollable_input_stream_create_source (
Packit Service ac8c34
                                   G_POLLABLE_INPUT_STREAM (self->priv->istream),
Packit Service ac8c34
                                   NULL);
Packit Service ac8c34
    g_source_set_callback (self->priv->input_source,
Packit Service ac8c34
                           (GSourceFunc)input_ready_cb,
Packit Service ac8c34
                           self,
Packit Service ac8c34
                           NULL);
Packit Service ac8c34
    g_source_attach (self->priv->input_source, g_main_context_get_thread_default ());
Packit Service ac8c34
Packit Service ac8c34
    if (!ctx->use_proxy) {
Packit Service ac8c34
        /* We're done here */
Packit Service ac8c34
        g_task_return_boolean (task, TRUE);
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    setup_proxy (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
create_iostream_with_fd (GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    QmiFile *file;
Packit Service ac8c34
    gint fd;
Packit Service ac8c34
Packit Service ac8c34
    self = g_task_get_source_object (task);
Packit Service ac8c34
    g_object_get (self, QMI_ENDPOINT_FILE, &file, NULL);
Packit Service ac8c34
    fd = open (qmi_file_get_path (file), O_RDWR | O_EXCL | O_NONBLOCK | O_NOCTTY);
Packit Service ac8c34
Packit Service ac8c34
    if (fd < 0) {
Packit Service ac8c34
        g_task_return_new_error (task,
Packit Service ac8c34
                                 QMI_CORE_ERROR,
Packit Service ac8c34
                                 QMI_CORE_ERROR_FAILED,
Packit Service ac8c34
                                 "Cannot open device file '%s': %s",
Packit Service ac8c34
                                 qmi_file_get_path_display (file),
Packit Service ac8c34
                                 strerror (errno));
Packit Service ac8c34
        g_object_unref (file);
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    g_object_unref (file);
Packit Service ac8c34
    g_assert (self->priv->fd < 0);
Packit Service ac8c34
    self->priv->fd = fd;
Packit Service ac8c34
    self->priv->istream = g_unix_input_stream_new  (fd, FALSE);
Packit Service ac8c34
    self->priv->ostream = g_unix_output_stream_new (fd, FALSE);
Packit Service ac8c34
Packit Service ac8c34
    setup_iostream (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void create_iostream_with_socket (GTask *task);
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
wait_for_proxy_cb (GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    create_iostream_with_socket (task);
Packit Service ac8c34
    return FALSE;
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
spawn_child_setup (void)
Packit Service ac8c34
{
Packit Service ac8c34
    if (setpgid (0, 0) < 0)
Packit Service ac8c34
        g_warning ("couldn't setup proxy specific process group");
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
create_iostream_with_socket (GTask *task)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    QmuxDeviceOpenContext *ctx;
Packit Service ac8c34
    GSocketAddress *socket_address;
Packit Service ac8c34
    GError *error = NULL;
Packit Service ac8c34
Packit Service ac8c34
    self = g_task_get_source_object (task);
Packit Service ac8c34
    ctx = g_task_get_task_data (task);
Packit Service ac8c34
Packit Service ac8c34
    /* Create socket client */
Packit Service ac8c34
    self->priv->socket_client = g_socket_client_new ();
Packit Service ac8c34
    g_socket_client_set_family (self->priv->socket_client, G_SOCKET_FAMILY_UNIX);
Packit Service ac8c34
    g_socket_client_set_socket_type (self->priv->socket_client, G_SOCKET_TYPE_STREAM);
Packit Service ac8c34
    g_socket_client_set_protocol (self->priv->socket_client, G_SOCKET_PROTOCOL_DEFAULT);
Packit Service ac8c34
Packit Service ac8c34
    /* Setup socket address */
Packit Service ac8c34
    socket_address = g_unix_socket_address_new_with_type (
Packit Service ac8c34
                         self->priv->proxy_path,
Packit Service ac8c34
                         -1,
Packit Service ac8c34
                         G_UNIX_SOCKET_ADDRESS_ABSTRACT);
Packit Service ac8c34
Packit Service ac8c34
    /* Connect to address */
Packit Service ac8c34
    self->priv->socket_connection = g_socket_client_connect (
Packit Service ac8c34
                                        self->priv->socket_client,
Packit Service ac8c34
                                        G_SOCKET_CONNECTABLE (socket_address),
Packit Service ac8c34
                                        NULL,
Packit Service ac8c34
                                        &error);
Packit Service ac8c34
    g_object_unref (socket_address);
Packit Service ac8c34
Packit Service ac8c34
    if (!self->priv->socket_connection) {
Packit Service ac8c34
        gchar **argc;
Packit Service ac8c34
        GSource *source;
Packit Service ac8c34
Packit Service ac8c34
        g_debug ("cannot connect to proxy: %s", error->message);
Packit Service ac8c34
        g_clear_error (&error);
Packit Service ac8c34
        g_clear_object (&self->priv->socket_client);
Packit Service ac8c34
Packit Service ac8c34
        /* Don't retry forever */
Packit Service ac8c34
        ctx->spawn_retries++;
Packit Service ac8c34
        if (ctx->spawn_retries > MAX_SPAWN_RETRIES) {
Packit Service ac8c34
            g_task_return_new_error (task,
Packit Service ac8c34
                                     QMI_CORE_ERROR,
Packit Service ac8c34
                                     QMI_CORE_ERROR_FAILED,
Packit Service ac8c34
                                     "Couldn't spawn the qmi-proxy");
Packit Service ac8c34
            g_object_unref (task);
Packit Service ac8c34
            return;
Packit Service ac8c34
        }
Packit Service ac8c34
Packit Service ac8c34
        g_debug ("spawning new qmi-proxy (try %u)...", ctx->spawn_retries);
Packit Service ac8c34
Packit Service ac8c34
        argc = g_new0 (gchar *, 2);
Packit Service ac8c34
        argc[0] = g_strdup (LIBEXEC_PATH "/qmi-proxy");
Packit Service ac8c34
        if (!g_spawn_async (NULL, /* working directory */
Packit Service ac8c34
                            argc,
Packit Service ac8c34
                            NULL, /* envp */
Packit Service ac8c34
                            G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL,
Packit Service ac8c34
                            (GSpawnChildSetupFunc) spawn_child_setup,
Packit Service ac8c34
                            NULL, /* child_setup_user_data */
Packit Service ac8c34
                            NULL,
Packit Service ac8c34
                            &error)) {
Packit Service ac8c34
            g_debug ("error spawning qmi-proxy: %s", error->message);
Packit Service ac8c34
            g_clear_error (&error);
Packit Service ac8c34
        }
Packit Service ac8c34
        g_strfreev (argc);
Packit Service ac8c34
Packit Service ac8c34
        /* Wait some ms and retry */
Packit Service ac8c34
        source = g_timeout_source_new (100);
Packit Service ac8c34
        g_source_set_callback (source, (GSourceFunc)wait_for_proxy_cb, task, NULL);
Packit Service ac8c34
        g_source_attach (source, g_main_context_get_thread_default ());
Packit Service ac8c34
        g_source_unref (source);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    self->priv->istream = g_io_stream_get_input_stream (G_IO_STREAM (self->priv->socket_connection));
Packit Service ac8c34
    if (self->priv->istream)
Packit Service ac8c34
        g_object_ref (self->priv->istream);
Packit Service ac8c34
Packit Service ac8c34
    self->priv->ostream = g_io_stream_get_output_stream (G_IO_STREAM (self->priv->socket_connection));
Packit Service ac8c34
    if (self->priv->ostream)
Packit Service ac8c34
        g_object_ref (self->priv->ostream);
Packit Service ac8c34
Packit Service ac8c34
    setup_iostream (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
endpoint_open (QmiEndpoint         *endpoint,
Packit Service ac8c34
               gboolean             use_proxy,
Packit Service ac8c34
               guint                timeout,
Packit Service ac8c34
               GCancellable        *cancellable,
Packit Service ac8c34
               GAsyncReadyCallback  callback,
Packit Service ac8c34
               gpointer             user_data)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    QmuxDeviceOpenContext *ctx;
Packit Service ac8c34
    GTask *task;
Packit Service ac8c34
Packit Service ac8c34
    ctx = g_slice_new (QmuxDeviceOpenContext);
Packit Service ac8c34
    ctx->use_proxy = use_proxy;
Packit Service ac8c34
    ctx->spawn_retries = 0;
Packit Service ac8c34
Packit Service ac8c34
    self = QMI_ENDPOINT_QMUX (endpoint);
Packit Service ac8c34
    task = g_task_new (self, NULL, callback, user_data);
Packit Service ac8c34
    g_task_set_task_data (task,
Packit Service ac8c34
                          ctx,
Packit Service ac8c34
                          (GDestroyNotify)qmux_device_open_context_free);
Packit Service ac8c34
Packit Service ac8c34
    if (self->priv->istream || self->priv->ostream) {
Packit Service ac8c34
        g_task_return_new_error (task,
Packit Service ac8c34
                                 QMI_CORE_ERROR,
Packit Service ac8c34
                                 QMI_CORE_ERROR_WRONG_STATE,
Packit Service ac8c34
                                 "Already open");
Packit Service ac8c34
        g_object_unref (task);
Packit Service ac8c34
        return;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    if (use_proxy)
Packit Service ac8c34
        create_iostream_with_socket (task);
Packit Service ac8c34
    else
Packit Service ac8c34
        create_iostream_with_fd (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
endpoint_is_open (QmiEndpoint *self)
Packit Service ac8c34
{
Packit Service ac8c34
    return !!(QMI_ENDPOINT_QMUX (self)->priv->istream ||
Packit Service ac8c34
              QMI_ENDPOINT_QMUX (self)->priv->ostream);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
endpoint_send (QmiEndpoint   *self,
Packit Service ac8c34
               QmiMessage    *message,
Packit Service ac8c34
               guint          timeout,
Packit Service ac8c34
               GCancellable  *cancellable,
Packit Service ac8c34
               GError       **error)
Packit Service ac8c34
{
Packit Service ac8c34
    gconstpointer raw_message;
Packit Service ac8c34
    gsize raw_message_len;
Packit Service ac8c34
    GError *inner_error = NULL;
Packit Service ac8c34
Packit Service ac8c34
    /* Get raw message */
Packit Service ac8c34
    raw_message = qmi_message_get_raw (message, &raw_message_len, &inner_error);
Packit Service ac8c34
    if (!raw_message) {
Packit Service ac8c34
        g_propagate_prefixed_error (error, inner_error, "Cannot get raw message: ");
Packit Service ac8c34
        return FALSE;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    if (!g_output_stream_write_all (QMI_ENDPOINT_QMUX (self)->priv->ostream,
Packit Service ac8c34
                                    raw_message,
Packit Service ac8c34
                                    raw_message_len,
Packit Service ac8c34
                                    NULL, /* bytes_written */
Packit Service ac8c34
                                    NULL, /* cancellable */
Packit Service ac8c34
                                    &inner_error)) {
Packit Service ac8c34
        g_propagate_prefixed_error (error, inner_error, "Cannot write message: ");
Packit Service ac8c34
        return FALSE;
Packit Service ac8c34
    }
Packit Service ac8c34
Packit Service ac8c34
    /* Flush explicitly if correctly written */
Packit Service ac8c34
    g_output_stream_flush (QMI_ENDPOINT_QMUX (self)->priv->ostream, NULL, NULL);
Packit Service ac8c34
    return TRUE;
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
static gboolean
Packit Service ac8c34
endpoint_close_finish (QmiEndpoint   *self,
Packit Service ac8c34
                       GAsyncResult  *res,
Packit Service ac8c34
                       GError       **error)
Packit Service ac8c34
{
Packit Service ac8c34
    return g_task_propagate_boolean (G_TASK (res), error);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
destroy_iostream (QmiEndpointQmux *self)
Packit Service ac8c34
{
Packit Service ac8c34
    if (self->priv->input_source) {
Packit Service ac8c34
        g_source_destroy (self->priv->input_source);
Packit Service ac8c34
        g_clear_pointer (&self->priv->input_source, g_source_unref);
Packit Service ac8c34
    }
Packit Service ac8c34
    g_clear_object (&self->priv->istream);
Packit Service ac8c34
    g_clear_object (&self->priv->ostream);
Packit Service ac8c34
    g_clear_object (&self->priv->socket_connection);
Packit Service ac8c34
    g_clear_object (&self->priv->socket_client);
Packit Service ac8c34
    if (self->priv->fd >= 0) {
Packit Service ac8c34
        close (self->priv->fd);
Packit Service ac8c34
        self->priv->fd = -1;
Packit Service ac8c34
    }
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
endpoint_close (QmiEndpoint         *endpoint,
Packit Service ac8c34
                guint                timeout,
Packit Service ac8c34
                GCancellable        *cancellable,
Packit Service ac8c34
                GAsyncReadyCallback  callback,
Packit Service ac8c34
                gpointer             user_data)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
    GTask *task;
Packit Service ac8c34
Packit Service ac8c34
    self = QMI_ENDPOINT_QMUX (endpoint);
Packit Service ac8c34
    task = g_task_new (self, cancellable, callback, user_data);
Packit Service ac8c34
Packit Service ac8c34
    destroy_iostream (self);
Packit Service ac8c34
Packit Service ac8c34
    g_task_return_boolean (task, TRUE);
Packit Service ac8c34
    g_object_unref (task);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
QmiEndpointQmux *
Packit Service ac8c34
qmi_endpoint_qmux_new (QmiFile *file,
Packit Service ac8c34
                       gchar *proxy_path,
Packit Service ac8c34
                       QmiClientCtl *client_ctl)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self;
Packit Service ac8c34
Packit Service ac8c34
    if (!file)
Packit Service ac8c34
        return NULL;
Packit Service ac8c34
Packit Service ac8c34
    self = g_object_new (QMI_TYPE_ENDPOINT_QMUX,
Packit Service ac8c34
                         QMI_ENDPOINT_FILE, file,
Packit Service ac8c34
                         NULL);
Packit Service ac8c34
    self->priv->proxy_path = proxy_path;
Packit Service ac8c34
    self->priv->client_ctl = g_object_ref (client_ctl);
Packit Service ac8c34
    return self;
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
/*****************************************************************************/
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
qmi_endpoint_qmux_init (QmiEndpointQmux *self)
Packit Service ac8c34
{
Packit Service ac8c34
    self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
Packit Service ac8c34
                                              QMI_TYPE_ENDPOINT_QMUX,
Packit Service ac8c34
                                              QmiEndpointQmuxPrivate);
Packit Service ac8c34
    self->priv->fd = -1;
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
dispose (GObject *object)
Packit Service ac8c34
{
Packit Service ac8c34
    QmiEndpointQmux *self = QMI_ENDPOINT_QMUX (object);
Packit Service ac8c34
Packit Service ac8c34
    destroy_iostream (self);
Packit Service ac8c34
Packit Service ac8c34
    G_OBJECT_CLASS (qmi_endpoint_qmux_parent_class)->dispose (object);
Packit Service ac8c34
}
Packit Service ac8c34
Packit Service ac8c34
static void
Packit Service ac8c34
qmi_endpoint_qmux_class_init (QmiEndpointQmuxClass *klass)
Packit Service ac8c34
{
Packit Service ac8c34
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
Packit Service ac8c34
    QmiEndpointClass *endpoint_class = QMI_ENDPOINT_CLASS (klass);
Packit Service ac8c34
Packit Service ac8c34
    g_type_class_add_private (object_class, sizeof (QmiEndpointQmuxPrivate));
Packit Service ac8c34
Packit Service ac8c34
    object_class->dispose = dispose;
Packit Service ac8c34
Packit Service ac8c34
    endpoint_class->open = endpoint_open;
Packit Service ac8c34
    endpoint_class->open_finish = endpoint_open_finish;
Packit Service ac8c34
    endpoint_class->is_open = endpoint_is_open;
Packit Service ac8c34
    endpoint_class->send = endpoint_send;
Packit Service ac8c34
    endpoint_class->close = endpoint_close;
Packit Service ac8c34
    endpoint_class->close_finish = endpoint_close_finish;
Packit Service ac8c34
}