diff --git a/client-gtk/Makefile.am b/client-gtk/Makefile.am index ddeb642..643e464 100644 --- a/client-gtk/Makefile.am +++ b/client-gtk/Makefile.am @@ -10,6 +10,7 @@ inador_gtk_client_SOURCES = main.c \ ni-interface.c ni-interface.h \ ni-window-interface.c ni-window-interface.h \ ni-ip.c ni-ip.h \ + ni-ip-add-dialog.c ni-ip-add-dialog.h \ $(BUILT_SOURCES) #inador_gtk_client_CPPFLAGS = -DGAMEDATA_DIR=\"$(gamedatadir)/\" -DLOCALEDIR=\"$(localedir)\" $(AM_CPPFLAGS) diff --git a/client-gtk/main.c b/client-gtk/main.c index 649f603..8c90f30 100644 --- a/client-gtk/main.c +++ b/client-gtk/main.c @@ -257,7 +257,7 @@ int main (int argc, char *argv[]) { 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); + g_signal_connect (ventana, "destroy", G_CALLBACK (cerrar_ventana_cb), NULL); scrolled = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); diff --git a/client-gtk/ni-client.c b/client-gtk/ni-client.c index 67a2e5e..fd3f68e 100644 --- a/client-gtk/ni-client.c +++ b/client-gtk/ni-client.c @@ -374,6 +374,124 @@ void ni_client_ask_interfaces (NIClient *ni_client) { send (ni_client->priv->client_socket, buffer, 2, 0); } +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) { + unsigned char buffer[80]; + uint32_t index; + int family_size; + int pos; + + if (ni_client->priv->client_socket < 0) { + return; + } + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + index = ni_interface_get_index (ni_interface); + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_ADD_IP; + memcpy (&buffer[2], &index, 4); + buffer[6] = family; + buffer[7] = prefix; + + buffer[8] = 0; + if (has_local) { + buffer[8] |= 0x01; + } + + if (has_brd) { + buffer[8] |= 0x02; + } + + buffer[9] = scope; + memcpy (&buffer[10], &flags, 4); + + memcpy (&buffer[14], addr, family_size); + + pos = 14 + family_size; + + if (has_local) { + memcpy (&buffer[pos], local_addr, family_size); + pos += family_size; + } + + if (has_brd) { + memcpy (&buffer[pos], brd_addr, family_size); + pos += family_size; + } + + send (ni_client->priv->client_socket, buffer, pos, 0); +} + +void ni_client_ask_ip_delete (NIClient *ni_client, NIInterface *ni_interface, NIIP *ni_ip) { + unsigned char buffer[32]; + uint32_t index; + int family_size; + int pos; + const struct_addr *addr, *local_addr; + + int family = ni_ip_get_family (ni_ip); + + if (ni_client->priv->client_socket < 0) { + return; + } + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + + index = ni_interface_get_index (ni_interface); + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_REMOVE_IP; + memcpy (&buffer[2], &index, 4); + buffer[6] = family; + buffer[7] = ni_ip_get_prefix (ni_ip); + + buffer[8] = 0; + if (ni_ip_has_local (ni_ip)) { + buffer[8] |= 0x01; + } + + addr = ni_ip_get_addr (ni_ip); + memcpy (&buffer[9], addr, family_size); + pos = 9 + family_size; + + if (ni_ip_has_local (ni_ip)) { + local_addr = ni_ip_get_local_addr (ni_ip); + memcpy (&buffer[9 + family_size], local_addr, family_size); + pos += family_size; + } + + send (ni_client->priv->client_socket, buffer, pos, 0); +} + +void ni_client_ask_change_iface_name (NIClient *ni_client, NIInterface *ni_interface, const gchar *new_name) { + unsigned char buffer[128]; + uint32_t index; + int n_len; + + if (ni_client->priv->client_socket < 0) { + return; + } + + if (new_name[0] == 0) return; + + index = ni_interface_get_index (ni_interface); + buffer[0] = NET_INADOR_TYPE_COMMAND; + buffer[1] = NET_INADOR_COMMAND_IFACE_CHANGE_NAME; + memcpy (&buffer[2], &index, 4); + n_len = strlen (new_name); + buffer[6] = n_len; + memcpy (&buffer[7], new_name, buffer[6]); + + send (ni_client->priv->client_socket, buffer, 7 + n_len, 0); +} + void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, int family) { unsigned char buffer[8]; uint32_t index; @@ -391,6 +509,22 @@ void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, send (ni_client->priv->client_socket, buffer, 7, 0); } +void ni_client_ask_up_down_interface (NIClient *ni_client, NIInterface *ni_interface, gboolean is_up) { + 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] = (is_up ? NET_INADOR_COMMAND_IFACE_UP : NET_INADOR_COMMAND_IFACE_DOWN); + memcpy (&buffer[2], &index, 4); + + send (ni_client->priv->client_socket, buffer, 6, 0); +} + gboolean ni_client_connect (NIClient *ni_client) { int s, ret; struct sockaddr_un path_dest; diff --git a/client-gtk/ni-client.h b/client-gtk/ni-client.h index 3f6b1bc..7b8d91e 100644 --- a/client-gtk/ni-client.h +++ b/client-gtk/ni-client.h @@ -30,6 +30,8 @@ #include #include +#include "ni-ip.h" + G_BEGIN_DECLS typedef struct _NIClientClass NIClientClass; @@ -76,6 +78,10 @@ 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); +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); +void ni_client_ask_ip_delete (NIClient *ni_client, NIInterface *ni_interface, NIIP *ni_ip); +void ni_client_ask_change_iface_name (NIClient *ni_client, NIInterface *ni_interface, const gchar *new_name); +void ni_client_ask_up_down_interface (NIClient *ni_client, NIInterface *ni_interface, gboolean is_up); G_END_DECLS diff --git a/client-gtk/ni-interface.c b/client-gtk/ni-interface.c index f5338cc..b1ad066 100644 --- a/client-gtk/ni-interface.c +++ b/client-gtk/ni-interface.c @@ -146,9 +146,6 @@ static void ni_interface_dispose (GObject *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); } @@ -170,7 +167,6 @@ static void ni_interface_set_property (GObject *object, guint prop_id, const GVa 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); @@ -568,6 +564,13 @@ guint ni_interface_get_index (NIInterface *ni_interface) { return ni_interface->priv->index; } +void ni_interface_set_name (NIInterface *ni_interface, const gchar *name) { + g_return_if_fail (NI_IS_INTERFACE (ni_interface)); + + /* Enviar la petición al ni_client */ + ni_client_ask_change_iface_name (ni_interface->priv->ni_client, ni_interface, name); +} + 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; @@ -593,6 +596,24 @@ const GList *ni_interface_get_ip_list (NIInterface *ni_interface) { return ni_interface->priv->ip_list; } +guint ni_interface_get_flags (NIInterface *ni_interface) { + g_return_val_if_fail (NI_IS_INTERFACE (ni_interface), 0); + + return ni_interface->priv->flags; +} + +void ni_interface_set_down (NIInterface *ni_interface) { + g_return_if_fail (NI_IS_INTERFACE (ni_interface)); + + ni_client_ask_up_down_interface (ni_interface->priv->ni_client, ni_interface, FALSE); +} + +void ni_interface_set_up (NIInterface *ni_interface) { + g_return_if_fail (NI_IS_INTERFACE (ni_interface)); + + ni_client_ask_up_down_interface (ni_interface->priv->ni_client, ni_interface, TRUE); +} + #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)); diff --git a/client-gtk/ni-interface.h b/client-gtk/ni-interface.h index cfe46c5..7c5ca8b 100644 --- a/client-gtk/ni-interface.h +++ b/client-gtk/ni-interface.h @@ -66,10 +66,14 @@ struct _NIInterface { guint ni_interface_get_index (NIInterface *ni_interface); const gchar *ni_interface_get_name (NIInterface *ni_interface); +void ni_interface_set_name (NIInterface *ni_interface, const gchar *name); 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); +guint ni_interface_get_flags (NIInterface *ni_interface); +void ni_interface_set_down (NIInterface *ni_interface); +void ni_interface_set_up (NIInterface *ni_interface); G_END_DECLS diff --git a/client-gtk/ni-ip-add-dialog.c b/client-gtk/ni-ip-add-dialog.c new file mode 100644 index 0000000..ebe6fe2 --- /dev/null +++ b/client-gtk/ni-ip-add-dialog.c @@ -0,0 +1,375 @@ +/* + * ni-add-ip-dialog.c + * This file is part of Network Inador + * + * Copyright (C) 2021 - Gatuno + * + * 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 + +#include + +#include +#include +#include + +#include "ni-ip-add-dialog.h" +#include "ni-ip.h" + +struct _NIIPAddDialogPrivate { + int family; + + GtkWidget *entry; + + GtkWidget *button_add; + + GtkWidget *check_p2p, *entry_p2p; + GtkWidget *check_noprefix; + gboolean valid_main_ip, valid_p2p_ip; +}; + +enum { + PROP_IP_FAMILY = 1, + + N_PROPERTIES +}; + +G_DEFINE_TYPE_WITH_PRIVATE (NIIPAddDialog, ni_ip_add_dialog, GTK_TYPE_DIALOG) + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void split_ip_mask (const char *texto, gchar *ip, int ip_size, gchar *mask, int mask_size) { + gchar *dup; + int g, has_slash = -1; + + mask[0] = 0; + dup = g_strdup (texto); + + for (g = 0; g < strlen (texto); g++) { + if (texto[g] == '/' && texto[g + 1] != 0) { + has_slash = g; + break; + } + } + + if (has_slash >= 0) { + strncpy (mask, &texto[has_slash + 1], mask_size); + strncpy (ip, texto, ip_size); + ip[has_slash] = 0; + } else { + strncpy (ip, texto, ip_size); + } +} + +gboolean ip_valid_ipv4 (const char *ip) { + struct in_addr addr; + + if (inet_pton (AF_INET, ip, &addr) == 0) { + return FALSE; + } + + return TRUE; +} + +gboolean ip_valid_ipv6 (const char *ip) { + struct in6_addr addr; + + if (inet_pton (AF_INET6, ip, &addr) == 0) { + return FALSE; + } + + return TRUE; +} + +static void ni_ip_add_dialog_update_response (NIIPAddDialog *dialog) { + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) && dialog->priv->valid_p2p_ip == FALSE) { + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); + return; + } + + if (dialog->priv->valid_main_ip == FALSE) { + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); + return; + } + + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, TRUE); +} + +static void ni_ip_add_dialog_validate_main_ip (GtkEditable *editable, gpointer data) { + NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); + struct_addr addr; + int prefix; + + dialog->priv->valid_main_ip = ni_ip_add_dialog_get_address (dialog, &addr, &prefix); + ni_ip_add_dialog_update_response (dialog); +} + +static void ni_ip_add_dialog_validate_p2p_ip (GtkEditable *editable, gpointer data) { + NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); + const gchar *texto; + int prefix; + + texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p)); + + dialog->priv->valid_p2p_ip = FALSE; + if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) { + dialog->priv->valid_p2p_ip = ip_valid_ipv4 (texto); + if (dialog->priv->valid_p2p_ip) { + ni_ip_add_dialog_update_response (dialog); + return; + } + } + + if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) { + dialog->priv->valid_p2p_ip = ip_valid_ipv6 (texto); + } + + ni_ip_add_dialog_update_response (dialog); +} + +void ni_ip_add_dialog_toggle_p2p_cb (GtkWidget *widget, gpointer data) { + NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (data); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) { + gtk_widget_set_sensitive (dialog->priv->entry_p2p, TRUE); + } else { + gtk_widget_set_sensitive (dialog->priv->entry_p2p, FALSE); + } + ni_ip_add_dialog_update_response (dialog); +} + +static void ni_ip_add_dialog_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { + NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (object); + g_return_if_fail (NI_IS_IP_ADD_DIALOG (object)); + + switch (prop_id) { + case PROP_IP_FAMILY: + dialog->priv->family = g_value_get_uint (value); + if (dialog->priv->family == AF_UNSPEC) { + gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "192.0.2.1/24 or 2001:db8::1/64"); + } else if (dialog->priv->family == AF_INET) { + gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "192.0.2.1/24"); + } else if (dialog->priv->family == AF_INET6) { + gtk_entry_set_placeholder_text (GTK_ENTRY (dialog->priv->entry), "2001:db8::1/64"); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_ip_add_dialog_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { + NIIPAddDialog *dialog = NI_IP_ADD_DIALOG (object); + g_return_if_fail (NI_IS_IP_ADD_DIALOG (object)); + + switch (prop_id) { + case PROP_IP_FAMILY: + g_value_set_uint (value, dialog->priv->family); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void ni_ip_add_dialog_class_init (NIIPAddDialogClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWindowClass *window_class = GTK_WINDOW_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass); + + object_class->set_property = ni_ip_add_dialog_set_property; + object_class->get_property = ni_ip_add_dialog_get_property; + + obj_properties[PROP_IP_FAMILY] = g_param_spec_uint ( + "family", + "Network family", + "Network family to allow", + 0, 10, AF_UNSPEC, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties); +} + +static void ni_ip_add_dialog_init (NIIPAddDialog *dialog) { + NIIPAddDialogPrivate *priv = ni_ip_add_dialog_get_instance_private (dialog); + GtkWidget *image; + GtkWidget *vbox, *expander; + GtkWidget *container, *label, *hbox; + + dialog->priv = priv; + + priv->family = AF_UNSPEC; + + gtk_window_set_title (GTK_WINDOW (dialog), "Add new IP"); + + gtk_dialog_add_button (GTK_DIALOG (dialog), "Cancelar", GTK_RESPONSE_CANCEL); + + priv->button_add = gtk_dialog_add_button (GTK_DIALOG (dialog), "Agregar", GTK_RESPONSE_OK); + image = gtk_image_new_from_icon_name ("list-add", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_button_set_image (GTK_BUTTON (priv->button_add), image); + gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_OK, FALSE); + + container = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + gtk_box_pack_start (GTK_BOX (container), vbox, TRUE, TRUE, 0); + + label = gtk_label_new ("Ingrese los detalles sobre la dirección IP:"); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 5); + + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ("IP:"); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + + priv->entry = gtk_entry_new (); + gtk_entry_set_placeholder_text (GTK_ENTRY (priv->entry), "192.0.2.1/24 or 2001:db8::1/64"); + g_signal_connect (priv->entry, "changed", G_CALLBACK (ni_ip_add_dialog_validate_main_ip), dialog); + gtk_box_pack_start (GTK_BOX (hbox), priv->entry, TRUE, TRUE, 0); + + expander = gtk_expander_new_with_mnemonic ("_Opciones avanzadas"); + gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0); + + vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 3); + gtk_container_add (GTK_CONTAINER (expander), vbox); + + /* La posible dirección peer-to-peer */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 3); + + priv->check_p2p = gtk_check_button_new_with_label ("Point-to-point address:"); + g_signal_connect (priv->check_p2p, "toggled", G_CALLBACK (ni_ip_add_dialog_toggle_p2p_cb), dialog); + gtk_box_pack_start (GTK_BOX (hbox), priv->check_p2p, FALSE, FALSE, 0); + + priv->entry_p2p = gtk_entry_new (); + g_signal_connect (priv->entry_p2p, "changed", G_CALLBACK (ni_ip_add_dialog_validate_p2p_ip), dialog); + gtk_box_pack_start (GTK_BOX (hbox), priv->entry_p2p, TRUE, TRUE, 0); + gtk_widget_set_sensitive (priv->entry_p2p, FALSE); + + priv->check_noprefix = gtk_check_button_new_with_label ("No prefix route"); + gtk_box_pack_start (GTK_BOX (vbox), priv->check_noprefix, FALSE, FALSE, 3); + + dialog->priv->valid_main_ip = FALSE; + dialog->priv->valid_p2p_ip = FALSE; + + gtk_widget_show_all (container); +} + +gboolean ni_ip_add_dialog_get_address (NIIPAddDialog *dialog, struct_addr *addr, int *prefix) { + const gchar *texto; + gchar *rest, ip[128], mask[32]; + int lprefix; + gboolean valid; + + texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry)); + + split_ip_mask (texto, ip, sizeof (ip), mask, sizeof (mask)); + + if (mask[0] != 0) { + lprefix = g_ascii_strtoll (mask, &rest, 10); + + if (rest[0] != 0) { + return FALSE; + } + } + + if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) { + valid = ip_valid_ipv4 (ip); + if (valid == FALSE || + (mask[0] != 0 && (lprefix <= 0 || lprefix > 32))) { + if (dialog->priv->family == AF_INET) { + return FALSE; + } + } else { + *prefix = 32; + if (mask[0] != 0) { + *prefix = lprefix; + } + inet_pton (AF_INET, ip, addr); + + return TRUE; + } + } + + if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) { + valid = ip_valid_ipv6 (ip); + if (valid == FALSE || (mask[0] != 0 && (lprefix <= 0 || lprefix > 128))) { + dialog->priv->valid_main_ip = FALSE; + return FALSE; + } else { + *prefix = 128; + if (mask[0] != 0) { + *prefix = lprefix; + } + inet_pton (AF_INET6, ip, addr); + } + } + + return FALSE; +} + +gboolean ni_ip_add_dialog_has_p2p_address (NIIPAddDialog *dialog) { + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)); +} + +gboolean ni_ip_add_dialog_get_p2p_address (NIIPAddDialog *dialog, struct_addr *addr) { + gboolean valid; + const gchar *texto; + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_p2p)) == FALSE) { + return FALSE; + } + + texto = gtk_entry_get_text (GTK_ENTRY (dialog->priv->entry_p2p)); + + if (dialog->priv->family == AF_INET || dialog->priv->family == AF_UNSPEC) { + valid = ip_valid_ipv4 (texto); + + if (valid) { + inet_pton (AF_INET, texto, addr); + + return TRUE; + } + } + + if (dialog->priv->family == AF_INET6 || dialog->priv->family == AF_UNSPEC) { + valid = ip_valid_ipv6 (texto); + + if (valid) { + inet_pton (AF_INET6, texto, addr); + + return TRUE; + } + } + + return FALSE; +} + +gboolean ni_ip_add_dialog_get_noprefix (NIIPAddDialog *dialog) { + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->check_noprefix)); +} + +GtkWidget* ni_ip_add_dialog_new (int family) { + NIIPAddDialog *dialog; + + dialog = g_object_new (NI_TYPE_IP_ADD_DIALOG, "family", family, NULL); + + return GTK_WIDGET (dialog); +} + diff --git a/client-gtk/ni-ip-add-dialog.h b/client-gtk/ni-ip-add-dialog.h new file mode 100644 index 0000000..1e2808e --- /dev/null +++ b/client-gtk/ni-ip-add-dialog.h @@ -0,0 +1,72 @@ +/* + * ni-add-ip-dialog.h + * This file is part of Network Inador + * + * Copyright (C) 2021 - Gatuno + * + * 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 + */ + +#ifndef __NI_IP_ADD_DIALOG_H__ +#define __NI_IP_ADD_DIALOG_H__ + +#include + +#include "ni-ip.h" + +G_BEGIN_DECLS + +typedef struct _NIIPAddDialogClass NIIPAddDialogClass; +typedef struct _NIIPAddDialog NIIPAddDialog; +typedef struct _NIIPAddDialogPrivate NIIPAddDialogPrivate; + +/* + * Type declaration. + */ +#define NI_TYPE_IP_ADD_DIALOG (ni_ip_add_dialog_get_type ()) +#define NI_IP_ADD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NI_TYPE_IP_ADD_DIALOG, NIIPAddDialog)) +#define NI_IP_ADD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), NI_TYPE_IP_ADD_DIALOG, NIIPAddDialogClass)) +#define NI_IS_IP_ADD_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NI_TYPE_IP_ADD_DIALOG)) +#define NI_IS_IP_ADD_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NI_TYPE_IP_ADD_DIALOG)) +#define NI_IP_ADD_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), NI_TYPE_IP_ADD_DIALOG, NIIPAddDialogClass)) + +GType ni_ip_add_dialog_get_type (void); + +struct _NIIPAddDialogClass { + GtkDialogClass parent_class; + +}; + +struct _NIIPAddDialog { + GtkDialog parent_instance; + + NIIPAddDialogPrivate *priv; +}; + +/* + * Method definitions. + */ +GtkWidget* ni_ip_add_dialog_new (int family); + +gboolean ni_ip_add_dialog_get_address (NIIPAddDialog *dialog, struct_addr *addr, int *prefix); +gboolean ni_ip_add_dialog_has_p2p_address (NIIPAddDialog *dialog); +gboolean ni_ip_add_dialog_get_p2p_address (NIIPAddDialog *dialog, struct_addr *addr); +gboolean ni_ip_add_dialog_get_noprefix (NIIPAddDialog *dialog); + +G_END_DECLS + +#endif /* __NI_IP_ADD_DIALOG_H__ */ + diff --git a/client-gtk/ni-ip.c b/client-gtk/ni-ip.c index 2b91e9f..4da8177 100644 --- a/client-gtk/ni-ip.c +++ b/client-gtk/ni-ip.c @@ -57,29 +57,6 @@ 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)); @@ -87,7 +64,6 @@ static void ni_ip_set_property (GObject *object, guint prop_id, const GValue *va 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); @@ -112,8 +88,6 @@ static void ni_ip_class_init (NIIPClass *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", diff --git a/client-gtk/ni-window-interface.c b/client-gtk/ni-window-interface.c index 6812936..ba8d9f1 100644 --- a/client-gtk/ni-window-interface.c +++ b/client-gtk/ni-window-interface.c @@ -29,30 +29,26 @@ #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 -}; +#include "ni-ip-add-dialog.h" struct _NIWindowInterfacePrivate { NIInterface *ni_interface; GtkWidget *vbox, *notebook; - GtkWidget *vbox_ipv4, *vbox_ipv6; + GtkWidget *vbox_ipv4, *vbox_ipv6, *vbox_info; + GtkWidget *info_name, *info_updown; + GtkWidget *button_name_apply, *button_name_revert; + GtkWidget *button_up, *button_down; GtkListStore *ipv4_store, *ipv6_store; + GtkWidget *del_ipv4_button, *del_ipv6_button; GtkWidget *tree_ipv4, *tree_ipv6; }; @@ -70,6 +66,10 @@ enum { NUM_IP_STORE_COLS }; +static void ni_window_interface_addr_added_cb (NIWindowInterface *window_iface, NIIP *ni_ip); +void ni_window_interface_update_state_from_flags (NIWindowInterface *window_iface); +static void ni_window_interface_name_cancel_cb (GtkWidget *widget, gpointer data); + G_DEFINE_TYPE_WITH_PRIVATE (NIWindowInterface, ni_window_interface, GTK_TYPE_WINDOW) static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; @@ -77,7 +77,7 @@ 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); + GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); NIInterface *ni_interface; obj = parent_class->constructor (type, n_construct_properties, construct_properties); @@ -106,7 +106,167 @@ static GObject *ni_interface_constructor (GType type, guint n_construct_properti } #endif -static void ni_window_interface_ip_addr_add (NIWindowInterface *window_iface, NIIP *ni_ip) { +static gboolean ni_window_interface_delete_event (GtkWidget *widget, GdkEventAny *event) { + /* Restaurar la caja original del nombre de la interfaz, si está cambiada */ + ni_window_interface_name_cancel_cb (NULL, widget); + + return gtk_widget_hide_on_delete (widget); +} + +static void has_ip_selected_v4_cb (GtkTreeSelection *selection, gpointer user_data) { + NIWindowInterface *window_iface = (NIWindowInterface *) user_data; + + if (gtk_tree_selection_count_selected_rows (selection) > 0) { + gtk_widget_set_sensitive (window_iface->priv->del_ipv4_button, TRUE); + } else { + gtk_widget_set_sensitive (window_iface->priv->del_ipv4_button, FALSE); + } +} + +static void has_ip_selected_v6_cb (GtkTreeSelection *selection, gpointer user_data) { + NIWindowInterface *window_iface = (NIWindowInterface *) user_data; + + if (gtk_tree_selection_count_selected_rows (selection) > 0) { + gtk_widget_set_sensitive (window_iface->priv->del_ipv6_button, TRUE); + } else { + gtk_widget_set_sensitive (window_iface->priv->del_ipv6_button, FALSE); + } +} + +static void ni_window_interface_addr_button_add_cb (GtkWidget *widget, int family, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + GtkWidget *dialog; + gint response; + NIClient *ni_client; + struct_addr addr, p2p_addr; + int prefix; + gboolean has_p2p; + uint32_t flags = 0; + + dialog = ni_ip_add_dialog_new (family); + + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window_iface)); + + 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_iface->priv->ni_interface); + + 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) { + + 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); + } + + gtk_widget_destroy (dialog); +} + +static void ni_window_interface_addr_button_del_cb (GtkWidget *widget, int family, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + GtkTreeIter iter; + GtkTreeModel *model; + GtkTreeSelection *selection; + NIIP *ni_ip; + + if (family == AF_INET) { + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window_iface->priv->tree_ipv4)); + } else if (family == AF_INET6) { + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window_iface->priv->tree_ipv6)); + } + + gtk_tree_selection_get_selected (selection, &model, &iter); + + gtk_tree_model_get (model, &iter, IP_STORE_COL_OBJECT, &ni_ip, -1); + + ni_client_ask_ip_delete (ni_interface_get_client (window_iface->priv->ni_interface), window_iface->priv->ni_interface, ni_ip); +} + +static void ni_window_interface_addr_v4_button_add_cb (GtkWidget *widget, gpointer data) { + ni_window_interface_addr_button_add_cb (widget, AF_INET, data); +} + +static void ni_window_interface_addr_v6_button_add_cb (GtkWidget *widget, gpointer data) { + ni_window_interface_addr_button_add_cb (widget, AF_INET6, data); +} + +static void ni_window_interface_addr_v4_button_del_cb (GtkWidget *widget, gpointer data) { + ni_window_interface_addr_button_del_cb (widget, AF_INET, data); +} + +static void ni_window_interface_addr_v6_button_del_cb (GtkWidget *widget, gpointer data) { + ni_window_interface_addr_button_del_cb (widget, AF_INET6, data); +} + +/* Evento cuando cambian el nombre de la interfaz en el entry */ +static void ni_window_interface_name_edit_cb (GtkEditable *editable, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + const gchar *original_name = ni_interface_get_name (window_iface->priv->ni_interface); + const gchar *current_name = gtk_entry_get_text (GTK_ENTRY (window_iface->priv->info_name)); + + if (current_name[0] == 0) { + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, TRUE); + } else if (strcmp (original_name, current_name) == 0) { + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); + } else { + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, TRUE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, TRUE); + } +} + +static void ni_window_interface_name_cancel_cb (GtkWidget *widget, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); + + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); +} + +static void ni_window_interface_name_apply_cb (GtkWidget *widget, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + const gchar *new_name; + + if (gtk_widget_get_sensitive (window_iface->priv->button_name_apply) == FALSE) { + return; + } + new_name = gtk_entry_get_text (GTK_ENTRY (window_iface->priv->info_name)); + + ni_interface_set_name (window_iface->priv->ni_interface, new_name); + + /* TODO: Activar el ícono de "cargando" en el entry + gtk_entry_set_icon_from_gicon (GTK_ENTRY (window_iface->priv->info_name), GTK_ENTRY_ICON_SECONDARY, */ + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); +} + +static void ni_window_interface_down_cb (GtkWidget *widget, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + + ni_interface_set_down (window_iface->priv->ni_interface); +} + +static void ni_window_interface_up_cb (GtkWidget *widget, gpointer data) { + NIWindowInterface *window_iface = (NIWindowInterface *) data; + + ni_interface_set_up (window_iface->priv->ni_interface); +} + +/* Eventos que vienen del network-inador */ +static void ni_window_interface_addr_added_cb (NIWindowInterface *window_iface, NIIP *ni_ip) { GtkTreeIter iter; char buffer[256], ip[128], local[128]; guint prefix, family, family_size; @@ -139,12 +299,12 @@ static void ni_window_interface_ip_addr_add (NIWindowInterface *window_iface, NI } } -static void ni_window_interface_ip_add_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { +static void ni_window_interface_new_ip_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); + ni_window_interface_addr_added_cb (window_iface, ni_ip); } -static void ni_window_interface_ip_del_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { +static void ni_window_interface_delete_ip_cb (NIInterface *ni_interface, NIIP *ni_ip, gpointer data) { GtkTreeIter iter; NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); gboolean has; @@ -181,15 +341,47 @@ static void ni_window_interface_changed_name_cb (GObject *object, GParamSpec *sp /* 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); + + /* Cambiar la label que corresponde al nombre */ + gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); + g_free (name); } +static void ni_window_interface_changed_flags_cb (GObject *object, GParamSpec *sp, gpointer data) { + NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (data); + + ni_window_interface_update_state_from_flags (window_iface); +} + +void ni_window_interface_update_state_from_flags (NIWindowInterface *window_iface) { + guint flags; + + /* Recuperar las flags */ + flags = ni_interface_get_flags (window_iface->priv->ni_interface); + + if (flags & IFF_UP) { + gtk_widget_set_sensitive (window_iface->priv->info_name, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_apply, FALSE); + gtk_widget_set_sensitive (window_iface->priv->button_name_revert, FALSE); + gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); + gtk_label_set_text (GTK_LABEL (window_iface->priv->info_updown), "UP"); + } else { + gtk_widget_set_sensitive (window_iface->priv->info_name, TRUE); + gtk_label_set_text (GTK_LABEL (window_iface->priv->info_updown), "DOWN"); + } +} + +/* Construcción del objeto */ static void ni_window_interface_constructed (GObject *obj) { - GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (obj); const GList *ip_list, *g; NIIP *ni_ip; gchar *name; + guint flags; parent_class->constructed (obj); @@ -206,29 +398,36 @@ static void ni_window_interface_constructed (GObject *obj) { for (g = ip_list; g != NULL; g = g->next) { ni_ip = (NIIP *) g->data; - ni_window_interface_ip_addr_add (window_iface, ni_ip); + ni_window_interface_addr_added_cb (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, "new-ip", G_CALLBACK (ni_window_interface_new_ip_cb), window_iface); + g_signal_connect (window_iface->priv->ni_interface, "delete-ip", G_CALLBACK (ni_window_interface_delete_ip_cb), window_iface); g_signal_connect (window_iface->priv->ni_interface, "notify::name", G_CALLBACK (ni_window_interface_changed_name_cb), window_iface); + g_signal_connect (window_iface->priv->ni_interface, "notify::flags", G_CALLBACK (ni_window_interface_changed_flags_cb), window_iface); + + gtk_entry_set_text (GTK_ENTRY (window_iface->priv->info_name), ni_interface_get_name (window_iface->priv->ni_interface)); + + ni_window_interface_update_state_from_flags (window_iface); } static void ni_window_interface_dispose (GObject *obj) { NIWindowInterface *window_iface; - GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); window_iface = NI_WINDOW_INTERFACE (obj); g_object_unref (window_iface->priv->ni_interface); + window_iface->priv->ni_interface = NULL; parent_class->dispose (obj); } +#if 0 static void ni_window_interface_finalize (GObject *obj) { NIWindowInterface *window_iface; - GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT); + GObjectClass *parent_class = G_OBJECT_CLASS (g_type_class_peek (GTK_TYPE_WINDOW)); window_iface = NI_WINDOW_INTERFACE (obj); @@ -236,6 +435,7 @@ static void ni_window_interface_finalize (GObject *obj) { parent_class->finalize (obj); } +#endif static void ni_window_interface_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { NIWindowInterface *window_iface = NI_WINDOW_INTERFACE (object); @@ -267,12 +467,14 @@ static void ni_window_interface_get_property (GObject *object, guint prop_id, GV static void ni_window_interface_class_init (NIWindowInterfaceClass *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_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; + + widget_class->delete_event = ni_window_interface_delete_event; obj_properties[PROP_NI_INTERFACE] = g_param_spec_object ( "ni-interface", @@ -313,12 +515,13 @@ static void ni_window_interface_init (NIWindowInterface *window_iface) { GtkWindow *window = GTK_WINDOW (window_iface); GtkWidget *hbox, *label, *button, *image; GtkWidget *vbox, *scrolled, *vbox2; + GtkTreeSelection *selection; + GtkSizeGroup *size_l; /* 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); @@ -326,6 +529,60 @@ static void ni_window_interface_init (NIWindowInterface *window_iface) { priv->notebook = gtk_notebook_new (); gtk_box_pack_start (GTK_BOX (priv->vbox), priv->notebook, TRUE, TRUE, 0); + /* Página de la información general de la interfaz */ + priv->vbox_info = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); + label = gtk_label_new ("Info"); + gtk_notebook_append_page (GTK_NOTEBOOK (priv->notebook), priv->vbox_info, label); + gtk_container_set_border_width (GTK_CONTAINER (priv->vbox_info), 5); + + size_l = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + + /* Poner las labels de información de la propia interfaz */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (priv->vbox_info), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ("Interfaz name:"); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_size_group_add_widget (size_l, label); + + priv->button_name_revert = gtk_button_new_from_icon_name ("view-refresh", GTK_ICON_SIZE_BUTTON); + gtk_widget_set_sensitive (priv->button_name_revert, FALSE); + g_signal_connect (priv->button_name_revert, "clicked", G_CALLBACK (ni_window_interface_name_cancel_cb), window_iface); + gtk_box_pack_end (GTK_BOX (hbox), priv->button_name_revert, FALSE, FALSE, 0); + + priv->button_name_apply = gtk_button_new_from_icon_name ("document-save", GTK_ICON_SIZE_BUTTON); + gtk_widget_set_sensitive (priv->button_name_apply, FALSE); + g_signal_connect (priv->button_name_apply, "clicked", G_CALLBACK (ni_window_interface_name_apply_cb), window_iface); + gtk_box_pack_end (GTK_BOX (hbox), priv->button_name_apply, FALSE, FALSE, 0); + + priv->info_name = gtk_entry_new (); + gtk_entry_set_text (GTK_ENTRY (priv->info_name), ""); + gtk_widget_set_sensitive (priv->info_name, FALSE); + g_signal_connect (priv->info_name, "changed", G_CALLBACK (ni_window_interface_name_edit_cb), window_iface); + g_signal_connect (priv->info_name, "activate", G_CALLBACK (ni_window_interface_name_apply_cb), window_iface); + gtk_box_pack_end (GTK_BOX (hbox), priv->info_name, TRUE, TRUE, 0); + + /* Las banderas de la intefaz */ + hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5); + gtk_box_pack_start (GTK_BOX (priv->vbox_info), hbox, FALSE, FALSE, 0); + + label = gtk_label_new ("Estado:"); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); + gtk_size_group_add_widget (size_l, label); + + priv->button_down = gtk_button_new_from_icon_name ("go-down", GTK_ICON_SIZE_BUTTON); + g_signal_connect (priv->button_down, "clicked", G_CALLBACK (ni_window_interface_down_cb), window_iface); + gtk_box_pack_end (GTK_BOX (hbox), priv->button_down, FALSE, FALSE, 0); + + priv->button_up = gtk_button_new_from_icon_name ("go-up", GTK_ICON_SIZE_BUTTON); + g_signal_connect (priv->button_up, "clicked", G_CALLBACK (ni_window_interface_up_cb), window_iface); + gtk_box_pack_end (GTK_BOX (hbox), priv->button_up, FALSE, FALSE, 0); + + priv->info_updown = gtk_label_new (""); + gtk_box_pack_end (GTK_BOX (hbox), priv->info_updown, FALSE, FALSE, 0); + /* Página de IPv4 */ priv->vbox_ipv4 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); label = gtk_label_new ("IPv4"); @@ -354,10 +611,16 @@ static void ni_window_interface_init (NIWindowInterface *window_iface) { 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_interface_addr_v4_button_add_cb), window_iface); - 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); + priv->del_ipv4_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), priv->del_ipv4_button, FALSE, FALSE, 0); + g_signal_connect (priv->del_ipv4_button, "clicked", G_CALLBACK (ni_window_interface_addr_v4_button_del_cb), window_iface); + gtk_widget_set_sensitive (priv->del_ipv4_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_ipv4)); + g_signal_connect (selection, "changed", G_CALLBACK (has_ip_selected_v4_cb), window_iface); /* Página de IPv6 */ priv->vbox_ipv6 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5); @@ -387,9 +650,16 @@ static void ni_window_interface_init (NIWindowInterface *window_iface) { 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_interface_addr_v6_button_add_cb), window_iface); - 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); + priv->del_ipv6_button = gtk_button_new_from_icon_name ("list-remove", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start (GTK_BOX (vbox2), priv->del_ipv6_button, FALSE, FALSE, 0); + g_signal_connect (priv->del_ipv6_button, "clicked", G_CALLBACK (ni_window_interface_addr_v6_button_del_cb), window_iface); + gtk_widget_set_sensitive (priv->del_ipv6_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_ipv6)); + 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); diff --git a/src/interfaces.c b/src/interfaces.c index 94b89c0..f3c603d 100644 --- a/src/interfaces.c +++ b/src/interfaces.c @@ -213,16 +213,13 @@ static int _interfaces_receive_message_interface (struct nl_msg *msg, void *arg, u32data = nla_get_u32 (attr); iface->vlan_parent = u32data; printf ("Interface %d: tiene como padre a %d\n", iface->index, iface->vlan_parent); - case IFA_FLAGS: - printf ("IFA_FLAGS: size %i\n", nla_len (attr)); - new_flags = nla_get_u32 (attr); - break; - default: - printf ("RTA Attribute \"%hu\" no procesado\n", nla_type (attr)); + /*default: + printf ("RTA Attribute \"%hu\" no procesado\n", nla_type (attr));*/ } } if (iface->flags != new_flags) { + iface->flags = new_flags; was_update = 1; } diff --git a/src/ip-address.c b/src/ip-address.c index c0ce5e9..ad4be95 100644 --- a/src/ip-address.c +++ b/src/ip-address.c @@ -37,7 +37,7 @@ #include "manager.h" -static IPAddr *_ip_address_search_addr (Interface *iface, sa_family_t family, void *addr, uint32_t prefix, void *local_addr) { +IPAddr *_ip_address_search_addr (Interface *iface, sa_family_t family, void *addr, uint32_t prefix, void *local_addr) { GList *g; IPAddr *ip_addr; int family_size = 0; @@ -76,13 +76,15 @@ int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { struct ifaddrmsg *addr_msg; int remaining; struct nlattr *attr; + struct ifa_cacheinfo cacheinfo; struct_addr addr; struct_addr local_addr; struct_addr brd_addr; + uint32_t new_flags; + /* TODO: Decidir si guardamos también la IP anycast */ - uint32_t flags; int family; int has_brd = 0, has_local = 0; int family_size = 0; @@ -103,7 +105,7 @@ int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { printf ("-> New addr\n"); - flags = addr_msg->ifa_flags; + new_flags = addr_msg->ifa_flags; family = addr_msg->ifa_family; if (family == AF_INET) { @@ -116,7 +118,7 @@ int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { printf ("-> new addr type attr: %i\n", nla_type (attr)); switch (nla_type (attr)) { case IFA_FLAGS: - memcpy (&flags, nla_data (attr), nla_len (attr)); + new_flags = nla_get_u32 (attr); break; case IFA_ADDRESS: memcpy (&addr, nla_data (attr), nla_len (attr)); @@ -129,6 +131,10 @@ int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { memcpy (&brd_addr, nla_data (attr), nla_len (attr)); has_brd = 1; break; + case IFA_CACHEINFO: + memcpy (&cacheinfo, nla_data (attr), nla_len (attr)); + printf ("Cache info timestamp: preferred: %u, valid: %u, created: %u, updated: %u\n", cacheinfo.ifa_prefered, cacheinfo.ifa_valid, cacheinfo.cstamp, cacheinfo.tstamp); + break; } } @@ -150,7 +156,7 @@ int ip_address_receive_message_newaddr (struct nl_msg *msg, void *arg) { was_new = 1; } - ip_addr->flags = flags; + ip_addr->flags = new_flags; ip_addr->scope = addr_msg->ifa_scope; /* Actualizar la local o la broadcast */ @@ -325,9 +331,11 @@ int ip_address_add_ip (NetworkInadorHandle *handle, int index, IPAddr *ip_addr) ret = nla_put (msg, IFA_ADDRESS, family_size, &ip_addr->addr); if (ip_addr->has_local) { ret |= nla_put (msg, IFA_LOCAL, family_size, &ip_addr->local_addr); + } else { + ret |= nla_put (msg, IFA_LOCAL, family_size, &ip_addr->addr); } if (ip_addr->has_brd) { - ret |= nla_put (msg, IFA_LOCAL, family_size, &ip_addr->brd_addr); + ret |= nla_put (msg, IFA_BROADCAST, family_size, &ip_addr->brd_addr); } if (ret != 0) { diff --git a/src/ip-address.h b/src/ip-address.h index 1a9fc31..931bb2c 100644 --- a/src/ip-address.h +++ b/src/ip-address.h @@ -35,4 +35,6 @@ void ip_address_init (NetworkInadorHandle *handle); int ip_address_add_ip (NetworkInadorHandle *handle, int index, IPAddr *addr); int ip_address_del_ip (NetworkInadorHandle *handle, int index, IPAddr *addr); +IPAddr *_ip_address_search_addr (Interface *iface, sa_family_t family, void *addr, uint32_t prefix, void *local_addr); + #endif diff --git a/src/manager.c b/src/manager.c index d0e861e..4c49f1f 100644 --- a/src/manager.c +++ b/src/manager.c @@ -324,6 +324,7 @@ void _manager_execute_iface_change_name (ManagerClientInfo *manager_client, unsi _manager_send_error (manager_client, NET_INADOR_ERROR_BAD_STRING, NET_INADOR_COMMAND_IFACE_CHANGE_NAME); return; } + name[name_len] = 0; ret = interfaces_change_name (manager_client->manager->handle, iface->index, name); @@ -378,10 +379,8 @@ void _manager_execute_clear_ips (ManagerClientInfo *manager_client, unsigned cha void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { Interface *iface; IPAddr ip_addr; - GList *g; int ret; int family_size, wanted_size, family; - int has_local, has_brd; if (buffer_len < 14) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_ADD_IP); @@ -408,8 +407,8 @@ void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char * return; } - has_local = buffer[8] & 0x01; - has_brd = (buffer[8] & 0x02) >> 1; + ip_addr.has_local = buffer[8] & 0x01; + ip_addr.has_brd = (buffer[8] & 0x02) >> 1; if (ip_addr.family == AF_INET) { family_size = sizeof (struct in_addr); @@ -417,7 +416,7 @@ void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char * family_size = sizeof (struct in6_addr); } /* Ya puedo revisar el resto de la longitud */ - wanted_size = 14 + family_size + (family_size * has_local) + (family_size * has_brd); + wanted_size = 14 + family_size + (family_size * ip_addr.has_local) + (family_size * ip_addr.has_brd); if (buffer_len < wanted_size) { _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_ADD_IP); return; @@ -429,14 +428,18 @@ void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char * memcpy (&ip_addr.addr, &buffer[14], family_size); wanted_size = 14 + family_size; - if (has_local) { + if (ip_addr.has_local) { memcpy (&ip_addr.local_addr, &buffer[wanted_size], family_size); wanted_size += family_size; + } else { + memcpy (&ip_addr.local_addr, &ip_addr.addr, family_size); } - if (has_brd) { + if (ip_addr.has_brd) { memcpy (&ip_addr.brd_addr, &buffer[wanted_size], family_size); wanted_size += family_size; + } else { + memset (&ip_addr.brd_addr, 0, sizeof (ip_addr.brd_addr)); } ret = ip_address_add_ip (manager_client->manager->handle, iface->index, &ip_addr); @@ -449,6 +452,77 @@ void _manager_execute_add_ip (ManagerClientInfo *manager_client, unsigned char * } } +void _manager_execute_delete_ip (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { + Interface *iface; + IPAddr *ip_addr; + struct_addr addr, local_addr; + int has_local; + int ret; + int family_size, wanted_size, family; + int prefix; + + if (buffer_len < 9) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_REMOVE_IP); + return; + } + + family = buffer[6]; + + if (family != AF_INET && family != AF_INET6) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_FAMILY, NET_INADOR_COMMAND_REMOVE_IP); + + return; + } + + iface = _manager_fetch_interface (manager_client, &buffer[2], NET_INADOR_COMMAND_REMOVE_IP); + if (iface == NULL) return; + + prefix = buffer[7]; + if (family == AF_INET && (prefix > 32 || prefix < 1)) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_REMOVE_IP); + return; + } else if (family == AF_INET6 && (prefix > 128 || prefix < 1)) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INVALID_VALUE, NET_INADOR_COMMAND_REMOVE_IP); + return; + } + + has_local = buffer[8] & 0x01; + + if (family == AF_INET) { + family_size = sizeof (struct in_addr); + } else if (family == AF_INET6) { + family_size = sizeof (struct in6_addr); + } + /* Ya puedo revisar el resto de la longitud */ + wanted_size = 9 + family_size + (family_size * has_local); + if (buffer_len < wanted_size) { + _manager_send_error (manager_client, NET_INADOR_ERROR_INCOMPLETE_REQUEST, NET_INADOR_COMMAND_REMOVE_IP); + return; + } + + memcpy (&addr, &buffer[9], family_size); + + if (has_local) { + memcpy (&local_addr, &buffer[9 + family_size], family_size); + } + + ip_addr = _ip_address_search_addr (iface, family, &addr, prefix, (has_local ? &local_addr : NULL)); + + if (ip_addr == NULL) { + _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_REMOVE_IP); + return; + } + + ret = ip_address_del_ip (manager_client->manager->handle, iface->index, ip_addr); + + if (ret == 0) { + /* OK */ + _manager_send_executed (manager_client); + } else { + _manager_send_error (manager_client, NET_INADOR_ERROR_NOT_EXECUTED, NET_INADOR_COMMAND_REMOVE_IP); + } +} + static void _manager_handle_set_event_mask (ManagerClientInfo *manager_client, unsigned char *buffer, int buffer_len) { uint32_t events; @@ -531,9 +605,9 @@ static gboolean _manager_client_data (GIOChannel *source, GIOCondition condition case NET_INADOR_COMMAND_ADD_IP: _manager_execute_add_ip (manager_client, buffer, bytes); break; - /*case NET_INADOR_COMMAND_REMOVE_IP: - - break;*/ + case NET_INADOR_COMMAND_REMOVE_IP: + _manager_execute_delete_ip (manager_client, buffer, bytes); + break; case NET_INADOR_COMMAND_SET_EVENT_MASK: _manager_handle_set_event_mask (manager_client, buffer, bytes); break;