qmi-proxy: initial implementation

This commit is contained in:
Aleksander Morgado 2013-08-06 13:01:54 +02:00
parent 4f10b4ed23
commit 852783f222
14 changed files with 824 additions and 4 deletions

4
.gitignore vendored
View File

@ -62,6 +62,10 @@ src/qmicli/test/Makefile
src/qmicli/test/Makefile.in
src/qmicli/test/test-helpers
src/qmi-proxy/.deps
src/qmi-proxy/.libs
src/qmi-proxy/qmi-proxy
build-aux/qmi-codegen/*.pyc
docs/reference/libqmi-glib/version.xml

View File

@ -97,6 +97,7 @@ AC_CONFIG_FILES([Makefile
src/libqmi-glib/test/Makefile
src/qmicli/Makefile
src/qmicli/test/Makefile
src/qmi-proxy/Makefile
utils/Makefile
docs/Makefile
docs/reference/Makefile

View File

@ -144,5 +144,19 @@
{ "name" : "Sync",
"type" : "Indication",
"service" : "CTL",
"id" : "0x0027" }
"id" : "0x0027" },
// *********************************************************************************
// Internal
{ "name" : "Internal Proxy Open",
"type" : "Message",
"service" : "CTL",
"id" : "0xFF00",
"input" : [ { "name" : "Device Path",
"id" : "0x01",
"mandatory" : "yes",
"type" : "TLV",
"format" : "string" } ],
"output" : [ { "common-ref" : "Operation Result" } ] }
]

View File

@ -78,6 +78,24 @@ QmiDevicePrivate
qmi_device_get_type
</SECTION>
<SECTION>
<FILE>qmi-proxy</FILE>
<TITLE>QmiProxy</TITLE>
QMI_PROXY_SOCKET_PATH
QmiProxy
qmi_proxy_new
<SUBSECTION Standard>
QmiProxyClass
QMI_PROXY
QMI_PROXY_CLASS
QMI_PROXY_GET_CLASS
QMI_IS_PROXY
QMI_IS_PROXY_CLASS
QMI_TYPE_PROXY
QmiProxyPrivate
qmi_proxy_get_type
</SECTION>
<SECTION>
<FILE>qmi-enums</FILE>
QmiService
@ -731,6 +749,7 @@ qmi_message_new_from_raw
qmi_message_response_new
qmi_message_ref
qmi_message_unref
qmi_message_is_request
qmi_message_is_response
qmi_message_is_indication
qmi_message_get_service

View File

@ -43,6 +43,7 @@
<xi:include href="xml/qmi-message.xml"/>
<xi:include href="xml/qmi-device.xml"/>
<xi:include href="xml/qmi-client.xml"/>
<xi:include href="xml/qmi-proxy.xml"/>
<xi:include href="xml/qmi-enums.xml"/>
<xi:include href="xml/qmi-errors.xml"/>
<xi:include href="xml/qmi-utils.xml"/>

View File

@ -1,2 +1,2 @@
SUBDIRS = libqmi-glib qmicli
SUBDIRS = libqmi-glib qmicli qmi-proxy

View File

@ -30,7 +30,8 @@ libqmi_glib_la_SOURCES = \
qmi-utils.h qmi-utils.c \
qmi-message.h qmi-message.c \
qmi-device.h qmi-device.c \
qmi-client.h qmi-client.c
qmi-client.h qmi-client.c \
qmi-proxy.h qmi-proxy.c
libqmi_glib_la_LIBADD = \
${top_builddir}/src/libqmi-glib/generated/libqmi-glib-generated.la \
@ -57,7 +58,8 @@ include_HEADERS = \
qmi-utils.h \
qmi-message.h \
qmi-device.h \
qmi-client.h
qmi-client.h \
qmi-proxy.h
EXTRA_DIST = \
qmi-version.h.in

View File

@ -31,6 +31,7 @@
#include "qmi-version.h"
#include "qmi-device.h"
#include "qmi-client.h"
#include "qmi-proxy.h"
#include "qmi-message.h"
#include "qmi-enums.h"
#include "qmi-utils.h"

View File

@ -142,6 +142,20 @@ get_qmi_flags (QmiMessage *self)
return ((struct full_message *)(self->data))->qmi.service.header.flags;
}
/**
* qmi_message_is_request:
* @self: a #QmiMessage.
*
* Checks whether the given #QmiMessage is a request.
*
* Returns: %TRUE if @self is a request message, %FALSE otherwise.
*/
gboolean
qmi_message_is_request (QmiMessage *self)
{
return (!qmi_message_is_response (self) && !qmi_message_is_indication (self));
}
/**
* qmi_message_is_response:
* @self: a #QmiMessage.

View File

@ -67,6 +67,7 @@ void qmi_message_unref (QmiMessage *self);
/*****************************************************************************/
/* QMI Message content getters */
gboolean qmi_message_is_request (QmiMessage *self);
gboolean qmi_message_is_response (QmiMessage *self);
gboolean qmi_message_is_indication (QmiMessage *self);
QmiService qmi_message_get_service (QmiMessage *self);

