[gssdp/wip/sniffer-rewrite] wip: refactor sniffer
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gssdp/wip/sniffer-rewrite] wip: refactor sniffer
- Date: Thu, 31 Jan 2019 21:21:17 +0000 (UTC)
commit 2c18c0533daf8e3b33a69e4e891f50a4210534b8
Author: Jens Georg <mail jensge org>
Date: Sun Jan 20 20:07:43 2019 +0100
wip: refactor sniffer
tools/gssdp-device-sniffer-window.c | 579 ++++++++++++++
tools/gssdp-device-sniffer-window.h | 29 +
...e-sniffer.ui => gssdp-device-sniffer-window.ui} | 300 ++++----
tools/gssdp-device-sniffer.c | 830 ---------------------
tools/gssdp-device-sniffer.gresource.xml | 6 +-
tools/main.c | 132 ++++
tools/meson.build | 20 +-
7 files changed, 893 insertions(+), 1003 deletions(-)
---
diff --git a/tools/gssdp-device-sniffer-window.c b/tools/gssdp-device-sniffer-window.c
new file mode 100644
index 0000000..ef7f270
--- /dev/null
+++ b/tools/gssdp-device-sniffer-window.c
@@ -0,0 +1,579 @@
+/* gssdp-device-sniffer-window.c
+ *
+ * Copyright 2019 Jens Georg
+ *
+ * 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 3 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/>.
+ */
+
+#include "libgssdp/gssdp-client-private.h"
+#include "gssdp-device-sniffer-window.h"
+
+#include <libsoup/soup.h>
+#include <libgssdp/gssdp.h>
+
+
+typedef enum {
+ PACKET_STORE_COLUMN_TIME,
+ PACKET_STORE_COLUMN_IP,
+ PACKET_STORE_COLUMN_INTERFACE,
+ PACKET_STORE_COLUMN_PACKET_TYPE,
+ PACKET_STORE_COLUMN_TARGET,
+ PACKET_STORE_COLUMN_HEADERS,
+ PACKET_STORE_COLUMN_RAW_ARRIVAL_TIME
+} PACKET_STORE_COLUMNS;
+
+typedef enum {
+ DEVICE_STORE_COLUMN_UUID,
+ DEVICE_STORE_COLUMN_FIRST_SEEN,
+ DEVICE_STORE_COLUMN_TYPE,
+ DEVICE_STORE_COLUMN_LOCATION
+} DEVICE_STORE_COLUMNS;
+
+static void
+on_trigger_rescan (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_about (GSimpleAction *action, GVariant *parameter, gpointer user_data);
+
+static void
+on_set_address_filter (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_show_address_filter (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_details_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_clear_packet_capture (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_packet_capture_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data);
+
+static void
+on_ssdp_message (GssdpDeviceSnifferWindow *self,
+ const gchar *from_ip,
+ gushort from_port,
+ _GSSDPMessageType type,
+ SoupMessageHeaders *headers,
+ GSSDPClient *client);
+
+static void
+on_resource_available (GssdpDeviceSnifferWindow *self,
+ const char *usn,
+ GList *locations,
+ GSSDPResourceBrowser *ssdp_resource_browser);
+
+static void
+on_resource_unavailable (GssdpDeviceSnifferWindow *self,
+ const char *usn,
+ GSSDPResourceBrowser *ssdp_resource_browser);
+
+static GActionEntry actions[] = {
+ { "clear-packet-capture", on_clear_packet_capture },
+ { "capture-packets", NULL, NULL, "true", on_packet_capture_activate },
+ { "trigger-rescan", on_trigger_rescan },
+ { "set-address-filter", on_set_address_filter },
+ { "show-packet-details", NULL, NULL, "true", on_details_activate },
+ { "show-address-filter", on_show_address_filter },
+ { "about", on_about }
+};
+
+struct _GssdpDeviceSnifferWindow
+{
+ GtkApplicationWindow parent_instance;
+
+ /* Template widgets */
+ GtkTreeView *packet_treeview;
+ GtkTreeView *device_details_treeview;
+ GtkMenuButton *window_menu;
+
+ GtkTextView *packet_details_textview;
+
+ /* UPnP stuff */
+ GSSDPClient *client;
+ GSSDPResourceBrowser *browser;
+ char *ip_filter;
+ gboolean capture_packets;
+};
+
+G_DEFINE_TYPE (GssdpDeviceSnifferWindow, gssdp_device_sniffer_window, GTK_TYPE_APPLICATION_WINDOW)
+
+#define SNIFFER_WINDOW_TEMPLATE "/org/gnome/GssdpDeviceSniffer/gssdp-device-sniffer-window.ui"
+#define SNIFFER_WINDOW_MENU_RESOURCE "/org/gnome/GssdpDeviceSniffer/window-menu.ui"
+
+static void
+on_trigger_rescan (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GssdpDeviceSnifferWindow *self = GSSDP_DEVICE_SNIFFER_WINDOW (user_data);
+
+ gssdp_resource_browser_rescan (self->browser);
+}
+
+static void
+on_about (GSimpleAction *action, GVariant *parameter, gpointer user_data)
+{
+#if 0
+ GtkWidget *dialog = NULL;
+
+ dialog = GTK_WIDGET (gtk_builder_get_object (builder,
+ "about-dialog"));
+ gtk_widget_show (dialog);
+#endif
+}
+
+static void
+on_set_address_filter (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+}
+
+static void
+on_show_address_filter (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+}
+
+static void
+on_details_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+}
+
+static void
+on_packet_capture_activate (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GssdpDeviceSnifferWindow *self = GSSDP_DEVICE_SNIFFER_WINDOW (user_data);
+
+ self->capture_packets = g_variant_get_boolean (parameter);
+ g_simple_action_set_state (action, parameter);
+}
+
+static void
+on_clear_packet_capture (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer user_data)
+{
+ GssdpDeviceSnifferWindow *self = GSSDP_DEVICE_SNIFFER_WINDOW (user_data);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean more;
+ time_t *arrival_time;
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (self->packet_treeview));
+ more = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (more) {
+ gtk_tree_model_get (model,
+ &iter,
+ PACKET_STORE_COLUMN_RAW_ARRIVAL_TIME, &arrival_time, -1);
+ g_free (arrival_time);
+ more = gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
+ }
+}
+
+static void
+packet_header_to_string (const char *header_name,
+ const char *header_val,
+ GString **text)
+{
+ g_string_append_printf (*text,
+ "%s: %s\n",
+ header_name,
+ header_val);
+}
+
+static void
+clear_textbuffer (GtkTextBuffer *textbuffer)
+{
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_bounds (textbuffer, &start, &end);
+ gtk_text_buffer_delete (textbuffer, &start, &end);
+}
+
+
+static void
+update_packet_details (GssdpDeviceSnifferWindow *self,
+ const char *text, unsigned int len)
+{
+ GtkTextBuffer *textbuffer;
+
+ textbuffer = gtk_text_view_get_buffer (self->packet_details_textview);
+
+ clear_textbuffer (textbuffer);
+ gtk_text_buffer_insert_at_cursor (textbuffer, text, len);
+}
+
+
+static void
+display_packet (GssdpDeviceSnifferWindow *self,
+ time_t arrival_time,
+ SoupMessageHeaders *packet_headers)
+{
+ GString *text;
+
+ text = g_string_new ("");
+ g_string_printf (text, "Received on: %s\nHeaders:\n\n",
+ ctime (&arrival_time));
+
+ soup_message_headers_foreach (packet_headers,
+ (SoupMessageHeadersForeachFunc)
+ packet_header_to_string,
+ &text);
+
+ update_packet_details (self, text->str, text->len);
+ g_string_free (text, TRUE);
+}
+
+
+static void
+on_packet_selected (GssdpDeviceSnifferWindow *self,
+ GtkTreeSelection *selection)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ time_t *arrival_time;
+
+ if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ SoupMessageHeaders *packet_headers;
+
+ gtk_tree_model_get (model,
+ &iter,
+ PACKET_STORE_COLUMN_HEADERS,
+ &packet_headers,
+ PACKET_STORE_COLUMN_RAW_ARRIVAL_TIME,
+ &arrival_time,
+ -1);
+ display_packet (self, *arrival_time, packet_headers);
+ g_boxed_free (SOUP_TYPE_MESSAGE_HEADERS, packet_headers);
+ }
+
+ else
+ update_packet_details (self, "", 0);
+}
+
+static gboolean
+on_treeview_popup_menu (GtkWidget *tv, GdkEventButton *event, gpointer user_data)
+{
+ if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
+ gtk_menu_popup_at_pointer (GTK_MENU (user_data), (GdkEvent *)event);
+ }
+
+ return FALSE;
+}
+
+
+static void
+gssdp_device_sniffer_window_class_init (GssdpDeviceSnifferWindowClass *klass)
+{
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ gtk_widget_class_set_template_from_resource (widget_class,
+ SNIFFER_WINDOW_TEMPLATE);
+ gtk_widget_class_bind_template_child (widget_class,
+ GssdpDeviceSnifferWindow,
+ packet_treeview);
+ gtk_widget_class_bind_template_child (widget_class,
+ GssdpDeviceSnifferWindow,
+ device_details_treeview);
+ gtk_widget_class_bind_template_child (widget_class,
+ GssdpDeviceSnifferWindow,
+ window_menu);
+ gtk_widget_class_bind_template_child (widget_class,
+ GssdpDeviceSnifferWindow,
+ packet_details_textview);
+}
+
+static void
+gssdp_device_sniffer_window_init (GssdpDeviceSnifferWindow *self)
+{
+ GtkBuilder *builder;
+ GError *error = NULL;
+ GtkTreeSelection *selection;
+ GtkWidget *menu;
+
+ gtk_widget_init_template (GTK_WIDGET (self));
+
+ builder = gtk_builder_new ();
+ gtk_builder_add_from_resource (builder, SNIFFER_WINDOW_MENU_RESOURCE, &error);
+
+ gtk_menu_button_set_menu_model (self->window_menu,
+ G_MENU_MODEL (gtk_builder_get_object (builder,
+ "sniffer-window-menu")));
+ g_action_map_add_action_entries (G_ACTION_MAP (self), actions, G_N_ELEMENTS (actions), self);
+
+
+ selection = gtk_tree_view_get_selection (self->packet_treeview);
+ g_signal_connect_swapped (selection,
+ "changed",
+ G_CALLBACK (on_packet_selected),
+ self);
+
+ menu = gtk_menu_new_from_model (G_MENU_MODEL (gtk_builder_get_object (builder,
+ "sniffer-context-menu")));
+ g_object_unref (builder);
+
+ gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (self->packet_treeview), NULL);
+ g_signal_connect (G_OBJECT (self->packet_treeview),
+ "button-press-event",
+ G_CALLBACK (on_treeview_popup_menu),
+ menu);
+
+ /* SSDP initialization */
+ self->client = g_initable_new (GSSDP_TYPE_CLIENT,
+ NULL,
+ &error,
+ //"address-family", G_SOCKET_FAMILY_IPV4,
+ //"interface", NULL,
+ NULL);
+ self->browser = gssdp_resource_browser_new (self->client,
+ GSSDP_ALL_RESOURCES);
+
+ g_signal_connect_swapped (self->client,
+ "message-received",
+ G_CALLBACK (on_ssdp_message),
+ self);
+ g_signal_connect_swapped (self->browser,
+ "resource-available",
+ G_CALLBACK (on_resource_available),
+ self);
+
+ g_signal_connect_swapped (self->browser,
+ "resource-unavailable",
+ G_CALLBACK (on_resource_unavailable),
+ self);
+
+ self->capture_packets = TRUE;
+ gssdp_resource_browser_set_active (self->browser, TRUE);
+}
+
+static const char *message_types[] = {"M-SEARCH", "RESPONSE", "NOTIFY"};
+
+static char **
+packet_to_treeview_data (GssdpDeviceSnifferWindow *self,
+ const gchar *from_ip,
+ time_t arrival_time,
+ _GSSDPMessageType type,
+ SoupMessageHeaders *headers)
+{
+ char **packet_data;
+ const char *target;
+ struct tm *tm;
+
+ packet_data = g_new0 (char *, 6);
+
+ /* Set the Time */
+ tm = localtime (&arrival_time);
+ packet_data[0] = g_strdup_printf ("%02d:%02d", tm->tm_hour, tm->tm_min);
+
+ /* Now the Source Address */
+ packet_data[1] = g_strdup (from_ip);
+
+ packet_data[2] = g_strdup (gssdp_client_get_interface (self->client));
+
+ /* Now the Packet Type */
+ packet_data[3] = g_strdup (message_types[type]);
+
+ /* Now the Packet Information */
+ if (type == _GSSDP_DISCOVERY_RESPONSE)
+ target = soup_message_headers_get_one (headers, "ST");
+ else
+ target = soup_message_headers_get_one (headers, "NT");
+
+ packet_data[4] = g_strdup (target);
+ packet_data[5] = NULL;
+
+ return packet_data;
+}
+
+
+static void
+append_packet (GssdpDeviceSnifferWindow *self,
+ const gchar *from_ip,
+ time_t arrival_time,
+ _GSSDPMessageType type,
+ SoupMessageHeaders *headers)
+{
+ GtkListStore *liststore;
+ GtkTreeIter iter;
+ char **packet_data;
+
+ liststore = GTK_LIST_STORE (
+ gtk_tree_view_get_model (self->packet_treeview));
+
+ packet_data = packet_to_treeview_data (self,
+ from_ip,
+ arrival_time,
+ type,
+ headers);
+
+ gtk_list_store_insert_with_values (liststore, &iter, 0,
+ PACKET_STORE_COLUMN_TIME, packet_data[0],
+ PACKET_STORE_COLUMN_IP, packet_data[1],
+ PACKET_STORE_COLUMN_INTERFACE, packet_data[2],
+ PACKET_STORE_COLUMN_PACKET_TYPE, packet_data[3],
+ PACKET_STORE_COLUMN_TARGET, packet_data[4],
+ PACKET_STORE_COLUMN_HEADERS, headers,
+ PACKET_STORE_COLUMN_RAW_ARRIVAL_TIME,
+ g_memdup (&arrival_time, sizeof (time_t)),
+ -1);
+ g_strfreev (packet_data);
+}
+
+
+static void
+on_ssdp_message (GssdpDeviceSnifferWindow *self,
+ const gchar *from_ip,
+ gushort from_port,
+ _GSSDPMessageType type,
+ SoupMessageHeaders *headers,
+ GSSDPClient *client)
+{
+ time_t arrival_time;
+
+ arrival_time = time (NULL);
+
+ if (type == _GSSDP_DISCOVERY_REQUEST)
+ return;
+
+ if (self->ip_filter != NULL && strcmp (self->ip_filter, from_ip) != 0)
+ return;
+
+ if (!self->capture_packets)
+ return;
+
+ append_packet (self, from_ip, arrival_time, type, headers);
+}
+
+static gboolean
+find_device (GtkTreeModel *model, const char *uuid, GtkTreeIter *iter)
+{
+ gboolean found = FALSE;
+ gboolean more;
+
+ more = gtk_tree_model_get_iter_first (model, iter);
+ while (more) {
+ char *device_uuid;
+ gtk_tree_model_get (model,
+ iter,
+ 0, &device_uuid, -1);
+ found = g_strcmp0 (device_uuid, uuid) == 0;
+ g_free (device_uuid);
+
+ if (found)
+ break;
+ more = gtk_tree_model_iter_next (model, iter);
+ }
+
+ return found;
+}
+
+static void
+append_device (GssdpDeviceSnifferWindow *self,
+ const char *uuid,
+ const char *first_notify,
+ const char *device_type,
+ const char *location)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ model = gtk_tree_view_get_model (self->device_details_treeview);
+
+ if (!find_device (model, uuid, &iter)) {
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (model),
+ &iter, 0,
+ DEVICE_STORE_COLUMN_UUID, uuid,
+ DEVICE_STORE_COLUMN_FIRST_SEEN, first_notify,
+ DEVICE_STORE_COLUMN_LOCATION, location, -1);
+ }
+
+ if (device_type) {
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+ DEVICE_STORE_COLUMN_TYPE, device_type, -1);
+ }
+}
+
+
+static void
+on_resource_available (GssdpDeviceSnifferWindow *self,
+ const char *usn,
+ GList *locations,
+ GSSDPResourceBrowser *ssdp_resource_browser)
+{
+ char **usn_tokens;
+ char *uuid;
+ char *device_type = NULL;
+ time_t current_time;
+ struct tm *tm;
+ char *first_notify;
+
+ current_time = time (NULL);
+ tm = localtime (¤t_time);
+ first_notify = g_strdup_printf ("%02d:%02d",
+ tm->tm_hour, tm->tm_min);
+
+ usn_tokens = g_strsplit (usn, "::", -1);
+ g_assert (usn_tokens != NULL && usn_tokens[0] != NULL);
+
+ uuid = usn_tokens[0] + 5; /* skip the prefix 'uuid:' */
+
+ if (usn_tokens[1] && strlen(usn_tokens[1]) != 0) {
+ char **urn_tokens;
+
+ urn_tokens = g_strsplit (usn_tokens[1], ":device:", -1);
+
+ if (urn_tokens[1])
+ device_type = g_strdup (urn_tokens[1]);
+ g_strfreev (urn_tokens);
+ }
+
+ /* Device Announcement */
+ append_device (self,
+ uuid,
+ first_notify,
+ device_type,
+ (char *) locations->data);
+
+ g_free (device_type);
+ g_free (first_notify);
+ g_strfreev (usn_tokens);
+}
+
+static void
+on_resource_unavailable (GssdpDeviceSnifferWindow *self,
+ const char *usn,
+ GSSDPResourceBrowser *ssdp_resource_browser)
+{
+}
diff --git a/tools/gssdp-device-sniffer-window.h b/tools/gssdp-device-sniffer-window.h
new file mode 100644
index 0000000..f45db0f
--- /dev/null
+++ b/tools/gssdp-device-sniffer-window.h
@@ -0,0 +1,29 @@
+/* gssdp-device-sniffer-window.h
+ *
+ * Copyright 2019 Jens Georg
+ *
+ * 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 3 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/>.
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GSSDP_DEVICE_SNIFFER_TYPE_WINDOW (gssdp_device_sniffer_window_get_type())
+
+G_DECLARE_FINAL_TYPE (GssdpDeviceSnifferWindow, gssdp_device_sniffer_window, GSSDP_DEVICE_SNIFFER, WINDOW,
GtkApplicationWindow)
+
+G_END_DECLS
diff --git a/tools/gssdp-device-sniffer.ui b/tools/gssdp-device-sniffer-window.ui
similarity index 51%
rename from tools/gssdp-device-sniffer.ui
rename to tools/gssdp-device-sniffer-window.ui
index f1acc7c..ab578b2 100644
--- a/tools/gssdp-device-sniffer.ui
+++ b/tools/gssdp-device-sniffer-window.ui
@@ -2,9 +2,38 @@
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
- <object class="GtkWindow" id="main-window">
+ <object class="GtkListStore" id="device_liststore">
+ <columns>
+ <!-- column-name uuid -->
+ <column type="gchararray"/>
+ <!-- column-name first_seen -->
+ <column type="gchararray"/>
+ <!-- column-name type -->
+ <column type="gchararray"/>
+ <!-- column-name location -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkListStore" id="packet_liststore">
+ <columns>
+ <!-- column-name time -->
+ <column type="gchararray"/>
+ <!-- column-name ip -->
+ <column type="gchararray"/>
+ <!-- column-name interface -->
+ <column type="gchararray"/>
+ <!-- column-name packet_type -->
+ <column type="gchararray"/>
+ <!-- column-name target -->
+ <column type="gchararray"/>
+ <!-- column-name headers -->
+ <column type="SoupMessageHeaders"/>
+ <!-- column-name raw_arrival_time -->
+ <column type="gpointer"/>
+ </columns>
+ </object>
+ <template class="GssdpDeviceSnifferWindow" parent="GtkApplicationWindow">
<property name="can_focus">False</property>
- <signal name="delete-event" handler="on_delete_event" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
@@ -21,7 +50,7 @@
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Clear packet capture</property>
- <signal name="clicked" handler="on_clear_packet_capture_activate" swapped="no"/>
+ <property name="action_name">win.clear-packet-capture</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@@ -43,7 +72,7 @@
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Toggle packet capture</property>
<property name="active">True</property>
- <signal name="toggled" handler="on_enable_packet_capture_activate" object="capture-image"
swapped="no"/>
+ <property name="action_name">win.capture-packets</property>
<child>
<object class="GtkImage" id="capture-image">
<property name="visible">True</property>
@@ -94,7 +123,7 @@
</object>
</child>
<child>
- <object class="GtkMenuButton" id="window-menu">
+ <object class="GtkMenuButton" id="window_menu">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
@@ -130,12 +159,68 @@
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
- <object class="GtkTreeView" id="packet-treeview">
+ <object class="GtkTreeView" id="packet_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="model">packet_liststore</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Time</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Source Address</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Interface</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Packet Type</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Packet Information</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">4</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
</object>
</child>
</object>
@@ -151,7 +236,7 @@
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
- <object class="GtkTextView" id="packet-details-textview">
+ <object class="GtkTextView" id="packet_details_textview">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="editable">False</property>
@@ -180,12 +265,57 @@
<property name="margin_bottom">6</property>
<property name="shadow_type">in</property>
<child>
- <object class="GtkTreeView" id="device-details-treeview">
+ <object class="GtkTreeView" id="device_details_treeview">
<property name="visible">True</property>
<property name="can_focus">True</property>
+ <property name="model">device_liststore</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Unique Identifier</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">First Notify</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Device Type</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">2</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn">
+ <property name="title" translatable="yes">Location</property>
+ <child>
+ <object class="GtkCellRendererText"/>
+ <attributes>
+ <attribute name="text">3</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
</object>
</child>
</object>
@@ -197,157 +327,5 @@
</child>
</object>
</child>
- </object>
- <object class="GtkAboutDialog" id="about-dialog">
- <property name="can_focus">False</property>
- <property name="resizable">False</property>
- <property name="type_hint">normal</property>
- <property name="transient_for">main-window</property>
- <property name="copyright" translatable="yes">Copyright © 2007 Zeeshan Ali (Khattak)</property>
- <property name="comments" translatable="yes">A Device Sniffer tool based on GSSDP framework.
-Inspired by Intel Tools for UPnP.</property>
- <property name="authors">Zeeshan Ali (Khattak) <zeeshanak gnome org></property>
- <property name="translator_credits" translatable="yes" comments="TRANSLATORS: Replace this string with
your names, one name per line.">translator-credits</property>
- <property name="logo_icon_name"/>
- <property name="license_type">lgpl-2-1</property>
- <signal name="delete-event" handler="gtk_widget_hide" object="about-dialog" swapped="yes"/>
- <signal name="response" handler="gtk_widget_hide" object="about-dialog" swapped="yes"/>
- <child type="titlebar">
- <placeholder/>
- </child>
- <child internal-child="vbox">
- <object class="GtkBox" id="aboutdialog-vbox1">
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="aboutdialog-action_area1">
- <property name="can_focus">False</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- </child>
- </object>
- <object class="GtkDialog" id="address-filter-dialog">
- <property name="can_focus">False</property>
- <property name="border_width">7</property>
- <property name="resizable">False</property>
- <property name="type_hint">dialog</property>
- <property name="transient_for">main-window</property>
- <signal name="delete-event" handler="gtk_widget_hide_on_delete" swapped="no"/>
- <signal name="response" handler="on_address_filter_dialog_response" swapped="no"/>
- <child type="titlebar">
- <placeholder/>
- </child>
- <child internal-child="vbox">
- <object class="GtkBox" id="dialog-vbox1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">8</property>
- <child internal-child="action_area">
- <object class="GtkButtonBox" id="dialog-action_area1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="layout_style">end</property>
- <child>
- <object class="GtkButton" id="closebutton1">
- <property name="label">gtk-close</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="can_default">True</property>
- <property name="receives_default">False</property>
- <property name="use_stock">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="pack_type">end</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkBox" id="vbox1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="border_width">5</property>
- <property name="orientation">vertical</property>
- <property name="spacing">6</property>
- <child>
- <object class="GtkRadioButton" id="dont-use-filter-radiobutton">
- <property name="label" translatable="yes">No filter, capture all traffic</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="halign">start</property>
- <property name="use_underline">True</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkRadioButton" id="use-filter-radiobutton">
- <property name="label" translatable="yes">Use IP address filter</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="halign">start</property>
- <property name="use_underline">True</property>
- <property name="draw_indicator">True</property>
- <property name="group">dont-use-filter-radiobutton</property>
- <signal name="toggled" handler="on_use_filter_radiobutton_toggled" swapped="no"/>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">1</property>
- </packing>
- </child>
- <child>
- <object class="GtkEntry" id="address-entry0">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="margin_left">23</property>
- <property name="max_length">46</property>
- <property name="activates_default">True</property>
- <property name="width_chars">47</property>
- <property name="caps_lock_warning">False</property>
- <property name="placeholder_text" translatable="yes">IP address for filter</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">False</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
- <packing>
- <property name="expand">True</property>
- <property name="fill">True</property>
- <property name="position">1</property>
- </packing>
- </child>
- </object>
- </child>
- <action-widgets>
- <action-widget response="-5">closebutton1</action-widget>
- </action-widgets>
- </object>
+ </template>
</interface>
diff --git a/tools/gssdp-device-sniffer.gresource.xml b/tools/gssdp-device-sniffer.gresource.xml
index ec8dc93..0cda3c4 100644
--- a/tools/gssdp-device-sniffer.gresource.xml
+++ b/tools/gssdp-device-sniffer.gresource.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
- <gresource prefix="/org/gupnp/GSSDP">
- <file preprocess="xml-stripblanks" alias="DeviceSniffer.ui">gssdp-device-sniffer.ui</file>
- <file alias="WindowMenu.ui">window-menu.ui</file>
+ <gresource prefix="/org/gnome/GssdpDeviceSniffer">
+ <file>gssdp-device-sniffer-window.ui</file>
+ <file>window-menu.ui</file>
</gresource>
</gresources>
diff --git a/tools/main.c b/tools/main.c
new file mode 100644
index 0000000..c8f9fdc
--- /dev/null
+++ b/tools/main.c
@@ -0,0 +1,132 @@
+/* main.c
+ *
+ * Copyright 2019 Jens Georg
+ *
+ * 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 3 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/>.
+ */
+
+#include <glib/gi18n.h>
+#include <libsoup/soup.h>
+
+#include "gssdp-device-sniffer-window.h"
+
+static void
+on_activate (GtkApplication *app)
+{
+ GtkWindow *window;
+ double w, h;
+ gint window_width, window_height;
+
+ g_type_ensure (soup_message_headers_get_type ());
+
+ /* It's good practice to check your parameters at the beginning of the
+ * function. It helps catch errors early and in development instead of
+ * by your users.
+ */
+ g_assert (GTK_IS_APPLICATION (app));
+
+ /* Get the current window or create one if necessary. */
+ window = gtk_application_get_active_window (app);
+
+ if (window == NULL) {
+#if GTK_CHECK_VERSION(3,22,0)
+ {
+ gint px, py;
+ GdkScreen *pointer_screen;
+ GdkDisplay *display;
+ GdkDevice *pointer;
+ GdkMonitor *monitor;
+ GdkRectangle rectangle;
+
+ display = gdk_display_get_default ();
+ pointer = gdk_seat_get_pointer (gdk_display_get_default_seat (display));
+
+ gdk_device_get_position (pointer,
+ &pointer_screen,
+ &px, &py);
+
+ monitor = gdk_display_get_monitor_at_point (display, px, py);
+
+
+ gdk_monitor_get_geometry (monitor, &rectangle);
+ w = rectangle.width * 0.75;
+ h = rectangle.height * 0.75;
+ }
+
+#else
+ w = gdk_screen_width () * 0.75;
+ h = gdk_screen_height () * 0.75;
+#endif
+
+ window_width = CLAMP ((int) w, 10, 1000);
+ window_height = CLAMP ((int) h, 10, 800);
+
+ window = g_object_new (GSSDP_DEVICE_SNIFFER_TYPE_WINDOW,
+ "application", app,
+ "default-width", window_width,
+ "default-height", window_height,
+ NULL);
+ }
+
+ /* Ask the window manager/compositor to present the window. */
+ gtk_window_present (window);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ GtkApplication * app = NULL;
+ int ret;
+
+#if 0
+ /* Set up gettext translations */
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+#endif
+ /*
+ * Create a new GtkApplication. The application manages our main loop,
+ * application windows, integration with the window manager/compositor, and
+ * desktop features such as file opening and single-instance applications.
+ */
+ app = gtk_application_new ("org.gnome.GssdpDeviceSniffer", G_APPLICATION_FLAGS_NONE);
+
+ /*
+ * We connect to the activate signal to create a window when the application
+ * has been lauched. Additionally, this signal notifies us when the user
+ * tries to launch a "second instance" of the application. When they try
+ * to do that, we'll just present any existing window.
+ *
+ * Because we can't pass a pointer to any function type, we have to cast
+ * our "on_activate" function to a GCallback.
+ */
+ g_signal_connect (app, "activate", G_CALLBACK (on_activate), NULL);
+
+ /*
+ * Run the application. This function will block until the applicaiton
+ * exits. Upon return, we have our exit code to return to the shell. (This
+ * is the code you see when you do `echo $?` after running a command in a
+ * terminal.
+ *
+ * Since GtkApplication inherits from GApplication, we use the parent class
+ * method "run". But we need to cast, which is what the "G_APPLICATION()"
+ * macro does.
+ */
+ ret = g_application_run (G_APPLICATION (app), argc, argv);
+
+ g_object_unref (G_OBJECT (app));
+
+ return ret;
+}
diff --git a/tools/meson.build b/tools/meson.build
index bfd44d2..bea75d9 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -1,14 +1,16 @@
-resource = gnome.compile_resources(
- 'org.gupnp.GSSDP.DeviceSniffer',
- 'gssdp-device-sniffer.gresource.xml'
+gssdp_device_sniffer_sources = [
+ 'main.c',
+ 'gssdp-device-sniffer-window.c',
+]
+
+gnome = import('gnome')
+
+gssdp_device_sniffer_sources += gnome.compile_resources('gssdp-device-sniffer-resources',
+ 'gssdp-device-sniffer.gresource.xml',
+ c_name: 'gssdp_device_sniffer'
)
-sniffer = executable(
- 'gssdp-device-sniffer',
- [
- 'gssdp-device-sniffer.c',
- resource
- ],
+executable('gssdp-device-sniffer', gssdp_device_sniffer_sources,
dependencies : [gssdp, gtk],
install: true,
export_dynamic : true,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]