680 lines
18 KiB
C
680 lines
18 KiB
C
/*
|
|
* ni-client.c
|
|
* This file is part of NetworkInador
|
|
*
|
|
* Copyright (C) 2021 - Gatuno
|
|
*
|
|
* NetworkInador is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* NetworkInador is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with NetworkInador; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include <glib.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
|
|
#include "ni-client.h"
|
|
#include "ni-interface.h"
|
|
#include "ni-marshal.h"
|
|
#include "../src/network-inador-manager.h"
|
|
|
|
#define COMMAND_SOCKET_PATH "/tmp/network-inador.socket"
|
|
|
|
/* Privados desde el ni-interface */
|
|
void ni_interface_consume_values (NIInterface *ni_interface, char *name, gint arp_type, guint master_index, guint mtu, guint flags);
|
|
|
|
/* Privados locales */
|
|
static void ni_client_dispose (GObject *obj);
|
|
static void ni_client_finalize (GObject *obj);
|
|
|
|
struct _NIClientPrivate {
|
|
int client_socket;
|
|
|
|
gchar *socket_path;
|
|
GHashTable *interfaces;
|
|
guint source;
|
|
guint events;
|
|
};
|
|
|
|
enum {
|
|
PROP_SOCKET_PATH = 1,
|
|
|
|
N_PROPERTIES
|
|
};
|
|
|
|
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
|
|
|
enum {
|
|
DATA_READ,
|
|
|
|
NEW_INTERFACE,
|
|
|
|
DELETE_INTERFACE,
|
|
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
static guint signals[LAST_SIGNAL];
|
|
|
|
G_DEFINE_TYPE_WITH_PRIVATE (NIClient, ni_client, G_TYPE_OBJECT)
|
|
|
|
static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size);
|
|
|
|
static void ni_client_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
|
|
NIClient *ni_client = NI_CLIENT (object);
|
|
g_return_if_fail (NI_IS_CLIENT (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_SOCKET_PATH:
|
|
if (ni_client->priv->socket_path != NULL) {
|
|
g_free (ni_client->priv->socket_path);
|
|
}
|
|
ni_client->priv->socket_path = g_value_dup_string (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_client_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
|
|
NIClient *ni_client = NI_CLIENT (object);
|
|
g_return_if_fail (NI_IS_CLIENT (object));
|
|
|
|
switch (prop_id) {
|
|
case PROP_SOCKET_PATH:
|
|
g_value_set_string (value, ni_client->priv->socket_path);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
}
|
|
}
|
|
|
|
static void ni_client_class_init (NIClientClass *klass) {
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->set_property = ni_client_set_property;
|
|
object_class->get_property = ni_client_get_property;
|
|
object_class->dispose = ni_client_dispose;
|
|
object_class->finalize = ni_client_finalize;
|
|
|
|
obj_properties[PROP_SOCKET_PATH] = g_param_spec_string (
|
|
"socket-path",
|
|
"Socket Path",
|
|
"The path of the unix socket.",
|
|
COMMAND_SOCKET_PATH,
|
|
G_PARAM_CONSTRUCT | G_PARAM_READWRITE);
|
|
|
|
g_object_class_install_properties (object_class, N_PROPERTIES, obj_properties);
|
|
|
|
signals[DATA_READ] = g_signal_new ("packet-read",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (NIClientClass, data_response),
|
|
g_signal_accumulator_true_handled,
|
|
NULL,
|
|
_ni_marshal_BOOLEAN__POINTER_UINT,
|
|
G_TYPE_BOOLEAN,
|
|
2,
|
|
G_TYPE_POINTER | G_SIGNAL_TYPE_STATIC_SCOPE,
|
|
G_TYPE_UINT);
|
|
|
|
signals[NEW_INTERFACE] = g_signal_new ("new-interface",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (NIClientClass, new_interface),
|
|
NULL,
|
|
NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE,
|
|
1,
|
|
NI_TYPE_INTERFACE);
|
|
|
|
signals[DELETE_INTERFACE] = g_signal_new ("delete-interface",
|
|
G_TYPE_FROM_CLASS (klass),
|
|
G_SIGNAL_RUN_LAST,
|
|
G_STRUCT_OFFSET (NIClientClass, delete_interface),
|
|
NULL,
|
|
NULL,
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
G_TYPE_NONE,
|
|
1,
|
|
NI_TYPE_INTERFACE);
|
|
|
|
klass->data_response = ni_client_data_read;
|
|
klass->new_interface = NULL;
|
|
klass->delete_interface = NULL;
|
|
}
|
|
|
|
static void ni_client_process_interface_response (NIClient *ni_client, gpointer data, guint size) {
|
|
printf ("Interface response\n");
|
|
NIInterface *ni_interface;
|
|
unsigned char *buffer = (unsigned char *) data;
|
|
|
|
uint32_t index, master_index, mtu, type;
|
|
uint16_t flags;
|
|
uint8_t bits;
|
|
guint name_size;
|
|
char iface_name[128];
|
|
|
|
memcpy (&index, &buffer[2], 4);
|
|
memcpy (&type, &buffer[6], 4);
|
|
memcpy (&master_index, &buffer[10], 4);
|
|
memcpy (&mtu, &buffer[14], 4);
|
|
memcpy (&flags, &buffer[18], 2);
|
|
bits = buffer[20];
|
|
|
|
name_size = buffer[21];
|
|
memcpy (iface_name, &buffer[22], name_size);
|
|
iface_name[name_size] = 0;
|
|
|
|
/* Insertar y crear */
|
|
ni_interface = g_object_new (NI_TYPE_INTERFACE, "ni-client", ni_client, "index", index, "wireless", (bits == 0 ? FALSE : TRUE), "type", type, "name", iface_name, "mtu", mtu, "flags", flags, "master-index", master_index, NULL);
|
|
|
|
g_hash_table_insert (ni_client->priv->interfaces, GINT_TO_POINTER(index), ni_interface);
|
|
|
|
g_signal_emit (ni_client, signals[NEW_INTERFACE], 0, ni_interface);
|
|
}
|
|
|
|
static gboolean ni_client_data_read (NIClient *ni_client, gpointer data, guint size) {
|
|
unsigned char *buffer = (unsigned char *) data;
|
|
uint32_t index;
|
|
NIInterface *ni_interface;
|
|
|
|
if (buffer[0] == NET_INADOR_TYPE_EVENT) {
|
|
switch (buffer[1]) {
|
|
case NET_INADOR_EVENT_IFACE_ADDED:
|
|
memcpy (&index, &buffer[2], 4);
|
|
|
|
/* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */
|
|
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
|
|
|
|
if (ni_interface == NULL) {
|
|
ni_client_process_interface_response (ni_client, data, size);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
break;
|
|
case NET_INADOR_EVENT_IFACE_REMOVED:
|
|
memcpy (&index, &buffer[2], 4);
|
|
|
|
/* La interfaz fué eliminada, nosotros procesamos este evento */
|
|
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
|
|
|
|
if (ni_interface == NULL) {
|
|
/* ¿Evento de una interfaz eliminada? Ignorar */
|
|
} else {
|
|
g_hash_table_remove (ni_client->priv->interfaces, GINT_TO_POINTER(index));
|
|
|
|
g_signal_emit (ni_client, signals[DELETE_INTERFACE], 0, ni_interface);
|
|
|
|
g_object_unref (ni_interface);
|
|
}
|
|
return TRUE;
|
|
break;
|
|
}
|
|
} else if (buffer[0] == NET_INADOR_TYPE_RESPONSE) {
|
|
switch (buffer[1]) {
|
|
case NET_INADOR_RESPONSE_IFACE:
|
|
memcpy (&index, &buffer[2], 4);
|
|
|
|
/* Si la interfaz no existe, proccesarla yo, para que se cree el objeto, si la interfaz ya existe, dejar pasar el mensaje */
|
|
ni_interface = (NIInterface *) g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
|
|
|
|
if (ni_interface == NULL) {
|
|
ni_client_process_interface_response (ni_client, data, size);
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Procesar los datos aquí */
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean ni_client_read_from_socket (GIOChannel *source, GIOCondition condition, gpointer data) {
|
|
NIClient *ni_client = NI_CLIENT (data);
|
|
unsigned char buffer[8192];
|
|
int res;
|
|
gboolean stop;
|
|
int g;
|
|
|
|
res = recv (ni_client->priv->client_socket, buffer, sizeof (buffer), 0);
|
|
|
|
if (res <= 0) {
|
|
/* El socket se cerró */
|
|
close (ni_client->priv->client_socket);
|
|
ni_client->priv->client_socket = -1;
|
|
|
|
/* Eliminar el source */
|
|
if (ni_client->priv->source > 0) {
|
|
g_source_remove (ni_client->priv->source);
|
|
ni_client->priv->source = 0;
|
|
}
|
|
|
|
/* TODO: Disparar aquí una señal de desconexión al network-inador */
|
|
return FALSE;
|
|
}
|
|
|
|
printf ("Data arrival: %i\n", res);
|
|
for (g = 0; g < res; g++) {
|
|
printf ("%02hhx ", buffer[g]);
|
|
}
|
|
printf ("\n");
|
|
/* Tenemos datos, hacer una validación básica */
|
|
if (buffer[0] != NET_INADOR_TYPE_RESPONSE &&
|
|
buffer[0] != NET_INADOR_TYPE_RESPONSE_ERROR &&
|
|
buffer[0] != NET_INADOR_TYPE_EVENT &&
|
|
buffer[0] != NET_INADOR_TYPE_RESPONSE_LISTING_END) {
|
|
/* Tipo de paquete inválido */
|
|
return TRUE;
|
|
}
|
|
|
|
g_signal_emit (ni_client, signals[DATA_READ], 0, (void *) buffer, res, &stop);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean ni_client_foreach_remove_every_interface (gpointer key, gpointer value, gpointer user_data) {
|
|
NIInterface *ni_interface = NI_INTERFACE (value);
|
|
|
|
g_object_unref (ni_interface);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static void ni_client_dispose (GObject *obj) {
|
|
NIClient *ni_client;
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
|
|
ni_client = NI_CLIENT (obj);
|
|
|
|
/* Recorrer todos los objetos interface para quitarles una referencia y liberarlos */
|
|
g_hash_table_foreach_remove (ni_client->priv->interfaces, ni_client_foreach_remove_every_interface, NULL);
|
|
|
|
if (ni_client->priv->source > 0) {
|
|
g_source_remove (ni_client->priv->source);
|
|
ni_client->priv->source = 0;
|
|
}
|
|
|
|
parent_class->dispose (obj);
|
|
}
|
|
|
|
static void ni_client_finalize (GObject *obj) {
|
|
NIClient *ni_client;
|
|
GObjectClass *parent_class = g_type_class_peek (G_TYPE_OBJECT);
|
|
|
|
ni_client = NI_CLIENT (obj);
|
|
|
|
g_hash_table_destroy (ni_client->priv->interfaces);
|
|
|
|
if (ni_client->priv->client_socket >= 0) {
|
|
close (ni_client->priv->client_socket);
|
|
ni_client->priv->client_socket = 0;
|
|
}
|
|
|
|
if (ni_client->priv->socket_path != NULL) {
|
|
g_free (ni_client->priv->socket_path);
|
|
ni_client->priv->socket_path = NULL;
|
|
}
|
|
|
|
parent_class->finalize (obj);
|
|
}
|
|
|
|
static void ni_client_init (NIClient *ni_client) {
|
|
NIClientPrivate *priv = ni_client_get_instance_private (ni_client);
|
|
ni_client->priv = priv;
|
|
|
|
priv->client_socket = -1;
|
|
priv->socket_path = NULL;
|
|
priv->source = 0;
|
|
priv->events = NET_INADOR_EVENT_MASK_INTERFACES | NET_INADOR_EVENT_MASK_IP;
|
|
|
|
priv->interfaces = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
}
|
|
|
|
void ni_client_update_event_mask (NIClient *ni_client) {
|
|
unsigned char buffer[8];
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_SET_EVENT_MASK;
|
|
memcpy (&buffer[2], &ni_client->priv->events, 4);
|
|
|
|
send (ni_client->priv->client_socket, buffer, 6, 0);
|
|
}
|
|
|
|
void ni_client_ask_interfaces (NIClient *ni_client) {
|
|
unsigned char buffer[8];
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_LIST_IFACES;
|
|
|
|
send (ni_client->priv->client_socket, buffer, 2, 0);
|
|
}
|
|
|
|
void ni_client_ask_ip_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, uint32_t *cacheinfo) {
|
|
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);
|
|
|
|
/* Copiar los timestamp solicitados */
|
|
memcpy (&buffer[14], cacheinfo, 8);
|
|
|
|
memcpy (&buffer[22], addr, family_size);
|
|
|
|
pos = 22 + 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_change_iface_mtu (NIClient *ni_client, NIInterface *ni_interface, guint new_mtu) {
|
|
unsigned char buffer[128];
|
|
uint32_t index, mtu;
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
index = ni_interface_get_index (ni_interface);
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_IFACE_CHANGE_MTU;
|
|
memcpy (&buffer[2], &index, 4);
|
|
//mtu = htonl (new_mtu);
|
|
mtu = new_mtu;
|
|
memcpy (&buffer[6], &mtu, 4);
|
|
|
|
send (ni_client->priv->client_socket, buffer, 10, 0);
|
|
}
|
|
|
|
void ni_client_ask_ip_interface (NIClient *ni_client, NIInterface *ni_interface, int family) {
|
|
unsigned char buffer[8];
|
|
uint32_t index;
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
index = ni_interface_get_index (ni_interface);
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_LIST_IP;
|
|
memcpy (&buffer[2], &index, 4);
|
|
buffer[6] = family;
|
|
|
|
send (ni_client->priv->client_socket, buffer, 7, 0);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void ni_client_ask_create_bridge (NIClient *ni_client, const gchar *name) {
|
|
unsigned char buffer[128];
|
|
int n_len;
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
if (name[0] == 0) return;
|
|
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_CREATE_BRIDGE;
|
|
n_len = strlen (name);
|
|
buffer[2] = n_len;
|
|
memcpy (&buffer[3], name, buffer[2]);
|
|
|
|
send (ni_client->priv->client_socket, buffer, 3 + n_len, 0);
|
|
}
|
|
|
|
void ni_client_ask_interface_clear_master (NIClient *ni_client, NIInterface *ni_interface) {
|
|
unsigned char buffer[128];
|
|
uint32_t index;
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_CLEAR_MASTER;
|
|
index = ni_interface_get_index (ni_interface);
|
|
memcpy (&buffer[2], &index, 4);
|
|
|
|
send (ni_client->priv->client_socket, buffer, 6, 0);
|
|
}
|
|
|
|
void ni_client_ask_interface_set_master (NIClient *ni_client, NIInterface *ni_interface, NIInterface *master) {
|
|
unsigned char buffer[128];
|
|
uint32_t index;
|
|
|
|
if (ni_client->priv->client_socket < 0) {
|
|
return;
|
|
}
|
|
|
|
buffer[0] = NET_INADOR_TYPE_COMMAND;
|
|
buffer[1] = NET_INADOR_COMMAND_SET_MASTER;
|
|
index = ni_interface_get_index (ni_interface);
|
|
memcpy (&buffer[2], &index, 4);
|
|
index = ni_interface_get_index (master);
|
|
memcpy (&buffer[6], &index, 4);
|
|
|
|
send (ni_client->priv->client_socket, buffer, 10, 0);
|
|
}
|
|
|
|
static void ni_client_foreach_has_table (gpointer key, gpointer value, gpointer data) {
|
|
GList **lista = (GList **) data;
|
|
|
|
*lista = g_list_append (*lista, value);
|
|
}
|
|
|
|
GList *ni_client_get_list_interfaces (NIClient *ni_client) {
|
|
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
|
|
GList *all_ifaces = NULL;
|
|
|
|
g_hash_table_foreach (ni_client->priv->interfaces, ni_client_foreach_has_table, &all_ifaces);
|
|
|
|
return all_ifaces;
|
|
}
|
|
|
|
NIInterface *ni_client_get_interface_by_index (NIClient *ni_client, guint index) {
|
|
g_return_val_if_fail (NI_IS_CLIENT (ni_client), NULL);
|
|
return g_hash_table_lookup (ni_client->priv->interfaces, GINT_TO_POINTER(index));
|
|
}
|
|
|
|
gboolean ni_client_connect (NIClient *ni_client) {
|
|
int s, ret;
|
|
struct sockaddr_un path_dest;
|
|
GIOChannel *channel;
|
|
|
|
if (ni_client->priv->client_socket >= 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
s = socket (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
|
|
|
|
if (s < 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
path_dest.sun_family = AF_UNIX;
|
|
strncpy (path_dest.sun_path, ni_client->priv->socket_path, sizeof (path_dest.sun_path));
|
|
ret = connect (s, (struct sockaddr *) &path_dest, sizeof (path_dest));
|
|
|
|
if (ret < 0) {
|
|
perror ("Connect");
|
|
close (s);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Tengo socket, instalar vigilante */
|
|
ni_client->priv->client_socket = s;
|
|
channel = g_io_channel_unix_new (s);
|
|
ni_client->priv->source = g_io_add_watch (channel, G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP, ni_client_read_from_socket, ni_client);
|
|
g_io_channel_unref (channel);
|
|
|
|
/* Pedir eventos */
|
|
ni_client_update_event_mask (ni_client);
|
|
|
|
/* Pedir un listado de interfaces */
|
|
ni_client_ask_interfaces (ni_client);
|
|
}
|
|
|
|
void ni_client_disconnect (NIClient *ni_client) {
|
|
/* TODO: Escribir esto */
|
|
}
|
|
|
|
NIClient *ni_client_new (void) {
|
|
return g_object_new (NI_TYPE_CLIENT, NULL);
|
|
}
|
|
|
|
NIClient *ni_client_new_with_path (const char *path) {
|
|
return g_object_new (NI_TYPE_CLIENT, "socket-path", path, NULL);
|
|
}
|
|
|