521
src/libqmi-glib/qmi-proxy.c Normal file
View File

@ -0,0 +1,521 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* libqmi-glib -- GLib/GIO based library to control QMI devices
*
* 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 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
*/
#include <string.h>
#include <ctype.h>
#include <sys/file.h>
#include <errno.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <gio/gunixsocketaddress.h>
#include "qmi-error-types.h"
#include "qmi-device.h"
#include "qmi-ctl.h"
#include "qmi-utils.h"
#include "qmi-proxy.h"
#define BUFFER_SIZE 512
#define QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN 0xFF00
#define QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN_INPUT_TLV_DEVICE_PATH 0x01
G_DEFINE_TYPE (QmiProxy, qmi_proxy, G_TYPE_OBJECT)
struct _QmiProxyPrivate {
/* Unix socket service */
GSocketService *socket_service;
/* Clients */
GList *clients;
/* Devices */
GList *devices;
};
/*****************************************************************************/
typedef struct {
QmiProxy *proxy; /* not full ref */
GSocketConnection *connection;
GSource *connection_readable_source;
GByteArray *buffer;
QmiDevice *device;
QmiMessage *internal_proxy_open_request;
} Client;
static gboolean connection_readable_cb (GSocket *socket, GIOCondition condition, Client *client);
static void
client_free (Client *client)
{
g_source_destroy (client->connection_readable_source);
g_source_unref (client->connection_readable_source);
g_output_stream_close (g_io_stream_get_output_stream (G_IO_STREAM (client->connection)), NULL, NULL);
if (client->buffer)
g_byte_array_unref (client->buffer);
if (client->internal_proxy_open_request)
g_byte_array_unref (client->internal_proxy_open_request);
g_object_unref (client->connection);
g_slice_free (Client, client);
}
static void
connection_close (Client *client)
{
QmiProxy *self = client->proxy;
client_free (client);
self->priv->clients = g_list_remove (self->priv->clients, client);
}
static QmiDevice *
find_device_for_path (QmiProxy *self,
const gchar *path)
{
GList *l;
for (l = self->priv->devices; l; l = g_list_next (l)) {
QmiDevice *device;
device = (QmiDevice *)l->data;
/* Return if found */
if (g_str_equal (qmi_device_get_path (device), path))
return device;
}
return NULL;
}
static gboolean
send_message (Client *client,
QmiMessage *message,
GError **error)
{
if (!g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (client->connection)),
message->data,
message->len,
NULL, /* bytes_written */
NULL, /* cancellable */
error)) {
g_prefix_error (error, "Cannot send message to client: ");
return FALSE;
}
return TRUE;
}
static void
complete_internal_proxy_open (Client *client)
{
QmiMessage *response;
GError *error = NULL;
g_debug ("connection to QMI device '%s' established", qmi_device_get_path (client->device));
g_assert (client->internal_proxy_open_request != NULL);
response = qmi_message_response_new (client->internal_proxy_open_request, QMI_PROTOCOL_ERROR_NONE);
if (!send_message (client, response, &error)) {
qmi_message_unref (response);
connection_close (client);
return;
}
qmi_message_unref (response);
qmi_message_unref (client->internal_proxy_open_request);
client->internal_proxy_open_request = NULL;
}
static void
device_open_ready (QmiDevice *device,
GAsyncResult *res,
Client *client)
{
QmiProxy *self = client->proxy;
QmiDevice *existing;
GError *error = NULL;
if (!qmi_device_open_finish (device, res, &error)) {
g_debug ("couldn't open QMI device: %s", error->message);
g_debug ("client connection closed");
connection_close (client);
g_error_free (error);
return;
}
/* Store device in the proxy independently */
existing = find_device_for_path (self, qmi_device_get_path (client->device));
if (existing) {
/* Race condition, we created two QmiDevices for the same port, just skip ours, no big deal */
g_object_unref (client->device);
client->device = g_object_ref (existing);
} else {
/* Keep the newly added device in the proxy */
self->priv->devices = g_list_append (self->priv->devices, g_object_ref (client->device));
}
complete_internal_proxy_open (client);
}
static void
device_new_ready (GObject *source,
GAsyncResult *res,
Client *client)
{
GError *error = NULL;
client->device = qmi_device_new_finish (res, &error);
if (!client->device) {
g_debug ("couldn't open QMI device: %s", error->message);
g_debug ("client connection closed");
connection_close (client);
g_error_free (error);
return;
}
qmi_device_open (client->device,
QMI_DEVICE_OPEN_FLAGS_NONE,
10,
NULL,
(GAsyncReadyCallback)device_open_ready,
client);
}
static gboolean
process_internal_proxy_open (Client *client,
QmiMessage *message)
{
QmiProxy *self = client->proxy;
const guint8 *buffer;
guint16 buffer_len;
gchar *device_file_path;
buffer = qmi_message_get_raw_tlv (message,
QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN_INPUT_TLV_DEVICE_PATH,
&buffer_len);
if (!buffer) {
g_debug ("ignoring message from client: invalid proxy open request");
return FALSE;
}
qmi_utils_read_string_from_buffer (&buffer, &buffer_len, 0, 0, &device_file_path);
g_debug ("valid request to open connection to QMI device file: %s", device_file_path);
/* Keep it */
client->internal_proxy_open_request = qmi_message_ref (message);
client->device = find_device_for_path (self, device_file_path);
/* Need to create a device ourselves */
if (!client->device) {
GFile *file;
file = g_file_new_for_path (device_file_path);
qmi_device_new (file,
NULL,
(GAsyncReadyCallback)device_new_ready,
client);
g_object_unref (file);
g_free (device_file_path);
return TRUE;
}
g_free (device_file_path);
/* Keep a reference to the device in the client */
g_object_ref (client->device);
complete_internal_proxy_open (client);
return FALSE;
}
static void
device_command_ready (QmiDevice *device,
GAsyncResult *res,
Client *client)
{
QmiMessage *response;
GError *error = NULL;
response = qmi_device_command_finish (device, res, &error);
if (!response) {
g_warning ("sending request to device failed: %s", error->message);
g_error_free (error);
return;
}
if (!send_message (client, response, &error)) {
qmi_message_unref (response);
connection_close (client);
return;
}
qmi_message_unref (response);
}
static gboolean
process_message (Client *client,
QmiMessage *message)
{
/* Accept only request messages from the client */
if (!qmi_message_is_request (message)) {
g_debug ("invalid message from client: not a request message");
return FALSE;
}
if (qmi_message_get_service (message) == QMI_SERVICE_CTL) {
if (qmi_message_get_message_id (message) == QMI_MESSAGE_CTL_INTERNAL_PROXY_OPEN)
return process_internal_proxy_open (client, message);
/* CTL, fixup transaction id and keep on */
}
/* Non-CTL service, just forward to qmi device */
qmi_device_command (client->device,
message,
10, /* for now... */
NULL,
(GAsyncReadyCallback)device_command_ready,
client);
return TRUE;
}
static void
parse_request (Client *client)
{
do {
GError *error = NULL;
QmiMessage *message;
/* Every message received must start with the QMUX marker.
* If it doesn't, we broke framing :-/
* If we broke framing, an error should be reported and the device
* should get closed */
if (client->buffer->len > 0 &&
client->buffer->data[0] != QMI_MESSAGE_QMUX_MARKER) {
/* TODO: Report fatal error */
g_warning ("QMI framing error detected");
return;
}
message = qmi_message_new_from_raw (client->buffer, &error);
if (!message) {
if (!error)
/* More data we need */
return;
/* Warn about the issue */
g_warning ("Invalid QMI message received: '%s'",
error->message);
g_error_free (error);
} else {
/* Play with the received message */
process_message (client, message);
qmi_message_unref (message);
}
} while (client->buffer->len > 0);
}
static gboolean
connection_readable_cb (GSocket *socket,
GIOCondition condition,
Client *client)
{
guint8 buffer[BUFFER_SIZE];
GError *error = NULL;
gssize read;
if (condition & G_IO_HUP || condition & G_IO_ERR) {
g_debug ("client connection closed");
connection_close (client);
return FALSE;
}
if (!(condition & G_IO_IN || condition & G_IO_PRI))
return TRUE;
read = g_input_stream_read (g_io_stream_get_input_stream (G_IO_STREAM (client->connection)),
buffer,
BUFFER_SIZE,
NULL,
&error);
if (read < 0) {
g_warning ("Error reading from istream: %s", error ? error->message : "unknown");
if (error)
g_error_free (error);
/* Close the device */
connection_close (client);
return FALSE;
}
if (read == 0)
return TRUE;
/* else, read > 0 */
if (!G_UNLIKELY (client->buffer))
client->buffer = g_byte_array_sized_new (read);
g_byte_array_append (client->buffer, buffer, read);
/* Try to parse input messages */
parse_request (client);
return TRUE;
}
static void
incoming_cb (GSocketService *service,
GSocketConnection *connection,
GObject *unused,
QmiProxy *self)
{
Client *client;
g_debug ("client connection open...");
/* Create client */
client = g_slice_new0 (Client);
client->proxy = self;
client->connection = g_object_ref (connection);
client->connection_readable_source = g_socket_create_source (g_socket_connection_get_socket (client->connection),
G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
NULL);
g_source_set_callback (client->connection_readable_source,
(GSourceFunc)connection_readable_cb,
client,
NULL);
g_source_attach (client->connection_readable_source, NULL);
/* Keep the client info around */
self->priv->clients = g_list_append (self->priv->clients, client);
}
static gboolean
setup_socket_service (QmiProxy *self,
GError **error)
{
GSocketAddress *socket_address;
GSocket *socket;
socket = g_socket_new (G_SOCKET_FAMILY_UNIX,
G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_DEFAULT,
error);
if (!socket)
return FALSE;
/* Bind to address */
socket_address = (g_unix_socket_address_new_with_type (
QMI_PROXY_SOCKET_PATH,
-1,
G_UNIX_SOCKET_ADDRESS_ABSTRACT));
if (!g_socket_bind (socket, socket_address, TRUE, error))
return FALSE;
g_object_unref (socket_address);
g_debug ("creating UNIX socket service...");
/* Listen */
if (!g_socket_listen (socket, error)) {
g_object_unref (socket);
return FALSE;
}
/* Create socket service */
self->priv->socket_service = g_socket_service_new ();
g_signal_connect (self->priv->socket_service, "incoming", G_CALLBACK (incoming_cb), self);
if (!g_socket_listener_add_socket (G_SOCKET_LISTENER (self->priv->socket_service),
socket,
NULL, /* don't pass an object, will take a reference */
error)) {
g_prefix_error (error, "Error adding socket at '%s' to socket service: ", QMI_PROXY_SOCKET_PATH);
g_object_unref (socket);
return FALSE;
}
g_debug ("starting UNIX socket service at '%s'...", QMI_PROXY_SOCKET_PATH);
g_socket_service_start (self->priv->socket_service);
g_object_unref (socket);
return TRUE;
}
/*****************************************************************************/
QmiProxy *
qmi_proxy_new (GError **error)
{
QmiProxy *self;
self = g_object_new (QMI_TYPE_PROXY, NULL);
if (!setup_socket_service (self, error))
g_clear_object (&self);
return self;
}
static void
qmi_proxy_init (QmiProxy *self)
{
/* Setup private data */
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
QMI_TYPE_PROXY,
QmiProxyPrivate);
}
static void
dispose (GObject *object)
{
QmiProxyPrivate *priv = QMI_PROXY (object)->priv;
if (priv->clients) {
g_list_free_full (priv->clients, (GDestroyNotify) client_free);
priv->clients = NULL;
}
if (priv->socket_service) {
if (g_socket_service_is_active (priv->socket_service))
g_socket_service_stop (priv->socket_service);
g_clear_object (&priv->socket_service);
g_unlink (QMI_PROXY_SOCKET_PATH);
g_debug ("UNIX socket service at '%s' stopped", QMI_PROXY_SOCKET_PATH);
}
G_OBJECT_CLASS (qmi_proxy_parent_class)->dispose (object);
}
static void
qmi_proxy_class_init (QmiProxyClass *proxy_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (proxy_class);
g_type_class_add_private (object_class, sizeof (QmiProxyPrivate));
/* Virtual methods */
object_class->dispose = dispose;
}

