diff options
author | Jens Georg <mail@jensge.org> | 2022-06-19 20:54:44 +0200 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2022-10-10 23:29:40 +0200 |
commit | ccb98911b5f4cdc40bc97b32ce3bfa83e212d869 (patch) | |
tree | edf53c4623d867afa04318d5b340cbe442de71c1 | |
parent | 84e07468e3f31e12873f51439dbdff27063b7e3b (diff) | |
download | gupnp-tools-ccb98911b5f4cdc40bc97b32ce3bfa83e212d869.tar.gz |
event-dumper: New tool
-rw-r--r-- | src/event-dumper/event-dumper.c | 181 | ||||
-rw-r--r-- | src/event-dumper/meson.build | 1 | ||||
-rw-r--r-- | src/meson.build | 1 |
3 files changed, 183 insertions, 0 deletions
diff --git a/src/event-dumper/event-dumper.c b/src/event-dumper/event-dumper.c new file mode 100644 index 0000000..77f901b --- /dev/null +++ b/src/event-dumper/event-dumper.c @@ -0,0 +1,181 @@ +#include <glib-unix.h> +#include <glib.h> +#include <libgupnp/gupnp.h> + +#include <iso646.h> + +void +on_variable_notify (GUPnPServiceProxy *proxy, + const char *variable, + GValue *value, + gpointer user_data) +{ + g_autoptr (GDateTime) dt = g_date_time_new_now_local (); + g_autofree char *timestr = g_date_time_format_iso8601 (dt); + g_auto (GValue) v = G_VALUE_INIT; + g_value_init (&v, G_TYPE_STRING); + g_value_transform (value, &v); + + g_print ("%s|%s|%s|%s|%s\n", + timestr, + gupnp_service_info_get_udn (GUPNP_SERVICE_INFO (user_data)), + gupnp_service_info_get_id (GUPNP_SERVICE_INFO (user_data)), + variable, + g_value_get_string (&v)); +} + +void +on_introspection (GObject *source, GAsyncResult *res, gpointer user_data) +{ + g_autoptr (GError) error = NULL; + + g_autoptr (GUPnPServiceIntrospection) is = + gupnp_service_info_introspect_finish ( + GUPNP_SERVICE_INFO (source), + res, + &error); + + g_autofree char *id = + gupnp_service_info_get_id (GUPNP_SERVICE_INFO (source)); + + if (error != NULL) { + g_warning ("Failed to introspect service proxy %s: %s", + id, + error->message); + + return; + } else { + g_info ("Got introspection for %s", id); + } + + const GList *state_variables = + gupnp_service_introspection_list_state_variables (is); + for (const GList *it = state_variables; it != NULL; + it = g_list_next (it)) { + GUPnPServiceStateVariableInfo *info = it->data; + if (not info->send_events) + continue; + + g_info ("Subscribing to %s (type: %s)", + info->name, + g_type_name (info->type)); + + gupnp_service_proxy_add_notify (GUPNP_SERVICE_PROXY (source), + info->name, + info->type, + on_variable_notify, + source); + } +} + +void +subscribe_to_proxy (GUPnPServiceProxy *sp, gpointer user_data) +{ + g_object_ref (sp); + g_autofree char *id = + gupnp_service_info_get_id (GUPNP_SERVICE_INFO (sp)); + + g_info ("Found new service proxy %s", id); + gupnp_service_info_introspect_async (GUPNP_SERVICE_INFO (sp), + NULL, + on_introspection, + NULL); + gupnp_service_proxy_set_subscribed (sp, TRUE); +} + +void +on_proxy_available (GUPnPControlPoint *cp, + GUPnPDeviceProxy *dp, + gpointer user_data) +{ + g_autofree char *id = + gupnp_device_info_get_friendly_name (GUPNP_DEVICE_INFO (dp)); + + g_info ("New device %s, type %s at %s", + id, + gupnp_device_info_get_device_type (GUPNP_DEVICE_INFO (dp)), + gupnp_device_info_get_location (GUPNP_DEVICE_INFO (dp))); + + GList *services = + gupnp_device_info_list_services (GUPNP_DEVICE_INFO (dp)); + + g_list_foreach ((GList *) services, (GFunc) subscribe_to_proxy, NULL); + + // Shallow-free the list, so we keep a reference to each service + g_list_free_full (services, (GDestroyNotify) g_object_unref); + + g_object_ref (dp); +} + +void +on_proxy_unavailable (GUPnPControlPoint *cp, + GUPnPDeviceProxy *dp, + gpointer user_data) +{ + g_autofree char *id = + gupnp_device_info_get_friendly_name (GUPNP_DEVICE_INFO (dp)); + + g_info ("Lost service proxy %s", id); + + // Dropping the reference we added in on_proxy_available + g_object_unref (dp); +} + +void +on_context_available (GUPnPContextManager *cm, + GUPnPContext *ctx, + gpointer user_data) +{ + + g_info ("New context: %s", + gssdp_client_get_host_ip (GSSDP_CLIENT (ctx))); + g_autoptr (GUPnPControlPoint) cp = + gupnp_control_point_new (ctx, "upnp:rootdevice"); + + g_signal_connect (cp, + "device-proxy-available", + G_CALLBACK (on_proxy_available), + NULL); + + g_signal_connect (cp, + "device-proxy-unavailable", + G_CALLBACK (on_proxy_unavailable), + NULL); + + gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE); + + gupnp_context_manager_manage_control_point (cm, cp); +} + +void +on_context_unavailable (GUPnPContextManager *cm, + GUPnPContext *ctx, + gpointer user_data) +{ + g_info ("Context gone: %s", + gssdp_client_get_host_ip (GSSDP_CLIENT (ctx))); +} + +int +main (int argc, char *argv[]) +{ + g_autoptr (GUPnPContextManager) cm = gupnp_context_manager_create (0); + g_autoptr (GMainLoop) loop = g_main_loop_new (NULL, FALSE); + + g_signal_connect (cm, + "context-available", + G_CALLBACK (on_context_available), + NULL); + + g_signal_connect (cm, + "context-unavailable", + G_CALLBACK (on_context_unavailable), + NULL); + + g_unix_signal_add (SIGINT, (GSourceFunc) g_main_loop_quit, loop); + g_unix_signal_add (SIGTERM, (GSourceFunc) g_main_loop_quit, loop); + + g_main_loop_run (loop); + + return 0; +} diff --git a/src/event-dumper/meson.build b/src/event-dumper/meson.build new file mode 100644 index 0000000..af358a7 --- /dev/null +++ b/src/event-dumper/meson.build @@ -0,0 +1 @@ +executable('gupnp-event-dumper', ['event-dumper.c'], dependencies : [gupnp, gobject], install: true) diff --git a/src/meson.build b/src/meson.build index 6601f45..ddca4d5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -8,3 +8,4 @@ endif subdir('discover') subdir('network-light') subdir('universal-cp') +subdir('event-dumper') |