From 7b7906e0f65199516e83736a39ecaf456a25debc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Arreola=20Rodr=C3=ADguez?= Date: Sat, 4 Sep 2021 23:32:04 -0500 Subject: [PATCH] Agrego cliente gtk para pruebas de eventos. --- .gitignore | 5 + Makefile.am | 2 +- client-gtk/Makefile.am | 40 ++ client-gtk/main.c | 284 ++++++++++++++ client-gtk/ni-client.c | 443 +++++++++++++++++++++ client-gtk/ni-client.h | 82 ++++ client-gtk/ni-interface.c | 651 +++++++++++++++++++++++++++++++ client-gtk/ni-interface.h | 76 ++++ client-gtk/ni-ip.c | 236 +++++++++++ client-gtk/ni-ip.h | 88 +++++ client-gtk/ni-marshal.list | 1 + client-gtk/ni-window-interface.c | 416 ++++++++++++++++++++ client-gtk/ni-window-interface.h | 71 ++++ configure.ac | 9 + 14 files changed, 2403 insertions(+), 1 deletion(-) create mode 100644 client-gtk/Makefile.am create mode 100644 client-gtk/main.c create mode 100644 client-gtk/ni-client.c create mode 100644 client-gtk/ni-client.h create mode 100644 client-gtk/ni-interface.c create mode 100644 client-gtk/ni-interface.h create mode 100644 client-gtk/ni-ip.c create mode 100644 client-gtk/ni-ip.h create mode 100644 client-gtk/ni-marshal.list create mode 100644 client-gtk/ni-window-interface.c create mode 100644 client-gtk/ni-window-interface.h diff --git a/.gitignore b/.gitignore index e830092..63b80a3 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,8 @@ po/stamp-po *.gmo *.mo + +client-gtk/inador-gtk-client +client-gtk/ni-marshal.c +client-gtk/ni-marshal.h +client-gtk/core diff --git a/Makefile.am b/Makefile.am index b38c378..9494687 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = src po +SUBDIRS = src client-gtk po ACLOCAL_AMFLAGS = -I m4 diff --git a/client-gtk/Makefile.am b/client-gtk/Makefile.am new file mode 100644 index 0000000..ddeb642 --- /dev/null +++ b/client-gtk/Makefile.am @@ -0,0 +1,40 @@ +# Automake file for NetworkInador GTK Client + +BUILT_SOURCES = \ + ni-marshal.c \ + ni-marshal.h + +bin_PROGRAMS = inador-gtk-client +inador_gtk_client_SOURCES = main.c \ + ni-client.c ni-client.h \ + ni-interface.c ni-interface.h \ + ni-window-interface.c ni-window-interface.h \ + ni-ip.c ni-ip.h \ + $(BUILT_SOURCES) + +#inador_gtk_client_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) +inador_gtk_client_CPPFLAGS = -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) +inador_gtk_client_CFLAGS = $(GTK_CFLAGS) $(AM_CFLAGS) +inador_gtk_client_LDADD = $(GTK_LIBS) +LDADD = $(LIBINTL) + +ni-marshal.h: $(srcdir)/ni-marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=_ni_marshal $(srcdir)/ni-marshal.list \ + --header \ + --internal > ni-marshal.h.tmp \ + && mv ni-marshal.h.tmp ni-marshal.h ) \ + || ( rm -f ni-marshal.h.tmp && exit 1 ) + +ni-marshal.c: $(srcdir)/ni-marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=_ni_marshal $(srcdir)/ni-marshal.list \ + --header \ + --body \ + --internal > ni-marshal.c.tmp \ + && mv ni-marshal.c.tmp ni-marshal.c ) \ + || ( rm -f ni-marshal.c.tmp && exit 1 ) + +EXTRA_DIST = ni-marshal.list + +CLEANFILES = \ + $(BUILT_SOURCES) + diff --git a/client-gtk/main.c b/client-gtk/main.c new file mode 100644 index 0000000..649f603 --- /dev/null +++ b/client-gtk/main.c @@ -0,0 +1,284 @@ +#include + +#include + +#include "ni-client.h" +#include "ni-interface.h" +#include "ni-window-interface.h" +#include "../src/link-types.h" + +enum { + COL_IFACE_OBJECT, + + COL_IFACE_INDEX, + COL_IFACE_NAME, + + COL_IFACE_ICON, + + COL_IFACE_WINDOW, + + NUM_COLS_IFACE, +}; + +enum { + INTERFACES_GROUP_ETHERNET, + INTERFACES_GROUP_WIFI, + INTERFACES_GROUP_BRIDGES, + INTERFACES_GROUP_OTHER, + INTERFACES_GROUP_LOOP_DUMMY, + NUM_INTERFACES_GROUP +}; + +typedef struct { + int group_type; + + GtkWidget *vbox; + GtkWidget *label; + GtkWidget *iconview; + GtkWidget *scrolled; + GtkTreeModel *model_filter; +} UINetworkType; + +const char *group_names[NUM_INTERFACES_GROUP] = { + "Redes cableadas", + "Redes inalámbricas", + "Puentes", + "Otros", + "Loopback y otros tipos" +}; + +GtkListStore *interfaces_store; +NIClient *ni_client; +GtkWidget *ventana; +GtkWidget *vbox; +GtkWidget *empty_label = NULL; +GHashTable *network_blocks_list; + +static void click_interface_cb (GtkIconView *iconview, GtkTreePath *path, gpointer data) { + UINetworkType *network_block = (UINetworkType *) data; + GtkTreeIter iter, real_iter; + GtkWidget *ventana; + NIInterface *ni_interface; + + gtk_tree_model_get_iter (GTK_TREE_MODEL (network_block->model_filter), &iter, path); + + gtk_tree_model_get (GTK_TREE_MODEL (network_block->model_filter), &iter, COL_IFACE_OBJECT, &ni_interface, COL_IFACE_WINDOW, &ventana, -1); + + if (ventana == NULL) { + ventana = ni_window_interface_new (ni_interface); + + gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (network_block->model_filter), &real_iter, &iter); + gtk_list_store_set (interfaces_store, &real_iter, COL_IFACE_WINDOW, ventana, -1); + } + gtk_widget_show (ventana); +} + +int guess_interface_type (NIInterface *ni_interface) { + guint type; + + type = ni_interface_get_iface_type (ni_interface); + if (type == NI_LINK_TYPE_ETHERNET) { + return INTERFACES_GROUP_ETHERNET; + } else if (type == NI_LINK_TYPE_WIFI) { + return INTERFACES_GROUP_WIFI; + } else if (type == NI_LINK_TYPE_DUMMY || type == NI_LINK_TYPE_LOOPBACK) { + return INTERFACES_GROUP_LOOP_DUMMY; + } else if (type == NI_LINK_TYPE_BRIDGE) { + return INTERFACES_GROUP_BRIDGES; + } + + return INTERFACES_GROUP_OTHER; +} + +gboolean network_block_model_filter_by_type (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) { + NIInterface *ni_interface; + const gchar *iface_type; + UINetworkType *network_block = (UINetworkType *) data; + + gtk_tree_model_get (model, iter, COL_IFACE_OBJECT, &ni_interface, -1); + if (ni_interface == NULL) { + return FALSE; + } + + //iface_type = ni_interface_get_iface_type (ni_interface); + if (guess_interface_type (ni_interface) == network_block->group_type) { + return TRUE; + } + + return FALSE; +} + +UINetworkType * create_block_list (int type) { + UINetworkType *network_block; + int g, pos; + + if (g_hash_table_size (network_blocks_list) == 0) { + /* Eliminar la etiqueta */ + gtk_widget_destroy (empty_label); + } + + network_block = g_new0 (UINetworkType, 1); + + network_block->group_type = type; + + network_block->model_filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (interfaces_store), NULL); + printf ("Para el group type: %i, el model_filter: %p\n", type, network_block->model_filter); + gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (network_block->model_filter), network_block_model_filter_by_type, network_block, NULL); + + network_block->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (vbox), network_block->vbox, FALSE, FALSE, 5); + /* Reordenar los grupos presentes, dentro del vbox */ + pos = 0; + for (g = 0; g < NUM_INTERFACES_GROUP && g < type; g++) { + if (g_hash_table_lookup (network_blocks_list, GINT_TO_POINTER (g)) != NULL) { + pos++; + } + } + gtk_box_reorder_child (GTK_BOX (vbox), network_block->vbox, pos); + + network_block->label = gtk_label_new (group_names [type]); + gtk_box_pack_start (GTK_BOX (network_block->vbox), network_block->label, FALSE, FALSE, 0); + + network_block->iconview = gtk_icon_view_new_with_model (network_block->model_filter); + g_signal_connect (network_block->iconview, "item-activated", G_CALLBACK (click_interface_cb), network_block); + + gtk_icon_view_set_text_column (GTK_ICON_VIEW (network_block->iconview), COL_IFACE_NAME); + gtk_icon_view_set_pixbuf_column (GTK_ICON_VIEW (network_block->iconview), COL_IFACE_ICON); + //gtk_icon_view_set_columns (GTK_ICON_VIEW (network_block->iconview), 1000); + gtk_icon_view_set_reorderable (GTK_ICON_VIEW (network_block->iconview), FALSE); + + network_block->scrolled = gtk_scrolled_window_new ( + gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (network_block->iconview)), + gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (network_block->iconview))); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (network_block->scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + gtk_container_add (GTK_CONTAINER (network_block->scrolled), network_block->iconview); + gtk_box_pack_start (GTK_BOX (network_block->vbox), network_block->scrolled, FALSE, FALSE, 0); + + gtk_widget_show_all (network_block->vbox); + + return network_block; +} + +gboolean locate_interface_from_store (GtkListStore *store, GtkTreeIter *iter, guint index) { + gboolean has; + guint index_data; + + has = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), iter); + while (has) { + gtk_tree_model_get (GTK_TREE_MODEL (interfaces_store), iter, COL_IFACE_INDEX, &index_data, -1); + + if (index == index_data) { + return TRUE; + } + has = gtk_tree_model_iter_next (GTK_TREE_MODEL (interfaces_store), iter); + } + return FALSE; +} + +static void interface_changed_name_cb (GObject *object, GParamSpec *sp, gpointer data) { + NIInterface *ni_interface = NI_INTERFACE (object); + guint index; + GtkTreeIter iter; + + index = ni_interface_get_index (ni_interface); + + if (locate_interface_from_store (interfaces_store, &iter, index)) { + gtk_list_store_set (interfaces_store, &iter, COL_IFACE_NAME, ni_interface_get_name (ni_interface), -1); + } +} + +void new_interface_cb (NIClient *ni_client, NIInterface *ni_interface, gpointer data) { + guint index; + UINetworkType *network_block; + int type; + GdkPixbuf *icon; + GtkTreeIter iter; + + type = guess_interface_type (ni_interface); + network_block = g_hash_table_lookup (network_blocks_list, GINT_TO_POINTER (type)); + + if (network_block == NULL) { + /* El bloque está vacio, pedir crearlo */ + network_block = create_block_list (type); + + g_hash_table_insert (network_blocks_list, GINT_TO_POINTER (type), network_block); + } + + if (type == INTERFACES_GROUP_ETHERNET) { + icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "network-wired", 32, 0, NULL); + } else { + icon = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), "network-wired", 32, 0, NULL); + } + + gtk_list_store_insert (interfaces_store, &iter, -1); + gtk_list_store_set (interfaces_store, &iter, COL_IFACE_OBJECT, ni_interface, COL_IFACE_INDEX, ni_interface_get_index (ni_interface), COL_IFACE_NAME, ni_interface_get_name (ni_interface), COL_IFACE_ICON, icon, COL_IFACE_WINDOW, NULL, -1); + + g_signal_connect (ni_interface, "notify::name", G_CALLBACK (interface_changed_name_cb), NULL); + + g_object_unref (icon); +} + +void delete_interface_cb (NIClient *ni_client, NIInterface *ni_interface, gpointer data) { + GtkWidget *ventana; + GtkTreeIter iter; + + if (locate_interface_from_store (interfaces_store, &iter, ni_interface_get_index (ni_interface))) { + gtk_tree_model_get (GTK_TREE_MODEL (interfaces_store), &iter, COL_IFACE_WINDOW, &ventana, -1); + /* Eliminar este objeto */ + if (ventana != NULL) { + gtk_widget_destroy (ventana); + } + gtk_list_store_remove (interfaces_store, &iter); + } +} + +void cerrar_ventana_cb (GtkWidget *ventana, gpointer data) { + g_object_unref (ni_client); + gtk_main_quit (); +} + +int main (int argc, char *argv[]) { + gboolean connected; + GtkWidget *label, *scrolled; + + gtk_init (&argc, &argv); + + ni_client = ni_client_new (); + + connected = ni_client_connect (ni_client); + g_signal_connect (ni_client, "new-interface", G_CALLBACK (new_interface_cb), NULL); + g_signal_connect (ni_client, "delete-interface", G_CALLBACK (delete_interface_cb), NULL); + + interfaces_store = gtk_list_store_new (NUM_COLS_IFACE, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_POINTER); + + network_blocks_list = g_hash_table_new (g_direct_hash, g_direct_equal); + + ventana = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (ventana), "Interfaces"); + gtk_window_set_default_size (GTK_WINDOW (ventana), 640, 480); + g_signal_connect (ventana, "destroy", G_CALLBACK (gtk_main_quit), NULL); + + scrolled = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); + + gtk_container_add (GTK_CONTAINER (ventana), scrolled); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_widget_set_size_request (vbox, 260, -1); + + gtk_container_add (GTK_CONTAINER (scrolled), vbox); + + if (connected == FALSE) { + empty_label = gtk_label_new ("El servicio del network inador no está corriendo\n"); + } else { + empty_label = gtk_label_new ("Recuperando información...\n"); + } + gtk_box_pack_start (GTK_BOX (vbox), empty_label, TRUE, TRUE, 0); + + gtk_widget_show_all (ventana); + + gtk_main (); + + return 0; +} diff --git a/client-gtk/ni-client.c b/client-gtk/ni-client.c new file mode 100644 index 0000000..67a2e5e --- /dev/null +++ b/client-gtk/ni-client.c @@ -0,0 +1,443 @@ +/* + * ni-client.c + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ni-client.h" +#include "ni-interface.h" +#include "ni-marshal.h" +#include "../src/network-inador-manager.h" + +#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket" + +/* Privados desde el ni-interface */ +void ni_interface_consume_values (NIInterface *ni_interface, char *name, gint arp_type, guint master_index, guint mtu, guint flags); + +/* Privados locales */ +static void ni_client_dispose (GObject *obj); +static void ni_client_finalize (GObject *obj); + +struct _NIClientPrivate { + int client_socket; + + gchar *socket_path; + GHashTable *interfaces; + guint source; + guint events; +}; + +enum { + PROP_SOCKET_PATH = 1, + + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +enum { + DATA_READ, + + NEW_INTERFACE, + + DELETE_INTERFACE, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE_WITH_PRIVATE (NIClient, ni_client, G_TYPE_OBJECT) + +static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size); + +static void ni_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NIClient *ni_client = NI_CLIENT (object); + g_return_if_fail (NI_IS_CLIENT (object)); + + switch (prop_id) { + case PROP_SOCKET_PATH: + if (ni_client->priv->socket_path != NULL) { + g_free (ni_client->priv->socket_path); + } + ni_client->priv->socket_path = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NIClient *ni_client = NI_CLIENT (object); + g_return_if_fail (NI_IS_CLIENT (object)); + + switch (prop_id) { + case PROP_SOCKET_PATH: + g_value_set_string (value, ni_client->priv->socket_path); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_client_class_init (NIClientClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = ni_client_set_property; + object_class->get_property = ni_client_get_property; + object_class->dispose = ni_client_dispose; + object_class->finalize = ni_client_finalize; + + obj_properties[PROP_SOCKET_PATH] = g_param_spec_string ( + "socket-path", + "Socket Path", + "The path of the unix socket.", + COMMAND_SOCKET_PATH, + G_PARAM_CONSTRUCT | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); + + signals[DATA_READ] = g_signal_new ("packet-read", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NIClientClass, data_response), + g_signal_accumulator_true_handled, + NULL, + _ni_marshal_BOOLEAN__POINTER_UINT, + G_TYPE_BOOLEAN, + 2, + G_TYPE_POINTER | G_SIGNAL_TYPE_STATIC_SCOPE, + G_TYPE_UINT); + + signals[NEW_INTERFACE] = g_signal_new ("new-interface", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NIClientClass, new_interface), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + NI_TYPE_INTERFACE); + + signals[DELETE_INTERFACE] = g_signal_new ("delete-interface", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NIClientClass, delete_interface), + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + NI_TYPE_INTERFACE); + + klass->data_response = ni_client_data_read; + klass->new_interface = NULL; + klass->delete_interface = NULL; +} + +static void ni_client_process_interface_response (NIClient *ni_client, gpointer data, guint size) { + printf ("Interface response\n"); + NIInterface *ni_interface; + unsigned char *buffer = (unsigned char *) data; + + uint32_t index, master_index, mtu, type; + uint16_t flags; + uint8_t bits; + guint name_size; + char iface_name[128]; + + memcpy (&index, &buffer[2], 4); + memcpy (&type, &buffer[6], 4); + memcpy (&master_index, &buffer[10], 4); + memcpy (&mtu, &buffer[14], 4); + memcpy (&flags, &buffer[18], 2); + bits = buffer[20]; + + name_size = buffer[21]; + memcpy (iface_name, &buffer[22], name_size); + iface_name[name_size] = 0; + + /* Insertar y crear */ + ni_interface = g_object_new (NI_TYPE_INTERFACE, "ni-client", ni_client, "index", index, "wireless", (bits == 0 ? FALSE : TRUE), "type", type, "name", iface_name, "mtu", mtu, "flags", flags, "master-index", master_index, NULL); + + g_hash_table_insert (ni_client->priv->interfaces, GINT_TO_POINTER(index), ni_interface); + + g_signal_emit (ni_client, signals[NEW_INTERFACE], 0, ni_interface); +} + +static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size) { + unsigned char *buffer = (unsigned char *) data; + uint32_t index; + NIInterface *ni_interface; + + if (buffer[0] == NET_INADOR_TYPE_EVENT) { + switch (buffer[1]) { + case NET_INADOR_EVENT_IFACE_ADDED: + memcpy (&index, &buffer[2], 4); + + /* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */ + ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index)); + + if (ni_interface == NULL) { + ni_client_process_interface_response (ni_client, data, size); + return TRUE; + } else { + return FALSE; + } + break; + case NET_INADOR_EVENT_IFACE_REMOVED: + memcpy (&index, &buffer[2], 4); + + /* La interfaz fué eliminada, nosotros procesamos este evento */ + ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index)); + + if (ni_interface == NULL) { + /* ¿Evento de una interfaz eliminada? Ignorar */ + } else { + g_hash_table_remove (ni_client->priv->interfaces, GINT_TO_POINTER(index)); + + g_signal_emit (ni_client, signals[DELETE_INTERFACE], 0, ni_interface); + + g_object_unref (ni_interface); + } + return TRUE; + break; + } + } else if (buffer[0] == NET_INADOR_TYPE_RESPONSE) { + switch (buffer[1]) { + case NET_INADOR_RESPONSE_IFACE: + memcpy (&index, &buffer[2], 4); + + /* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */ + ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index)); + + if (ni_interface == NULL) { + ni_client_process_interface_response (ni_client, data, size); + return TRUE; + } else { + return FALSE; + } + break; + } + } + + /* Procesar los datos aquí */ + return TRUE; +} + +static gboolean ni_client_read_from_socket (GIOChannel *source, GIOCondition condition, gpointer data) { + NIClient *ni_client = NI_CLIENT (data); + unsigned char buffer[8192]; + int res; + gboolean stop; + int g; + + res = recv (ni_client->priv->client_socket, buffer, sizeof (buffer), 0); + + if (res <= 0) { + /* El socket se cerró */ + close (ni_client->priv->client_socket); + ni_client->priv->client_socket = -1; + + return FALSE; + } + + printf ("Data arrival: %i\n", res); + for (g = 0; g < res; g++) { + printf ("%02hhx ", buffer[g]); + } + printf ("\n"); + /* Tenemos datos, hacer una validación básica */ + if (buffer[0] != NET_INADOR_TYPE_RESPONSE && + buffer[0] != NET_INADOR_TYPE_RESPONSE_ERROR && + buffer[0] != NET_INADOR_TYPE_EVENT && + buffer[0] != NET_INADOR_TYPE_RESPONSE_LISTING_END) { + /* Tipo de paquete inválido */ + return TRUE; + } + + g_signal_emit (ni_client, signals[DATA_READ], 0, (void *) buffer, res, &stop); + + return TRUE; +} + +static gboolean ni_client_foreach_remove_every_interface (gpointer key, gpointer value, gpointer user_data) { + NIInterface *ni_interface = NI_INTERFACE (value); + + g_object_unref (ni_interface); + + return TRUE; +} + +static void ni_client_dispose (GObject *obj) { + NIClient *ni_client; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_client = NI_CLIENT (obj); + + /* Recorrer todos los objetos interface para quitarles una referencia y liberarlos */ + g_hash_table_foreach_remove (ni_client->priv->interfaces, ni_client_foreach_remove_every_interface, NULL); + + if (ni_client->priv->source > 0) { + g_source_remove (ni_client->priv->source); + ni_client->priv->source = 0; + } + + parent_class->dispose (obj); +} + +static void ni_client_finalize (GObject *obj) { + NIClient *ni_client; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_client = NI_CLIENT (obj); + + g_hash_table_destroy (ni_client->priv->interfaces); + + if (ni_client->priv->client_socket >= 0) { + close (ni_client->priv->client_socket); + ni_client->priv->client_socket = 0; + } + + if (ni_client->priv->socket_path != NULL) { + g_free (ni_client->priv->socket_path); + ni_client->priv->socket_path = NULL; + } + + parent_class->finalize (obj); +} + +static void ni_client_init (NIClient *ni_client) { + NIClientPrivate *priv = ni_client_get_instance_private (ni_client); + ni_client->priv = priv; + + priv->client_socket = -1; + priv->socket_path = NULL; + priv->source = 0; + priv->events = NET_INADOR_EVENT_MASK_INTERFACES | NET_INADOR_EVENT_MASK_IP; + + priv->interfaces = g_hash_table_new (g_direct_hash, g_direct_equal); +} + +void ni_client_update_event_mask (NIClient *ni_client) { + unsigned char buffer[8]; + + if (ni_client->priv->client_socket < 0) { + return; + } + + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_SET_EVENT_MASK; + memcpy (&buffer[2], &ni_client->priv->events, 4); + + send (ni_client->priv->client_socket, buffer, 6, 0); +} + +void ni_client_ask_interfaces (NIClient *ni_client) { + unsigned char buffer[8]; + + if (ni_client->priv->client_socket < 0) { + return; + } + + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_LIST_IFACES; + + send (ni_client->priv->client_socket, buffer, 2, 0); +} + +void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, int family) { + unsigned char buffer[8]; + uint32_t index; + + if (ni_client->priv->client_socket < 0) { + return; + } + + index = ni_interface_get_index (ni_interface); + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_LIST_IP; + memcpy (&buffer[2], &index, 4); + buffer[6] = family; + + send (ni_client->priv->client_socket, buffer, 7, 0); +} + +gboolean ni_client_connect (NIClient *ni_client) { + int s, ret; + struct sockaddr_un path_dest; + GIOChannel *channel; + + if (ni_client->priv->client_socket >= 0) { + return FALSE; + } + + s = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); + + if (s < 0) { + return FALSE; + } + + path_dest.sun_family = AF_UNIX; + strncpy (path_dest.sun_path, ni_client->priv->socket_path, sizeof (path_dest.sun_path)); + ret = connect (s, (struct sockaddr *) &path_dest, sizeof (path_dest)); + + if (ret < 0) { + perror ("Connect"); + close (s); + return FALSE; + } + + /* Tengo socket, instalar vigilante */ + ni_client->priv->client_socket = s; + channel = g_io_channel_unix_new (s); + ni_client->priv->source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, ni_client_read_from_socket, ni_client); + g_io_channel_unref (channel); + + /* Pedir eventos */ + ni_client_update_event_mask (ni_client); + + /* Pedir un listado de interfaces */ + ni_client_ask_interfaces (ni_client); +} + +void ni_client_disconnect (NIClient *ni_client) { + /* TODO: Escribir esto */ +} + +NIClient *ni_client_new (void) { + return g_object_new (NI_TYPE_CLIENT, NULL); +} + +NIClient *ni_client_new_with_path (const char *path) { + return g_object_new (NI_TYPE_CLIENT, "socket-path", path, NULL); +} + diff --git a/client-gtk/ni-client.h b/client-gtk/ni-client.h new file mode 100644 index 0000000..3f6b1bc --- /dev/null +++ b/client-gtk/ni-client.h @@ -0,0 +1,82 @@ +/* + * ni-client.h + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* inclusion guard */ +#ifndef __NI_CLIENT_H__ +#define __NI_CLIENT_H__ + + +#include + +#include +#include + +G_BEGIN_DECLS + +typedef struct _NIClientClass NIClientClass; +typedef struct _NIClient NIClient; +typedef struct _NIClientPrivate NIClientPrivate; + +/* + * Type declaration. + */ +/* + * Type declaration. + */ +#define NI_TYPE_CLIENT (ni_client_get_type ()) +#define NI_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NI_TYPE_CLIENT, NIClient)) +#define NI_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NI_TYPE_CLIENT, NIClientClass)) +#define NI_IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NI_TYPE_CLIENT)) +#define NI_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NI_TYPE_CLIENT)) +#define NI_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NI_TYPE_CLIENT, NIClientClass)) + +GType ni_client_get_type (void); + +struct _NIClientClass { + GObjectClass parent_class; + + gboolean (* data_response) (NIClient *ni_client, gpointer data, guint size); + /*gboolean (* data_response_error) (NiClient *ni_client, gpointer data, guint size);*/ + void (*new_interface) (NIClient *ni_client, gpointer ni_interface); + void (*delete_interface) (NIClient *ni_client, gpointer ni_interface); +}; + +struct _NIClient { + GObject parent_instance; + + NIClientPrivate *priv; +}; + +typedef struct _NIInterface NIInterface; + +/* + * Method definitions. + */ +NIClient *ni_client_new (void); +NIClient *ni_client_new_with_path (const char *path); +gboolean ni_client_connect (NIClient *ni_client); +void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, int family); +void ni_client_ask_ips (NIClient *ni_client, NIInterface *ni_interface); + +G_END_DECLS + +#endif /* __NI_CLIENT_H__ */ diff --git a/client-gtk/ni-interface.c b/client-gtk/ni-interface.c new file mode 100644 index 0000000..f5338cc --- /dev/null +++ b/client-gtk/ni-interface.c @@ -0,0 +1,651 @@ +/* + * ni-interface.c + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "ni-client.h" +#include "ni-interface.h" +#include "ni-ip.h" + +#include "../src/network-inador-manager.h" + +struct _NIInterfacePrivate { + NIClient *ni_client; + + guint index; + gchar *name; + guint type; + + guint master_index; + guint mtu; + guint flags; + + gboolean is_wireless; + GList *ip_list; +}; + +enum { + PROP_NI_CLIENT = 1, + + PROP_INDEX, + PROP_NAME, + PROP_TYPE, + + PROP_MASTER_INDEX, + + PROP_MTU, + + PROP_FLAGS, + + PROP_WIRELESS, + + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +enum { + NEW_IP, + + DELETE_IP, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +struct _SearchIP { + guint family; + guint prefix; + + struct_addr local_addr; + struct_addr addr; + + gboolean has_local_addr; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (NIInterface, ni_interface, G_TYPE_OBJECT) + +static gboolean ni_interface_process_interface_response (NIClient *ni_client, unsigned char *buffer, guint size, gpointer data); + +#if 0 +static GObject *ni_interface_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { + GObject *obj; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + NIInterface *ni_interface; + + obj = parent_class->constructor (type, n_construct_properties, construct_properties); + + ni_interface = NI_INTERFACE (obj); + { + int g; + for (g = 0; g < n_construct_properties; g++) { + GParamSpec *pspec = construct_properties[g].pspec; + GValue *value = construct_properties[g].value; + + /* Manejar el valor */ + if (strcmp (g_param_spec_get_name (pspec), "index") == 0) { + printf ("Estableciendo sobre el constructor, el index\n"); + ni_interface->priv->index = g_value_get_uint (value); + + ni_interface_check_and_connect_signal (ni_interface); + } else if (strcmp (g_param_spec_get_name (pspec), "ni-client") == 0) { + ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); + + } + } + } + + return obj; +} +#endif + +static void ni_interface_constructed (GObject *obj) { + NIInterface *ni_interface; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + parent_class->constructed (obj); + + ni_interface = NI_INTERFACE (obj); + + if (ni_interface->priv->ni_client != NULL && ni_interface->priv->index != 0) { + /* Conectar la señal de datos */ + g_signal_connect (ni_interface->priv->ni_client, "packet-read", G_CALLBACK (ni_interface_process_interface_response), ni_interface); + + /* Solicitar listado de IP's */ + ni_client_ask_ip_interface (ni_interface->priv->ni_client, ni_interface, AF_UNSPEC); + } +} + +static void ni_interface_dispose (GObject *obj) { + NIInterface *ni_interface; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_interface = NI_INTERFACE (obj); + + g_signal_handlers_disconnect_by_func (ni_interface->priv->ni_client, G_CALLBACK (ni_interface_process_interface_response), ni_interface); + + /* Quitar la referencia hacia el ni_client */ + g_object_unref (ni_interface->priv->ni_client); + + parent_class->dispose (obj); +} + +static void ni_interface_finalize (GObject *obj) { + NIInterface *ni_interface; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_interface = NI_INTERFACE (obj); + + /* Nada que hacer, por el momento */ + + parent_class->finalize (obj); +} + +static void ni_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NIInterface *ni_interface = NI_INTERFACE (object); + g_return_if_fail (NI_IS_INTERFACE (object)); + + switch (prop_id) { + case PROP_NI_CLIENT: + ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); + g_object_ref (ni_interface->priv->ni_client); + break; + case PROP_INDEX: + ni_interface->priv->index = g_value_get_uint (value); + break; + case PROP_NAME: + if (ni_interface->priv->name != NULL) { + g_free (ni_interface->priv->name); + } + ni_interface->priv->name = g_value_dup_string (value); + break; + case PROP_TYPE: + ni_interface->priv->type = g_value_get_uint (value); + break; + case PROP_WIRELESS: + ni_interface->priv->is_wireless = g_value_get_boolean (value); + break; + case PROP_MTU: + ni_interface->priv->mtu = g_value_get_uint (value); + break; + case PROP_MASTER_INDEX: + ni_interface->priv->master_index = g_value_get_uint (value); + break; + case PROP_FLAGS: + ni_interface->priv->flags = g_value_get_uint (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_interface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NIInterface *ni_interface = NI_INTERFACE (object); + g_return_if_fail (NI_IS_INTERFACE (object)); + + switch (prop_id) { + case PROP_NI_CLIENT: + g_value_set_object (value, ni_interface->priv->ni_client); + break; + case PROP_INDEX: + g_value_set_uint (value, ni_interface->priv->index); + break; + case PROP_NAME: + g_value_set_string (value, ni_interface->priv->name); + break; + case PROP_TYPE: + g_value_set_uint (value, ni_interface->priv->type); + break; + case PROP_WIRELESS: + g_value_set_boolean (value, ni_interface->priv->is_wireless); + break; + case PROP_MTU: + g_value_set_uint (value, ni_interface->priv->mtu); + break; + case PROP_MASTER_INDEX: + g_value_set_uint (value, ni_interface->priv->master_index); + break; + case PROP_FLAGS: + g_value_set_uint (value, ni_interface->priv->flags); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_interface_class_init (NIInterfaceClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = ni_interface_set_property; + object_class->get_property = ni_interface_get_property; + object_class->constructed = ni_interface_constructed; + object_class->dispose = ni_interface_dispose; + object_class->finalize = ni_interface_finalize; + + obj_properties[PROP_NI_CLIENT] = g_param_spec_object ( + "ni-client", + "Network Inador Client", + "The client object", + NI_TYPE_CLIENT, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_INDEX] = g_param_spec_uint ( + "index", + "Index", + "The index of the interface.", + 1, G_MAXUINT, 1, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_NAME] = g_param_spec_string ( + "name", + "Name", + "Name of the interface", + NULL, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_TYPE] = g_param_spec_uint ( + "type", + "Interface Type", + "Type of the interface.", + 0, G_MAXUINT, 1, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_MASTER_INDEX] = g_param_spec_uint ( + "master-index", + "Master index", + "The index of the master interface", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_MTU] = g_param_spec_uint ( + "mtu", + "MTU", + "The mtu of the interface.", + 0, G_MAXUINT, 1500, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_FLAGS] = g_param_spec_uint ( + "flags", + "Flags", + "The flags of the interface.", + 0, G_MAXUINT, 0, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_WIRELESS] = g_param_spec_boolean ( + "wireless", + "Wireless", + "Indicates if this interface is wireless", + FALSE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); + + signals[NEW_IP] = g_signal_new ("new-ip", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + NI_TYPE_IP); + + signals[DELETE_IP] = g_signal_new ("delete-ip", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + 0, + NULL, + NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, + NI_TYPE_IP); +} + +static gint ni_interface_locate_ip (gconstpointer *a, gconstpointer *b) { + NIIP *ni_ip = (NIIP *) a; + struct _SearchIP *search_ip = (struct _SearchIP *) b; + int family_size = 0; + + if (ni_ip_get_family (ni_ip) != search_ip->family) return -1; + + if (search_ip->family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (search_ip->family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + if (ni_ip_get_prefix (ni_ip) != search_ip->prefix) return -1; + + if (memcmp (ni_ip_get_addr (ni_ip), &search_ip->addr, family_size) != 0) { + return -1; + } + + if (ni_ip_has_local (ni_ip) != search_ip->has_local_addr) { + return -1; + } + + if (search_ip->has_local_addr) { + if (memcmp (ni_ip_get_local_addr (ni_ip), &search_ip->local_addr, family_size) != 0) { + return -1; + } + } + + return 0; +} + +static void ni_interface_process_interface_update (NIInterface *ni_interface, gpointer data, guint size) { + unsigned char *buffer = (unsigned char *) data; + + uint32_t master_index, mtu; + uint16_t flags; + guint name_size; + char iface_name[128]; + + memcpy (&master_index, &buffer[10], 4); + memcpy (&mtu, &buffer[14], 4); + memcpy (&flags, &buffer[18], 2); + + name_size = buffer[21]; + memcpy (iface_name, &buffer[22], name_size); + iface_name[name_size] = 0; + + g_object_freeze_notify (G_OBJECT (ni_interface)); + if (ni_interface->priv->name == NULL) { + ni_interface->priv->name = g_strdup (iface_name); + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); + } else if (strcmp (ni_interface->priv->name, iface_name) != 0) { + g_free (ni_interface->priv->name); + + ni_interface->priv->name = g_strdup (iface_name); + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); + } + + if (ni_interface->priv->master_index != master_index) { + ni_interface->priv->master_index = master_index; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); + } + + if (ni_interface->priv->mtu != mtu) { + ni_interface->priv->master_index = master_index; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); + } + + if (ni_interface->priv->flags != flags) { + ni_interface->priv->flags = flags; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_FLAGS]); + } + + g_object_thaw_notify (G_OBJECT (ni_interface)); +} + +static void ni_interface_process_ip_added (NIInterface *ni_interface, gpointer data, guint size) { + unsigned char *buffer = (unsigned char *) data; + uint32_t index, flags; + guint family, prefix, bits, scope, pos; + gint family_size = 0; + gboolean has_local_addr = FALSE, has_brd_addr = FALSE; + NIIP *ni_ip; + struct_addr addr, local_addr, brd_addr; + GList *g; + + family = buffer[6]; + prefix = buffer[7]; + bits = buffer[8]; + scope = buffer[9]; + + if (bits & 0x01) has_local_addr = TRUE; + if (bits & 0x02) has_brd_addr = TRUE; + memcpy (&flags, &buffer[10], 4); + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + memcpy (&addr, &buffer[14], family_size); + + pos = 14 + family_size; + if (has_local_addr) { + memcpy (&local_addr, &buffer[pos], family_size); + pos += family_size; + } + + if (has_brd_addr) { + memcpy (&brd_addr, &buffer[pos], family_size); + } + + ni_ip = ni_ip_new (ni_interface, family, prefix, &addr, flags, scope, has_local_addr, (has_local_addr ? &local_addr : NULL), has_brd_addr, (has_brd_addr ? &brd_addr : NULL)); + + ni_interface->priv->ip_list = g_list_append (ni_interface->priv->ip_list, ni_ip); + + printf ("Emitiendo signal de IP-addr\n"); + g_signal_emit (ni_interface, signals[NEW_IP], 0, ni_ip); +} + +static void ni_interface_process_ip_removed (NIInterface *ni_interface, gpointer data, guint size) { + unsigned char *buffer = (unsigned char *) data; + struct _SearchIP search_ip; + gint family_size = 0; + guint bits, pos; + GList *g; + NIIP *ni_ip; + + search_ip.family = buffer[6]; + search_ip.prefix = buffer[7]; + bits = buffer[8]; + + if (bits & 0x01) search_ip.has_local_addr = TRUE; + + if (search_ip.family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (search_ip.family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + memcpy (&search_ip.addr, &buffer[10], family_size); + + pos = 10 + family_size; + if (search_ip.has_local_addr) { + memcpy (&search_ip.local_addr, &buffer[pos], family_size); + pos += family_size; + } + + /* Localizar la IP y eliminarla */ + g = g_list_find_custom (ni_interface->priv->ip_list, &search_ip, (GCompareFunc) ni_interface_locate_ip); + + if (g == NULL) { + /* ¿IP eliminada sin que exista? Super error */ + } else { + ni_ip = (NIIP *) g->data; + ni_interface->priv->ip_list = g_list_remove (ni_interface->priv->ip_list, g->data); + + /* Ahora, ya desligado, emitir la señal */ + g_signal_emit (ni_interface, signals[DELETE_IP], 0, ni_ip); + + g_object_unref (ni_ip); + } +} + +static gboolean ni_interface_process_interface_response (NIClient *ni_client, unsigned char *buffer, guint size, gpointer user_data) { + NIInterface *ni_interface = (NIInterface *) user_data; + uint32_t index; + + if (buffer[0] == NET_INADOR_TYPE_EVENT) { + switch (buffer[1]) { + case NET_INADOR_EVENT_IPADDR_ADDED: + memcpy (&index, &buffer[2], 4); + + if (index != ni_interface->priv->index) { + /* Mensaje de IP, pero no para mí, dejar pasar */ + return FALSE; + } + + ni_interface_process_ip_added (ni_interface, buffer, size); + + return TRUE; + break; + case NET_INADOR_EVENT_IFACE_ADDED: + /* Mensaje de actualización de mi estado */ + memcpy (&index, &buffer[2], 4); + + if (index != ni_interface->priv->index) { + /* Mensaje de la interfaz, pero no para mí, dejar pasar */ + return FALSE; + } + + ni_interface_process_interface_update (ni_interface, buffer, size); + return TRUE; + break; + case NET_INADOR_EVENT_IPADDR_REMOVED: + memcpy (&index, &buffer[2], 4); + + if (index != ni_interface->priv->index) { + /* Mensaje de la interfaz, pero no para mí, dejar pasar */ + return FALSE; + } + ni_interface_process_ip_removed (ni_interface, buffer, size); + return TRUE; + break; + } + } else if (buffer[0] == NET_INADOR_TYPE_RESPONSE) { + switch (buffer[1]) { + case NET_INADOR_RESPONSE_IPADDR: + memcpy (&index, &buffer[2], 4); + + if (index != ni_interface->priv->index) { + /* Mensaje de IP, pero no para mí, dejar pasar */ + return FALSE; + } + printf ("Response IP addr sobre interfaz\n"); + ni_interface_process_ip_added (ni_interface, buffer, size); + + return TRUE; + break; + case NET_INADOR_RESPONSE_IFACE: + memcpy (&index, &buffer[2], 4); + + if (index != ni_interface->priv->index) { + /* Mensaje de la interfaz, pero no para mí, dejar pasar */ + return FALSE; + } + + ni_interface_process_interface_update (ni_interface, buffer, size); + return TRUE; + break; + } + } + + return FALSE; /* Que se siga procesando */ +} + +guint ni_interface_get_index (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), 0); + return ni_interface->priv->index; +} + +const gchar *ni_interface_get_name (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); + return ni_interface->priv->name; +} + +guint ni_interface_get_iface_type (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), 0); + return ni_interface->priv->type; +} + +gboolean ni_interface_is_wireless (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), FALSE); + return ni_interface->priv->is_wireless; +} + +NIClient *ni_interface_get_client (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); + return ni_interface->priv->ni_client; +} + +const GList *ni_interface_get_ip_list (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); + return ni_interface->priv->ip_list; +} + +#if 0 +void ni_interface_consume_values (NIInterface *ni_interface, char *name, gint arp_type, guint master_index, guint mtu, guint flags) { + g_object_freeze_notify (G_OBJECT (ni_interface)); + + if (ni_interface->priv->name == NULL) { + ni_interface->priv->name = g_strdup (name); + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); + } else if (strcmp (ni_interface->priv->name, name) != 0) { + g_free (ni_interface->priv->name); + + ni_interface->priv->name = g_strdup (name); + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_NAME]); + } + + + if (ni_interface->priv->arp_type != arp_type) { + ni_interface->priv->arp_type = arp_type; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_ARP_TYPE]); + } + + if (ni_interface->priv->master_index != master_index) { + ni_interface->priv->master_index = master_index; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); + } + + if (ni_interface->priv->mtu != mtu) { + ni_interface->priv->master_index = master_index; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_MASTER_INDEX]); + } + + if (ni_interface->priv->flags != flags) { + ni_interface->priv->flags = flags; + g_object_notify_by_pspec (G_OBJECT (ni_interface), obj_properties[PROP_FLAGS]); + } + + g_object_thaw_notify (G_OBJECT (ni_interface)); +} +#endif + +static void ni_interface_init (NIInterface *ni_interface) { + NIInterfacePrivate *priv = ni_interface_get_instance_private (ni_interface); + ni_interface->priv = priv; + + /* initialize all public and private members to reasonable default values. + * They are all automatically initialized to 0 to begin with. */ + priv->ni_client = NULL; + priv->index = 0; + priv->name = NULL; + priv->type = 0; + priv->is_wireless = FALSE; + priv->master_index = 0; + priv->mtu = 0; + priv->flags = 0; + priv->ip_list = NULL; +} + diff --git a/client-gtk/ni-interface.h b/client-gtk/ni-interface.h new file mode 100644 index 0000000..cfe46c5 --- /dev/null +++ b/client-gtk/ni-interface.h @@ -0,0 +1,76 @@ +/* + * ni-interface.h + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* inclusion guard */ +#ifndef __NI_INTERFACE_H__ +#define __NI_INTERFACE_H__ + + +#include + +#include +#include + +G_BEGIN_DECLS + +typedef struct _NIInterfaceClass NIInterfaceClass; +typedef struct _NIInterface NIInterface; +typedef struct _NIInterfacePrivate NIInterfacePrivate; + +typedef struct _NIClient NIClient; + +/* + * Type declaration. + */ +#define NI_TYPE_INTERFACE (ni_interface_get_type ()) +#define NI_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NI_TYPE_INTERFACE, NIInterface)) +#define NI_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NI_TYPE_INTERFACE, NIInterfaceClass)) +#define NI_IS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NI_TYPE_INTERFACE)) +#define NI_IS_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NI_TYPE_INTERFACE)) +#define NI_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NI_TYPE_INTERFACE, NIInterfaceClass)) + +GType ni_interface_get_type (void); + +struct _NIInterfaceClass { + GObjectClass parent_class; +}; + +struct _NIInterface { + GObject parent_instance; + + NIInterfacePrivate *priv; +}; + +/* + * Method definitions. + */ + +guint ni_interface_get_index (NIInterface *ni_interface); +const gchar *ni_interface_get_name (NIInterface *ni_interface); +guint ni_interface_get_iface_type (NIInterface *ni_interface); +gboolean ni_interface_is_wireless (NIInterface *ni_interface); +NIClient *ni_interface_get_client (NIInterface *ni_interface); +const GList *ni_interface_get_ip_list (NIInterface *ni_interface); + +G_END_DECLS + +#endif /* __NI_INTERFACE_H__ */ diff --git a/client-gtk/ni-ip.c b/client-gtk/ni-ip.c new file mode 100644 index 0000000..2b91e9f --- /dev/null +++ b/client-gtk/ni-ip.c @@ -0,0 +1,236 @@ +/* + * ni-ip.c + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include "ni-interface.h" +#include "ni-ip.h" + +#include "../src/network-inador-manager.h" + +struct _NIIPPrivate { + NIInterface *ni_interface; + + guint family; + gint family_size; + guint prefix; + + struct_addr local_addr; + struct_addr addr; + struct_addr brd_addr; + + gboolean has_brd; + gboolean has_local; + + uint32_t flags; + unsigned char scope; +}; + +enum { + PROP_NI_INTERFACE = 1, + + N_PROPERTIES +}; + +G_DEFINE_TYPE_WITH_PRIVATE (NIIP, ni_ip, G_TYPE_OBJECT) + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void ni_ip_dispose (GObject *obj) { + NIIP *ni_ip; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_ip = NI_IP (obj); + + /* Quitar la referencia hacia el ni_interface */ + g_object_unref (ni_ip->priv->ni_interface); + + parent_class->dispose (obj); +} + +static void ni_ip_finalize (GObject *obj) { + NIIP *ni_ip; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + ni_ip = NI_IP (obj); + + /* Nada que hacer, por el momento */ + + parent_class->finalize (obj); +} + +static void ni_ip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NIIP *ni_ip = NI_IP (object); + g_return_if_fail (NI_IS_IP (object)); + + switch (prop_id) { + case PROP_NI_INTERFACE: + ni_ip->priv->ni_interface = NI_INTERFACE (g_value_get_object (value)); + g_object_ref (ni_ip->priv->ni_interface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_ip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NIIP *ni_ip = NI_IP (object); + g_return_if_fail (NI_IS_IP (object)); + + switch (prop_id) { + case PROP_NI_INTERFACE: + g_value_set_object (value, ni_ip->priv->ni_interface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_ip_class_init (NIIPClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = ni_ip_set_property; + object_class->get_property = ni_ip_get_property; + object_class->dispose = ni_ip_dispose; + object_class->finalize = ni_ip_finalize; + + obj_properties[PROP_NI_INTERFACE] = g_param_spec_object ( + "ni-interface", + "Network Inador Interface", + "The interface object", + NI_TYPE_INTERFACE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); +} + + +static void ni_ip_init (NIIP *ni_ip) { + NIIPPrivate *priv = ni_ip_get_instance_private (ni_ip); + ni_ip->priv = priv; + + /* initialize all public and private members to reasonable default values. + * They are all automatically initialized to 0 to begin with. */ + priv->ni_interface = NULL; + priv->prefix = 0; + priv->family = AF_UNSPEC; + priv->has_brd = FALSE; + priv->has_local = FALSE; + priv->flags = 0; + priv->scope = 0; + + memset (&priv->addr, 0, sizeof (priv->addr)); + memset (&priv->local_addr, 0, sizeof (priv->local_addr)); + memset (&priv->brd_addr, 0, sizeof (priv->brd_addr)); +} + +/* Los métodos getters */ +gboolean ni_ip_has_local (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), FALSE); + + return ni_ip->priv->has_local; +} + +gboolean ni_ip_has_brd (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), FALSE); + + return ni_ip->priv->has_local; +} + +guint ni_ip_get_family (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), 0); + + return ni_ip->priv->family; +} + +guint ni_ip_get_prefix (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), 0); + + return ni_ip->priv->prefix; +} + +uint32_t ni_ip_get_flags (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), 0); + + return ni_ip->priv->flags; +} + +unsigned char ni_ip_get_scope (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), 0); + + return ni_ip->priv->scope; +} + +const struct_addr *ni_ip_get_addr (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), NULL); + + return &ni_ip->priv->addr; +} + +const struct_addr *ni_ip_get_local_addr (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), NULL); + + return &ni_ip->priv->local_addr; +} + +const struct_addr *ni_ip_get_brd_addr (NIIP *ni_ip) { + g_return_val_if_fail (NI_IS_IP (ni_ip), NULL); + + return &ni_ip->priv->brd_addr; +} + + +NIIP *ni_ip_new (NIInterface *ni_interface, int family, int prefix, struct_addr *addr, uint32_t flags, unsigned char scope, int has_local, struct_addr *local_addr, int has_brd, struct_addr *brd_addr) { + NIIP *ni_ip; + + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), NULL); + + ni_ip = g_object_new (NI_TYPE_IP, "ni-interface", ni_interface, NULL); + + /* Establecer y copiar los valores */ + ni_ip->priv->family = family; + ni_ip->priv->prefix = prefix; + ni_ip->priv->has_local = has_local; + ni_ip->priv->has_brd = has_brd; + ni_ip->priv->flags = flags; + ni_ip->priv->scope = scope; + + if (family == AF_INET) { + ni_ip->priv->family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + ni_ip->priv->family_size = sizeof (struct in6_addr); + } + + memcpy (&ni_ip->priv->addr, addr, ni_ip->priv->family_size); + if (has_local) { + memcpy (&ni_ip->priv->local_addr, local_addr, ni_ip->priv->family_size); + } + + if (has_brd) { + memcpy (&ni_ip->priv->brd_addr, brd_addr, ni_ip->priv->family_size); + } + + return ni_ip; +} + diff --git a/client-gtk/ni-ip.h b/client-gtk/ni-ip.h new file mode 100644 index 0000000..f9eaba5 --- /dev/null +++ b/client-gtk/ni-ip.h @@ -0,0 +1,88 @@ +/* + * ni-interface.h + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* inclusion guard */ +#ifndef __NI_IP_H__ +#define __NI_IP_H__ + +#include + +#include + +#include +#include + +G_BEGIN_DECLS + +typedef union { + struct in_addr v4; + struct in6_addr v6; +} struct_addr; + +typedef struct _NIIPClass NIIPClass; +typedef struct _NIIP NIIP; +typedef struct _NIIPPrivate NIIPPrivate; + +typedef struct _NIInterface NIInterface; + +/* + * Type declaration. + */ +#define NI_TYPE_IP (ni_ip_get_type ()) +#define NI_IP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NI_TYPE_IP, NIIP)) +#define NI_IP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NI_TYPE_IP, NIIPClass)) +#define NI_IS_IP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NI_TYPE_IP)) +#define NI_IS_IP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NI_TYPE_IP)) +#define NI_IP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NI_TYPE_IP, NIIPClass)) + +GType ni_ip_get_type (void); + +struct _NIIPClass { + GObjectClass parent_class; + +}; + +struct _NIIP { + GObject parent_instance; + + NIIPPrivate *priv; +}; + +/* + * Method definitions. + */ + +gboolean ni_ip_has_local (NIIP *ni_ip); +gboolean ni_ip_has_brd (NIIP *ni_ip); +guint ni_ip_get_family (NIIP *ni_ip); +guint ni_ip_get_prefix (NIIP *ni_ip); +uint32_t ni_ip_get_flags (NIIP *ni_ip); +unsigned char ni_ip_get_scope (NIIP *ni_ip); +const struct_addr *ni_ip_get_addr (NIIP *ni_ip); +const struct_addr *ni_ip_get_local_addr (NIIP *ni_ip); +const struct_addr *ni_ip_get_brd_addr (NIIP *ni_ip); + +NIIP *ni_ip_new (NIInterface *ni_interface, int family, int prefix, struct_addr *addr, uint32_t flags, unsigned char scope, int has_local, struct_addr *local_addr, int has_brd, struct_addr *brd_addr); + +G_END_DECLS + +#endif /* __NI_IP_H__ */ diff --git a/client-gtk/ni-marshal.list b/client-gtk/ni-marshal.list new file mode 100644 index 0000000..efd30bc --- /dev/null +++ b/client-gtk/ni-marshal.list @@ -0,0 +1 @@ +BOOLEAN:POINTER,UINT diff --git a/client-gtk/ni-window-interface.c b/client-gtk/ni-window-interface.c new file mode 100644 index 0000000..6812936 --- /dev/null +++ b/client-gtk/ni-window-interface.c @@ -0,0 +1,416 @@ +/* + * ni-window-interface.c + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#include +#include +#include + +#include + +#include +#include +#include + +#include "ni-window-interface.h" + +#include "ni-client.h" +#include "ni-interface.h" +#include "ni-ip.h" + +enum { + IP_FAMILY, + IP_ADDR, + IP_PREFIX, + IP_LOCAL_ADDR, + + IP_OBJECT, + + NUM_COLS_IP +}; + +struct _NIWindowInterfacePrivate { + NIInterface *ni_interface; + + GtkWidget *vbox, *notebook; + GtkWidget *vbox_ipv4, *vbox_ipv6; + GtkListStore *ipv4_store, *ipv6_store; + GtkWidget *tree_ipv4, *tree_ipv6; +}; + +enum { + PROP_NI_INTERFACE = 1, + + N_PROPERTIES +}; + +enum { + IP_STORE_COL_MAIN_IP, + IP_STORE_COL_BROADCAST, + IP_STORE_COL_OBJECT, + + NUM_IP_STORE_COLS +}; + +G_DEFINE_TYPE_WITH_PRIVATE (NIWindowInterface, ni_window_interface, GTK_TYPE_WINDOW) + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +#if 0 +static GObject *ni_interface_constructor (GType type, guint n_construct_properties, GObjectConstructParam *construct_properties) { + GObject *obj; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + NIInterface *ni_interface; + + obj = parent_class->constructor (type, n_construct_properties, construct_properties); + + ni_interface = NI_INTERFACE (obj); + { + int g; + for (g = 0; g < n_construct_properties; g++) { + GParamSpec *pspec = construct_properties[g].pspec; + GValue *value = construct_properties[g].value; + + /* Manejar el valor */ + if (strcmp (g_param_spec_get_name (pspec), "index") == 0) { + printf ("Estableciendo sobre el constructor, el index\n"); + ni_interface->priv->index = g_value_get_uint (value); + + ni_interface_check_and_connect_signal (ni_interface); + } else if (strcmp (g_param_spec_get_name (pspec), "ni-client") == 0) { + ni_interface->priv->ni_client = NI_CLIENT (g_value_get_object (value)); + + } + } + } + + return obj; +} +#endif + +static void ni_window_interface_ip_addr_add (NIWindowInterface *window_iface, NIIP *ni_ip) { + GtkTreeIter iter; + char buffer[256], ip[128], local[128]; + guint prefix, family, family_size; + + family = ni_ip_get_family (ni_ip); + inet_ntop (family, ni_ip_get_addr (ni_ip), ip, sizeof (ip)); + prefix = ni_ip_get_prefix (ni_ip); + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + if (ni_ip_has_local (ni_ip) && + memcmp (ni_ip_get_local_addr (ni_ip), ni_ip_get_addr (ni_ip), family_size) != 0) { + inet_ntop (family, ni_ip_get_local_addr (ni_ip), local, sizeof (local)); + + snprintf (buffer, sizeof (buffer), "%s peer %s/%u", local, ip, prefix); + } else { + snprintf (buffer, sizeof (buffer), "%s/%u", ip, prefix); + } + + if (family == AF_INET) { + gtk_list_store_insert (window_iface->priv->ipv4_store, &iter, -1); + gtk_list_store_set (window_iface->priv->ipv4_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1); + } else if (family == AF_INET6) { + gtk_list_store_insert (window_iface->priv->ipv6_store, &iter, -1); + gtk_list_store_set (window_iface->priv->ipv6_store, &iter, IP_STORE_COL_MAIN_IP, buffer, IP_STORE_COL_OBJECT, ni_ip, -1); + } +} + +static void ni_window_interface_ip_add_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); + ni_window_interface_ip_addr_add (window_iface, ni_ip); +} + +static void ni_window_interface_ip_del_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { + GtkTreeIter iter; + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); + gboolean has; + guint family; + GtkListStore *p; + void *iter_obj; + + family = ni_ip_get_family (ni_ip); + + if (family == AF_INET) { + p = window_iface->priv->ipv4_store; + } else if (family == AF_INET6) { + p = window_iface->priv->ipv6_store; + } + + has = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (p), &iter); + while (has) { + gtk_tree_model_get (GTK_TREE_MODEL (p), &iter, IP_STORE_COL_OBJECT, &iter_obj, -1); + + if (iter_obj == ni_ip) { + /* Eliminar este objeto */ + gtk_list_store_remove (p, &iter); + return; + } + has = gtk_tree_model_iter_next (GTK_TREE_MODEL (p), &iter); + } +} + +static void ni_window_interface_changed_name_cb (GObject *object, GParamSpec *sp, gpointer data) { + NIInterface *ni_interface = NI_INTERFACE (object); + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); + gchar *name; + + /* Cambiar el título */ + name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface)); + gtk_window_set_title (GTK_WINDOW (window_iface), name); + g_free (name); +} + +static void ni_window_interface_constructed (GObject *obj) { + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (obj); + const GList *ip_list, *g; + NIIP *ni_ip; + gchar *name; + + parent_class->constructed (obj); + + if (window_iface->priv->ni_interface == NULL) return; + + /* Cambiar el título */ + name = g_strdup_printf ("Interfaz %s", ni_interface_get_name (window_iface->priv->ni_interface)); + gtk_window_set_title (GTK_WINDOW (obj), name); + g_free (name); + + /* TODO: Recorrer las ips, y procesar la información */ + ip_list = ni_interface_get_ip_list (window_iface->priv->ni_interface); + + for (g = ip_list; g != NULL; g = g->next) { + ni_ip = (NIIP *) g->data; + + ni_window_interface_ip_addr_add (window_iface, ni_ip); + } + + /* Conectar la señal de IP agregada y la señal de IP eliminada */ + g_signal_connect (window_iface->priv->ni_interface, "new-ip", G_CALLBACK (ni_window_interface_ip_add_cb), window_iface); + g_signal_connect (window_iface->priv->ni_interface, "delete-ip", G_CALLBACK (ni_window_interface_ip_del_cb), window_iface); + g_signal_connect (window_iface->priv->ni_interface, "notify::name", G_CALLBACK (ni_window_interface_changed_name_cb), window_iface); +} + +static void ni_window_interface_dispose (GObject *obj) { + NIWindowInterface *window_iface; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + window_iface = NI_WINDOW_INTERFACE (obj); + + g_object_unref (window_iface->priv->ni_interface); + + parent_class->dispose (obj); +} + +static void ni_window_interface_finalize (GObject *obj) { + NIWindowInterface *window_iface; + GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + + window_iface = NI_WINDOW_INTERFACE (obj); + + /* Nada que hacer, por el momento */ + + parent_class->finalize (obj); +} + +static void ni_window_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object); + g_return_if_fail (NI_IS_WINDOW_INTERFACE (object)); + + switch (prop_id) { + case PROP_NI_INTERFACE: + window_iface->priv->ni_interface = NI_INTERFACE (g_value_get_object (value)); + g_object_ref (window_iface->priv->ni_interface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_window_interface_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object); + g_return_if_fail (NI_IS_WINDOW_INTERFACE (object)); + + switch (prop_id) { + case PROP_NI_INTERFACE: + g_value_set_object (value, window_iface->priv->ni_interface); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_window_interface_class_init (NIWindowInterfaceClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass); + + object_class->set_property = ni_window_interface_set_property; + object_class->get_property = ni_window_interface_get_property; + object_class->constructed = ni_window_interface_constructed; + object_class->dispose = ni_window_interface_dispose; + object_class->finalize = ni_window_interface_finalize; + + obj_properties[PROP_NI_INTERFACE] = g_param_spec_object ( + "ni-interface", + "Network Inador Client Interface", + "The interface object", + NI_TYPE_INTERFACE, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); +} + +GtkWidget *ni_window_interface_create_tree (GtkListStore *store, GtkWidget **tree) { + GtkWidget *scrolled; + GtkAdjustment *h, *v; + GtkTreeViewColumn *column; + GtkCellRenderer *renderer; + + *tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store)); + + h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); + v = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree)); + + scrolled = gtk_scrolled_window_new (h, v); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Dirección", renderer, "text", IP_STORE_COL_MAIN_IP, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column); + + gtk_container_add (GTK_CONTAINER (scrolled), *tree); + + return scrolled; +} + +static void ni_window_interface_init (NIWindowInterface *window_iface) { + NIWindowInterfacePrivate *priv = ni_window_interface_get_instance_private (window_iface); + window_iface->priv = priv; + GtkWindow *window = GTK_WINDOW (window_iface); + GtkWidget *hbox, *label, *button, *image; + GtkWidget *vbox, *scrolled, *vbox2; + + /* initialize all public and private members to reasonable default values. + * They are all automatically initialized to 0 to begin with. */ + priv->ni_interface = NULL; + gtk_window_set_title (window, "Interfaz"); + g_signal_connect (window, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL); + + priv->vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_container_add (GTK_CONTAINER (window), priv->vbox); + + priv->notebook = gtk_notebook_new (); + gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0); + + /* Página de IPv4 */ + priv->vbox_ipv4 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + label = gtk_label_new ("IPv4"); + gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv4, label); + gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv4), 5); + + /* Preparar el list store */ + priv->ipv4_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (priv->vbox_ipv4), vbox, TRUE, TRUE, 5); + + label = gtk_label_new ("Direcciones:"); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + scrolled = ni_window_interface_create_tree (priv->ipv4_store, &priv->tree_ipv4); + gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0); + + /* Botonera del tree view */ + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + + button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + + + /* Página de IPv6 */ + priv->vbox_ipv6 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + label = gtk_label_new ("IPv6"); + gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_ipv6, label); + gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_ipv6), 5); + + /* Preparar el list store */ + priv->ipv6_store = gtk_list_store_new (NUM_IP_STORE_COLS, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (priv->vbox_ipv6), vbox, TRUE, TRUE, 5); + + label = gtk_label_new ("Direcciones:"); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0); + + scrolled = ni_window_interface_create_tree (priv->ipv6_store, &priv->tree_ipv6); + gtk_box_pack_start (GTK_BOX (hbox), scrolled, TRUE, TRUE, 0); + + /* Botonera del tree view */ + vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0); + + button = gtk_button_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + + button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), button, FALSE, FALSE, 0); + + /* La botonera inferior */ + hbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL); + gtk_button_box_set_layout (GTK_BUTTON_BOX (hbox), GTK_BUTTONBOX_END); + gtk_box_pack_start (GTK_BOX (priv->vbox), hbox, FALSE, FALSE, 0); + + /* El boton de cerrar */ + button = gtk_button_new_with_label ("Cerrar"); + g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_hide_on_delete), window); + image = gtk_image_new_from_icon_name ("window-close", GTK_ICON_SIZE_BUTTON); + gtk_button_set_image (GTK_BUTTON (button), image); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + + gtk_widget_show_all (priv->vbox); +} + +GtkWidget* ni_window_interface_new (NIInterface *ni_interface) { + NIWindowInterface *window_iface; + + window_iface = g_object_new (NI_TYPE_WINDOW_INTERFACE, "type", GTK_WINDOW_TOPLEVEL, "ni-interface", ni_interface, NULL); + + return GTK_WIDGET (window_iface); +} + diff --git a/client-gtk/ni-window-interface.h b/client-gtk/ni-window-interface.h new file mode 100644 index 0000000..d9832ca --- /dev/null +++ b/client-gtk/ni-window-interface.h @@ -0,0 +1,71 @@ +/* + * ni-window-interface.h + * This file is part of NetworkInador + * + * Copyright (C) 2021 - Gatuno + * + * NetworkInador 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. + * + * NetworkInador 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 NetworkInador; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* inclusion guard */ +#ifndef __NI_WINDOW_INTERFACE_H__ +#define __NI_WINDOW_INTERFACE_H__ + + +#include + +#include +#include + +#include "ni-interface.h" + +G_BEGIN_DECLS + +typedef struct _NIWindowInterfaceClass NIWindowInterfaceClass; +typedef struct _NIWindowInterface NIWindowInterface; +typedef struct _NIWindowInterfacePrivate NIWindowInterfacePrivate; + +/* + * Type declaration. + */ +#define NI_TYPE_WINDOW_INTERFACE (ni_window_interface_get_type ()) +#define NI_WINDOW_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NI_TYPE_WINDOW_INTERFACE, NIWindowInterface)) +#define NI_WINDOW_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NI_TYPE_WINDOW_INTERFACE, NIWindowInterfaceClass)) +#define NI_IS_WINDOW_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NI_TYPE_WINDOW_INTERFACE)) +#define NI_IS_WINDOW_INTERFACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NI_TYPE_WINDOW_INTERFACE)) +#define NI_WINDOW_INTERFACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NI_TYPE_WINDOW_INTERFACE, NIWindowInterfaceClass)) + +GType ni_window_interface_get_type (void); + +struct _NIWindowInterfaceClass { + GtkWindowClass parent_class; + +}; + +struct _NIWindowInterface { + GtkWindow parent_instance; + + NIWindowInterfacePrivate *priv; +}; + +/* + * Method definitions. + */ +GtkWidget* ni_window_interface_new (NIInterface *ni_interface); + +G_END_DECLS + +#endif /* __NI_WINDOW_INTERFACE_H__ */ diff --git a/configure.ac b/configure.ac index 52556a2..6e7edf3 100644 --- a/configure.ac +++ b/configure.ac @@ -36,11 +36,16 @@ esac GLIB_VERSION=2.50 LIBNL_VERSION=0.29 +GTK3_VERSION=3.24 AC_MSG_CHECKING([if you have Glib installed on your system]) PKG_CHECK_EXISTS([glib-2.0 >= $GLIB_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([Glib not found in your system])]) PKG_CHECK_MODULES(GLIB, [glib-2.0 >= $GLIB_VERSION], [], []) +AC_MSG_CHECKING([if you have GTK+3 installed on your system]) +PKG_CHECK_EXISTS([gtk+-3.0 >= $GTK3_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([GTK+3 not found in your system])]) +PKG_CHECK_MODULES(GTK, [gtk+-3.0 >= $GTK3_VERSION], [], []) + AC_MSG_CHECKING([if you have libnl-3 installed on your system]) PKG_CHECK_EXISTS([libnl-3.0 >= LIBNL_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([libnl-3 not found in your system])]) PKG_CHECK_MODULES(LIBNL3, [libnl-3.0 >= $LIBNL_VERSION], [], []) @@ -49,11 +54,15 @@ AC_MSG_CHECKING([if you have libnl-gen-3 installed on your system]) PKG_CHECK_EXISTS([libnl-genl-3.0 >= LIBNL_VERSION], [AC_MSG_RESULT([yes])], [AC_MSG_FAILURE([libnl-gen-3 not found in your system])]) PKG_CHECK_MODULES(LIBNLGEN3, [libnl-genl-3.0 >= $LIBNL_VERSION], [], []) +GLIB_GENMARSHAL="$($PKG_CONFIG --variable=glib_genmarshal glib-2.0)" +AC_SUBST([GLIB_GENMARSHAL]) + AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([ Makefile src/Makefile + client-gtk/Makefile po/Makefile.in ]) # src/dhcpc/Makefile