NetworkInador/client-gtk/ni-interface.c

652 lines
18 KiB
C

/*
* 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#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;
}