View File

@ -0,0 +1,55 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* libqmi-glib -- GLib/GIO based library to control QMI devices
*
* 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 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, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@lanedo.com>
*/
#ifndef QMI_PROXY_H
#define QMI_PROXY_H
#include <glib-object.h>
#include <gio/gio.h>
#define QMI_TYPE_PROXY (qmi_proxy_get_type ())
#define QMI_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), QMI_TYPE_PROXY, QmiProxy))
#define QMI_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), QMI_TYPE_PROXY, QmiProxyClass))
#define QMI_IS_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), QMI_TYPE_PROXY))
#define QMI_IS_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), QMI_TYPE_PROXY))
#define QMI_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), QMI_TYPE_PROXY, QmiProxyClass))
typedef struct _QmiProxy QmiProxy;
typedef struct _QmiProxyClass QmiProxyClass;
typedef struct _QmiProxyPrivate QmiProxyPrivate;
#define QMI_PROXY_SOCKET_PATH "qmi-proxy"
struct _QmiProxy {
GObject parent;
QmiProxyPrivate *priv;
};
struct _QmiProxyClass {
GObjectClass parent;
};
GType qmi_proxy_get_type (void);
QmiProxy *qmi_proxy_new (GError **error);
#endif /* QMI_PROXY_H */

16
src/qmi-proxy/Makefile.am Normal file
View File

