|
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 |
}
|