708 lines
25 KiB
C
708 lines
25 KiB
C
/*
|
|
* ni-window-route.c
|
|
* This file is part of Network Inador
|
|
*
|
|
* Copyright (C) 2022 - Félix Arreola Rodríguez
|
|
*
|
|
* Network Inador 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.
|
|
*
|
|
* Network Inador 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 Network Inador; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <linux/if_addr.h>
|
|
#include <linux/if.h>
|
|
|
|
#include "ni-window-route.h"
|
|
|
|
#include "ni-client.h"
|
|
#include "ni-route.h"
|
|
#include "ni-interface.h"
|
|
#include "ni-add-route-dialog.h"
|
|
|
|
|
|
struct _NIWindowRoutePrivate {
|
|
NIClient *ni_client;
|
|
|
|
int family;
|
|
|
|
uint32_t table_filter;
|
|
GtkWidget *vbox, *tree_routes;
|
|
GtkListStore *routes_store;
|
|
GtkTreeModel *routes_filtered;
|
|
GtkListStore *tables_store;
|
|
|
|
GtkWidget *del_route_button;
|
|
GtkWidget *combo_tables;
|
|
};
|
|
|
|
enum {
|
|
PROP_NI_CLIENT = 1,
|
|
|
|
PROP_NI_FAMILY,
|
|
|
|
PROP_NI_TABLE_FILTER,
|
|
|
|
N_PROPERTIES
|
|
};
|
|
|
|
enum {
|
|
ROUTE_STORE_TABLE,
|
|
ROUTE_STORE_COL_DST_GW,
|
|
|
|
ROUTE_STORE_COL_METRIC,
|
|
|
|
ROUTE_STORE_COL_PREFSRC,
|
|
|
|
// TODO: Agregar tipo de protocolo, tos, scope
|
|
ROUTE_STORE_COL_OBJECT,
|
|
|
|
NUM_ROUTE_STORE_COLS
|
|
};
|
|
|
|
enum {
|
|
TABLE_STORE_TABLE,
|
|
TABLE_STORE_NAME,
|
|
|
|
TABLE_STORE_IS_NEW,
|
|
|
|
NUM_TABLE_STORE_COLS
|
|
};
|
|
|
|
struct _NIWindowRouteSearchTable {
|
|
gboolean found;
|
|
uint32_t tabla;
|
|
GtkTreeIter iter;
|
|
};
|
|
|
|
struct _NIWindowRouteSearchRoute {
|
|
gboolean found;
|
|
void *obj;
|
|
GtkTreeIter iter;
|
|
};
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (NIWindowRoute, ni_window_route, GTK_TYPE_WINDOW)
|
|
|
|
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
|
|
|
static gboolean ni_window_route_foreach_tables_search_id (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
|
|
static gboolean ni_window_route_foreach_routes_search_route (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer data);
|
|
static void ni_window_interface_new_route_cb (NIClient *ni_client, NIRoute *ni_route, gpointer data);
|
|
static void ni_window_interface_delete_route_cb (NIClient *ni_client, NIRoute *ni_route, gpointer data);
|
|
|
|
static void ni_window_route_updated_route_cb (NIRoute *ni_route, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
struct _NIWindowRouteSearchRoute for_search;
|
|
char buffer_ip[256];
|
|
guint priority;
|
|
const struct_addr *dest;
|
|
int family;
|
|
|
|
family = ni_route_get_family (ni_route);
|
|
|
|
/* Preparar el pref-src, si lo tiene */
|
|
buffer_ip[0] = 0;
|
|
if (ni_route_has_prefsrc (ni_route)) {
|
|
dest = ni_route_get_prefsrc (ni_route);
|
|
|
|
inet_ntop (family, dest, buffer_ip, sizeof (buffer_ip));
|
|
}
|
|
|
|
priority = ni_route_get_priority (ni_route);
|
|
|
|
for_search.found = FALSE;
|
|
for_search.obj = ni_route;
|
|
|
|
gtk_tree_model_foreach (GTK_TREE_MODEL (window_route->priv->routes_store), ni_window_route_foreach_routes_search_route, &for_search);
|
|
|
|
if (for_search.found == TRUE) {
|
|
/* Tengo fila, actualizar los valores */
|
|
gtk_list_store_set (window_route->priv->routes_store, &for_search.iter, ROUTE_STORE_COL_METRIC, priority, ROUTE_STORE_COL_PREFSRC, buffer_ip, -1);
|
|
}
|
|
}
|
|
|
|
static void ni_window_route_route_added_cb (NIWindowRoute *window_route, NIRoute *ni_route) {
|
|
int family, prefix;
|
|
char buffer_ip[256], buffer[512];
|
|
const struct_addr *dest;
|
|
uint32_t table;
|
|
guint priority;
|
|
struct _NIWindowRouteSearchTable for_search;
|
|
|
|
family = ni_route_get_family (ni_route);
|
|
dest = ni_route_get_dest (ni_route);
|
|
prefix = ni_route_get_prefix (ni_route);
|
|
table = ni_route_get_table (ni_route);
|
|
priority = ni_route_get_priority (ni_route);
|
|
|
|
if (family != window_route->priv->family) {
|
|
return;
|
|
}
|
|
|
|
/* Preparar el dest-gw */
|
|
inet_ntop (family, dest, buffer_ip, sizeof (buffer_ip));
|
|
if (family == AF_INET && prefix == 32) {
|
|
snprintf (buffer, sizeof (buffer), "%s", buffer_ip);
|
|
} else if (family == AF_INET6 && prefix == 128) {
|
|
snprintf (buffer, sizeof (buffer), "%s", buffer_ip);
|
|
} else {
|
|
snprintf (buffer, sizeof (buffer), "%s/%i", buffer_ip, prefix);
|
|
}
|
|
|
|
/* Preparar el pref-src, si lo tiene */
|
|
buffer_ip[0] = 0;
|
|
if (ni_route_has_prefsrc (ni_route)) {
|
|
dest = ni_route_get_prefsrc (ni_route);
|
|
|
|
inet_ntop (family, dest, buffer_ip, sizeof (buffer_ip));
|
|
}
|
|
|
|
/* Revisar que la tabla exista, si la tabla no existe, la creamos en el menú de la lista de tablas */
|
|
for_search.found = FALSE;
|
|
for_search.tabla = table;
|
|
|
|
gtk_tree_model_foreach (GTK_TREE_MODEL (window_route->priv->tables_store), ni_window_route_foreach_tables_search_id, &for_search);
|
|
|
|
if (for_search.found == FALSE) {
|
|
/* Insertar el valor en el list store de las tablas */
|
|
gtk_list_store_insert_with_values (window_route->priv->tables_store, NULL, -1, TABLE_STORE_TABLE, table, TABLE_STORE_NAME, NULL, TABLE_STORE_IS_NEW, FALSE, -1);
|
|
}
|
|
|
|
gtk_list_store_insert_with_values (window_route->priv->routes_store, NULL, -1, ROUTE_STORE_TABLE, table, ROUTE_STORE_COL_DST_GW, buffer, ROUTE_STORE_COL_METRIC, priority, ROUTE_STORE_COL_PREFSRC, buffer_ip, ROUTE_STORE_COL_OBJECT, ni_route, -1);
|
|
|
|
g_signal_connect (ni_route, "updated", G_CALLBACK (ni_window_route_updated_route_cb), window_route);
|
|
}
|
|
|
|
/* Función para renderizar la tabla y el nombre con guion separado */
|
|
void ni_window_route_cell_renderer_table_id (GtkCellLayout *cell_layout, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) {
|
|
uint32_t tabla;
|
|
const gchar *name;
|
|
gboolean new;
|
|
char buffer[1024];
|
|
|
|
gtk_tree_model_get (tree_model, iter, TABLE_STORE_TABLE, &tabla, TABLE_STORE_NAME, &name, TABLE_STORE_IS_NEW, &new, -1);
|
|
|
|
if (new == FALSE) {
|
|
if (name == NULL) {
|
|
g_snprintf (buffer, sizeof (buffer), "%i - (Sin nombre)", tabla);
|
|
} else {
|
|
g_snprintf (buffer, sizeof (buffer), "%i - %s", tabla, name);
|
|
}
|
|
g_object_set (cell, "text", buffer, NULL);
|
|
} else {
|
|
g_object_set (cell, "text", "Nueva tabla...", NULL);
|
|
}
|
|
}
|
|
|
|
/* Función para renderizar la gateway */
|
|
void ni_window_route_cell_renderer_gw_oiface (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell, GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) {
|
|
NIRoute *ni_route;
|
|
NIClient *ni_client;
|
|
NIInterface *ni_interface;
|
|
int family;
|
|
char buffer_ip[256], buffer[8192];
|
|
int buffer_len;
|
|
int g, num_nexthops;
|
|
const NIRouteNH *nexthops;
|
|
|
|
gtk_tree_model_get (tree_model, iter, ROUTE_STORE_COL_OBJECT, &ni_route, -1);
|
|
|
|
family = ni_route_get_family (ni_route);
|
|
|
|
ni_client = ni_route_get_client (ni_route);
|
|
num_nexthops = ni_route_get_num_nexthops (ni_route);
|
|
nexthops = ni_route_get_nexthops (ni_route);
|
|
buffer_len = 0;
|
|
for (g = 0; g < num_nexthops; g++) {
|
|
if (g != 0) {
|
|
/* Anexar la coma, */
|
|
buffer_len += g_snprintf (&buffer[buffer_len], sizeof (buffer) - buffer_len, ", ");
|
|
}
|
|
|
|
if (nexthops[g].has_gw) {
|
|
inet_ntop (family, &nexthops[g].gw, buffer_ip, sizeof (buffer_ip));
|
|
|
|
buffer_len += g_snprintf (&buffer[buffer_len], sizeof (buffer) - buffer_len, "%s ", buffer_ip);
|
|
}
|
|
|
|
ni_interface = ni_client_get_interface_by_index (ni_client, nexthops[g].out_index);
|
|
if (ni_interface == NULL) {
|
|
buffer_len += g_snprintf (&buffer[buffer_len], sizeof (buffer) - buffer_len, "[¿?]");
|
|
} else {
|
|
buffer_len += g_snprintf (&buffer[buffer_len], sizeof (buffer) - buffer_len, "[%s]", ni_interface_get_name (ni_interface));
|
|
}
|
|
}
|
|
|
|
g_object_set (cell, "text", buffer, NULL);
|
|
}
|
|
|
|
static gboolean ni_window_route_delete_event (GtkWidget *widget, GdkEventAny *event) {
|
|
return gtk_widget_hide_on_delete (widget);
|
|
}
|
|
|
|
static void ni_window_route_constructed (GObject *obj) {
|
|
GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW));
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (obj);
|
|
const GList *route_list = NULL, *g;
|
|
NIRoute *ni_route;
|
|
|
|
parent_class->constructed (obj);
|
|
|
|
if (window_route->priv->ni_client == 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);*/
|
|
|
|
/* Conectar la señal de ruta agregada y ruta eliminada */
|
|
g_signal_connect (window_route->priv->ni_client, "new-route", G_CALLBACK (ni_window_interface_new_route_cb), window_route);
|
|
g_signal_connect (window_route->priv->ni_client, "delete-route", G_CALLBACK (ni_window_interface_delete_route_cb), window_route);
|
|
|
|
/* Recorrer las rutas, y procesar la información */
|
|
if (window_route->priv->family == AF_INET) {
|
|
route_list = ni_client_get_routes_v4 (window_route->priv->ni_client);
|
|
} else if (window_route->priv->family == AF_INET6) {
|
|
route_list = ni_client_get_routes_v6 (window_route->priv->ni_client);
|
|
}
|
|
|
|
for (g = route_list; g != NULL; g = g->next) {
|
|
ni_route = (NIRoute *) g->data;
|
|
|
|
ni_window_route_route_added_cb (window_route, ni_route);
|
|
}
|
|
}
|
|
|
|
static void ni_window_route_dispose (GObject *obj) {
|
|
NIWindowRoute *window_route;
|
|
GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW));
|
|
|
|
window_route = NI_WINDOW_ROUTE (obj);
|
|
|
|
g_object_unref (window_route->priv->ni_client);
|
|
window_route->priv->ni_client = NULL;
|
|
|
|
parent_class->dispose (obj);
|
|
}
|
|
|
|
static void ni_window_route_change_filter_table_id (NIWindowRoute *window_route, uint32_t new_table) {
|
|
/* Primero, guardar el valor nuevo */
|
|
window_route->priv->table_filter = new_table;
|
|
|
|
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (window_route->priv->routes_filtered));
|
|
|
|
/* Notificar el cambio de propiedad */
|
|
g_object_notify_by_pspec (G_OBJECT (window_route), obj_properties[PROP_NI_TABLE_FILTER]);
|
|
}
|
|
|
|
static gboolean ni_window_route_foreach_tables_search_id (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
|
|
struct _NIWindowRouteSearchTable *for_search = (struct _NIWindowRouteSearchTable *) data;
|
|
uint32_t tabla;
|
|
gboolean is_new;
|
|
|
|
gtk_tree_model_get (tree_model, iter, TABLE_STORE_TABLE, &tabla, TABLE_STORE_IS_NEW, &is_new, -1);
|
|
if (is_new) return FALSE;
|
|
|
|
if (tabla == for_search->tabla) {
|
|
for_search->found = TRUE;
|
|
for_search->iter = *iter;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean ni_window_route_foreach_routes_search_route (GtkTreeModel *tree_model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
|
|
struct _NIWindowRouteSearchRoute *for_search = (struct _NIWindowRouteSearchRoute *) data;
|
|
void *route;
|
|
|
|
gtk_tree_model_get (tree_model, iter, ROUTE_STORE_COL_OBJECT, &route, -1);
|
|
|
|
if (route == for_search->obj) {
|
|
for_search->found = TRUE;
|
|
for_search->iter = *iter;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gint ni_window_route_sort_tables_func (GtkTreeModel *tree_model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data) {
|
|
uint32_t tabla_a, tabla_b;
|
|
gboolean is_new_a, is_new_b;
|
|
|
|
gtk_tree_model_get (tree_model, a, TABLE_STORE_TABLE, &tabla_a, TABLE_STORE_IS_NEW, &is_new_a, -1);
|
|
gtk_tree_model_get (tree_model, b, TABLE_STORE_TABLE, &tabla_b, TABLE_STORE_IS_NEW, &is_new_b, -1);
|
|
|
|
if (is_new_a) {
|
|
return 1;
|
|
}
|
|
|
|
if (is_new_b) {
|
|
return -1;
|
|
}
|
|
|
|
return tabla_a - tabla_b;
|
|
}
|
|
|
|
static void ni_window_route_changed_combo_table_cb (GtkWidget *combo, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
GtkTreeIter iter;
|
|
uint32_t tabla;
|
|
gboolean is_new;
|
|
struct _NIWindowRouteSearchTable for_search;
|
|
|
|
gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
|
|
gtk_tree_model_get (GTK_TREE_MODEL (window_route->priv->tables_store), &iter, TABLE_STORE_TABLE, &tabla, TABLE_STORE_IS_NEW, &is_new, -1);
|
|
|
|
if (is_new) {
|
|
/* TODO: Presentar el cuadro de dialogo de creación de nueva tabla */
|
|
|
|
/* Localizar el valor previo de la tabla, para regresar el combo */
|
|
for_search.found = FALSE;
|
|
for_search.tabla = window_route->priv->table_filter;
|
|
|
|
gtk_tree_model_foreach (GTK_TREE_MODEL (window_route->priv->tables_store), ni_window_route_foreach_tables_search_id, &for_search);
|
|
if (for_search.found) {
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &for_search.iter);
|
|
} else {
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), NULL);
|
|
}
|
|
} else {
|
|
/* Aplicar el nuevo filtro */
|
|
ni_window_route_change_filter_table_id (window_route, tabla);
|
|
}
|
|
}
|
|
|
|
gboolean ni_window_route_tree_filter_routes_func (GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
uint32_t tabla;
|
|
|
|
if (window_route->priv->table_filter == 0) return TRUE;
|
|
|
|
gtk_tree_model_get (tree_model, iter, ROUTE_STORE_TABLE, &tabla, -1);
|
|
if (tabla == window_route->priv->table_filter) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void ni_window_interface_new_route_cb (NIClient *ni_client, NIRoute *ni_route, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
|
|
ni_window_route_route_added_cb (window_route, ni_route);
|
|
}
|
|
|
|
static void ni_window_interface_delete_route_cb (NIClient *ni_client, NIRoute *ni_route, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
struct _NIWindowRouteSearchRoute for_search;
|
|
|
|
for_search.found = FALSE;
|
|
for_search.obj = ni_route;
|
|
|
|
gtk_tree_model_foreach (GTK_TREE_MODEL (window_route->priv->routes_store), ni_window_route_foreach_routes_search_route, &for_search);
|
|
|
|
if (for_search.found == TRUE) {
|
|
/* Tengo fila, actualizar los valores */
|
|
gtk_list_store_remove (window_route->priv->routes_store, &for_search.iter);
|
|
}
|
|
}
|
|
|
|
static void ni_window_route_add_route_button_add_cb (GtkWidget *button, gpointer data) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (data);
|
|
GtkWidget *dialog;
|
|
gint response;
|
|
NIClient *ni_client;
|
|
GList *gws;
|
|
int metrica, tabla, tipo;
|
|
struct_addr destino;
|
|
gboolean has_
|
|
dialog = ni_add_route_dialog_new (window_route->priv->family);
|
|
|
|
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window_route));
|
|
|
|
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
|
|
|
|
response = gtk_dialog_run (GTK_DIALOG (dialog));
|
|
|
|
if (response == GTK_RESPONSE_OK) {
|
|
/* Mandar la ip al network-inador */
|
|
ni_client = ni_interface_get_client (window_route->priv->ni_interface);
|
|
|
|
gws = ni_add_route_dialog_get_gateways (NI_ADD_ROUTE_DIALOG (dialog));
|
|
|
|
if (gws != NULL) {
|
|
|
|
}
|
|
|
|
g_list_free_full (gws, g_free);
|
|
#if 0
|
|
ni_ip_add_dialog_get_address (NI_IP_ADD_DIALOG (dialog), &addr, &prefix);
|
|
has_p2p = ni_ip_add_dialog_has_p2p_address (NI_IP_ADD_DIALOG (dialog));
|
|
if (has_p2p) {
|
|
memcpy (&p2p_addr, &addr, sizeof (p2p_addr));
|
|
ni_ip_add_dialog_get_p2p_address (NI_IP_ADD_DIALOG (dialog), &addr);
|
|
}
|
|
|
|
flags |= IFA_F_PERMANENT;
|
|
if (ni_ip_add_dialog_get_noprefix (NI_IP_ADD_DIALOG (dialog))) {
|
|
flags |= IFA_F_NOPREFIXROUTE;
|
|
}
|
|
//void ni_client_ask_ip_new (NIClient *ni_client, 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) {
|
|
|
|
/* TODO: Pedir los tiempos de validez de la interfaz */
|
|
guint32 cacheinfo[2];
|
|
cacheinfo[0] = 60;
|
|
cacheinfo[1] = 60;
|
|
ni_client_ask_ip_new (ni_client, window_iface->priv->ni_interface, family, prefix, &addr, flags, 0, has_p2p, (has_p2p ? &p2p_addr : NULL), FALSE, NULL, cacheinfo);
|
|
#endif
|
|
}
|
|
|
|
gtk_widget_destroy (dialog);
|
|
}
|
|
|
|
static void ni_window_route_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (object);
|
|
g_return_if_fail (NI_IS_WINDOW_ROUTE (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_NI_CLIENT:
|
|
window_route->priv->ni_client = NI_CLIENT (g_value_get_object (value));
|
|
g_object_ref (window_route->priv->ni_client);
|
|
break;
|
|
case PROP_NI_FAMILY:
|
|
window_route->priv->family = g_value_get_uint (value);
|
|
break;
|
|
case PROP_NI_TABLE_FILTER:
|
|
ni_window_route_change_filter_table_id (window_route, g_value_get_uint (value));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_window_route_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
|
|
NIWindowRoute *window_route = NI_WINDOW_ROUTE (object);
|
|
g_return_if_fail (NI_IS_WINDOW_ROUTE (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_NI_CLIENT:
|
|
g_value_set_object (value, window_route->priv->ni_client);
|
|
break;
|
|
case PROP_NI_FAMILY:
|
|
g_value_set_uint (value, window_route->priv->family);
|
|
break;
|
|
case PROP_NI_TABLE_FILTER:
|
|
g_value_set_uint (value, window_route->priv->table_filter);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_window_route_class_init (NIWindowRouteClass *klass) {
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass);
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
object_class->set_property = ni_window_route_set_property;
|
|
object_class->get_property = ni_window_route_get_property;
|
|
object_class->constructed = ni_window_route_constructed;
|
|
object_class->dispose = ni_window_route_dispose;
|
|
|
|
widget_class->delete_event = ni_window_route_delete_event;
|
|
|
|
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_NI_FAMILY] = g_param_spec_uint (
|
|
"family",
|
|
"Family",
|
|
"The routing family.",
|
|
0, G_MAXUINT, 0,
|
|
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE);
|
|
|
|
obj_properties[PROP_NI_TABLE_FILTER] = g_param_spec_uint (
|
|
"table-filter",
|
|
"Tabla filtrada",
|
|
"Tabla filtrada.",
|
|
0, G_MAXUINT, 0,
|
|
G_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
|
|
}
|
|
|
|
GtkWidget *ni_window_route_create_tree_for_routes (GtkTreeModel *store, GtkWidget **tree) {
|
|
GtkWidget *scrolled;
|
|
GtkAdjustment *h, *v;
|
|
GtkTreeViewColumn *column;
|
|
GtkCellRenderer *renderer;
|
|
|
|
*tree = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
|
|
|
|
gtk_tree_view_set_grid_lines (GTK_TREE_VIEW (*tree), GTK_TREE_VIEW_GRID_LINES_HORIZONTAL);
|
|
h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (*tree));
|
|
v = gtk_scrollable_get_vadjustment (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 ("Destino", renderer, "text", ROUTE_STORE_COL_DST_GW, NULL);
|
|
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new ();
|
|
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_column_set_title (GTK_TREE_VIEW_COLUMN (column), "Puerta de enlace");
|
|
gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE);
|
|
gtk_tree_view_column_set_cell_data_func (GTK_TREE_VIEW_COLUMN (column), renderer, ni_window_route_cell_renderer_gw_oiface, NULL, NULL);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new_with_attributes ("Métrica", renderer, "text", ROUTE_STORE_COL_METRIC, NULL);
|
|
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new_with_attributes ("Dir. Origen", renderer, "text", ROUTE_STORE_COL_PREFSRC, NULL);
|
|
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new_with_attributes ("Tabla", renderer, "text", ROUTE_STORE_TABLE, NULL);
|
|
gtk_tree_view_column_set_resizable (GTK_TREE_VIEW_COLUMN (column), TRUE);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (*tree), column);
|
|
|
|
gtk_container_add (GTK_CONTAINER (scrolled), *tree);
|
|
|
|
return scrolled;
|
|
}
|
|
|
|
static void ni_window_route_init (NIWindowRoute *window_route) {
|
|
NIWindowRoutePrivate *priv = ni_window_route_get_instance_private (window_route);
|
|
window_route->priv = priv;
|
|
GtkWindow *window = GTK_WINDOW (window_route);
|
|
GtkWidget *hbox, *label, *button, *image;
|
|
GtkWidget *vbox, *scrolled, *vbox2;
|
|
GtkTreeSelection *selection;
|
|
GtkSizeGroup *size_l;
|
|
GtkTreeIter iter;
|
|
GtkCellRenderer *renderer;
|
|
|
|
/* 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->family = 0;
|
|
gtk_window_set_title (window, "Tabla de ruteo");
|
|
|
|
priv->vbox = vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_container_add (GTK_CONTAINER (window), priv->vbox);
|
|
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
|
|
gtk_box_pack_start (GTK_BOX (vbox), vbox2, FALSE, FALSE, 5);
|
|
|
|
label = gtk_label_new ("Seleccione tabla de ruteo:");
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 0);
|
|
|
|
priv->tables_store = gtk_list_store_new (NUM_TABLE_STORE_COLS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_BOOLEAN);
|
|
/* TODO: Recuperar esta informacion de las tablas de ruteo desde el NetworkInador */
|
|
gtk_list_store_insert_with_values (priv->tables_store, &iter, -1, TABLE_STORE_TABLE, 0, TABLE_STORE_NAME, "Todas", TABLE_STORE_IS_NEW, FALSE, -1);
|
|
gtk_list_store_insert_with_values (priv->tables_store, NULL, -1, TABLE_STORE_TABLE, 254, TABLE_STORE_NAME, "Main", TABLE_STORE_IS_NEW, FALSE, -1);
|
|
gtk_list_store_insert_with_values (priv->tables_store, NULL, -1, TABLE_STORE_TABLE, 255, TABLE_STORE_NAME, "Local", TABLE_STORE_IS_NEW, FALSE, -1);
|
|
gtk_list_store_insert_with_values (priv->tables_store, NULL, -1, TABLE_STORE_TABLE, 0, TABLE_STORE_NAME, NULL, TABLE_STORE_IS_NEW, TRUE, -1);
|
|
|
|
/* Mantener ordenadas las tablas */
|
|
gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (priv->tables_store), ni_window_route_sort_tables_func, NULL, NULL);
|
|
gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (priv->tables_store), GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
|
|
|
|
priv->combo_tables = gtk_combo_box_new_with_model (GTK_TREE_MODEL (priv->tables_store));
|
|
renderer = gtk_cell_renderer_text_new ();
|
|
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (priv->combo_tables), renderer, TRUE);
|
|
gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (priv->combo_tables), renderer, ni_window_route_cell_renderer_table_id, NULL, NULL);
|
|
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (priv->combo_tables), &iter);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), priv->combo_tables, FALSE, FALSE, 0);
|
|
g_signal_connect (priv->combo_tables, "changed", G_CALLBACK (ni_window_route_changed_combo_table_cb), window_route);
|
|
|
|
/* Preparar el list store */
|
|
priv->routes_store = gtk_list_store_new (NUM_ROUTE_STORE_COLS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_POINTER);
|
|
priv->routes_filtered = gtk_tree_model_filter_new (GTK_TREE_MODEL (priv->routes_store), NULL);
|
|
gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (priv->routes_filtered), ni_window_route_tree_filter_routes_func, window_route, NULL);
|
|
|
|
label = gtk_label_new ("Rutas:");
|
|
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_route_create_tree_for_routes (priv->routes_filtered, &priv->tree_routes);
|
|
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);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (ni_window_route_add_route_button_add_cb), window_route);
|
|
|
|
priv->del_route_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), priv->del_route_button, FALSE, FALSE, 0);
|
|
//g_signal_connect (priv->del_route_button, "clicked", G_CALLBACK (ni_window_interface_addr_v6_button_del_cb), window_iface);
|
|
gtk_widget_set_sensitive (priv->del_route_button, FALSE);
|
|
|
|
/* Conectar la señal de cambio de selección del tree view */
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->tree_routes));
|
|
//g_signal_connect (selection, "changed", G_CALLBACK (has_ip_selected_v6_cb), window_iface);
|
|
|
|
/* 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_route_new (NIClient *ni_client, int family) {
|
|
NIWindowRoute *window_route;
|
|
|
|
window_route = g_object_new (NI_TYPE_WINDOW_ROUTE, "type", GTK_WINDOW_TOPLEVEL, "ni-client", ni_client, "family", family, NULL);
|
|
|
|
return GTK_WIDGET (window_route);
|
|
}
|
|
|