@ -0,0 +1,16 @@
sbin_PROGRAMS = qmi-proxy
qmi_proxy_CPPFLAGS = \
$(GLIB_CFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/src/libqmi-glib \
-I$(top_srcdir)/src/libqmi-glib/generated \
-I$(top_builddir)/src/libqmi-glib \
-I$(top_builddir)/src/libqmi-glib/generated
qmi_proxy_SOURCES = qmi-proxy.c
qmi_proxy_LDADD = \
$(GLIB_LIBS) \
$(top_builddir)/src/libqmi-glib/libqmi-glib.la

171
src/qmi-proxy/qmi-proxy.c Normal file
View File

@ -0,0 +1,171 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* qmid -- A proxy to communicate with QMI ports
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright (C) 2013 Aleksander Morgado <aleksander@gnu.org>
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <gio/gio.h>
#include <glib-unix.h>
#include <libqmi-glib.h>
#define PROGRAM_NAME "qmid"
#define PROGRAM_VERSION PACKAGE_VERSION
/* Globals */
static GMainLoop *loop;
static QmiProxy *proxy;
/* Main options */
static gboolean version_flag;
static GOptionEntry main_entries[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version_flag,
"Print version",
NULL
},
{ NULL }
};
static gboolean
quit_cb (gpointer user_data)
{
if (loop) {
g_warning ("Caught signal, stopping the loop...");
g_idle_add ((GSourceFunc) g_main_loop_quit, loop);
}
return FALSE;
}
static void
log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
const gchar *log_level_str;
time_t now;
gchar time_str[64];
struct tm *local_time;
gboolean err;
now = time ((time_t *) NULL);
local_time = localtime (&now);
strftime (time_str, 64, "%d %b %Y, %H:%M:%S", local_time);
err = FALSE;
switch (log_level) {
case G_LOG_LEVEL_WARNING:
log_level_str = "-Warning **";
err = TRUE;
break;
case G_LOG_LEVEL_CRITICAL:
case G_LOG_FLAG_FATAL:
case G_LOG_LEVEL_ERROR:
log_level_str = "-Error **";
err = TRUE;
break;
case G_LOG_LEVEL_DEBUG:
log_level_str = "[Debug]";
break;
default:
log_level_str = "";
break;
}
g_fprintf (err ? stderr : stdout,
"[%s] %s %s\n",
time_str,
log_level_str,
message);
}
static void
print_version_and_exit (void)
{
g_print ("\n"
PROGRAM_NAME " " PROGRAM_VERSION "\n"
"Copyright (2013) Aleksander Morgado\n"
"License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl-2.0.html>\n"
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n"
"\n");
exit (EXIT_SUCCESS);
}
/*****************************************************************************/
int main (int argc, char **argv)
{
GError *error = NULL;
GOptionContext *context;
setlocale (LC_ALL, "");
g_type_init ();
/* Setup option context, process it and destroy it */
context = g_option_context_new ("- Proxy for QMI devices");
g_option_context_add_main_entries (context, main_entries, NULL);
if (!g_option_context_parse (context, &argc, &argv, &error)) {
g_printerr ("error: %s\n",
error->message);
exit (EXIT_FAILURE);
}
g_option_context_free (context);
if (version_flag)
print_version_and_exit ();
g_log_set_handler (NULL, G_LOG_LEVEL_MASK, log_handler, NULL);
g_log_set_handler ("Qmi", G_LOG_LEVEL_MASK, log_handler, NULL);
/* Setup signals */
g_unix_signal_add (SIGINT, quit_cb, NULL);
g_unix_signal_add (SIGHUP, quit_cb, NULL);
g_unix_signal_add (SIGTERM, quit_cb, NULL);
/* Setup proxy */
proxy = qmi_proxy_new (&error);
if (!proxy) {
g_printerr ("error: %s\n", error->message);
exit (EXIT_FAILURE);
}
/* Loop */
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
g_main_loop_unref (loop);
/* Cleanup; releases socket and such */
g_object_unref (proxy);
return EXIT_SUCCESS;
}