[v2] alfred: support for changing interfaces

Message ID 1409744490-20628-1-git-send-email-sw@simonwunderlich.de (mailing list archive)
State Accepted, archived
Commit babd772a36e186bf1a0d2e00239c6754ba240704
Headers

Commit Message

Simon Wunderlich Sept. 3, 2014, 11:41 a.m. UTC
  From: Simon Wunderlich <simon@open-mesh.com>

This patch adds support for changing the interface alfreds listens to on
the fly without restarting alfred.

Signed-off-by: Simon Wunderlich <simon@open-mesh.com>

---
Changes to PATCH:
 * fix const warning
---
 alfred.h     |  4 +++-
 client.c     | 54 +++++++++++++++++++++++++++++++++++++++++++++++++
 main.c       | 66 +++++++++++++++++++++++++++++++++++-------------------------
 man/alfred.8 |  3 +++
 packet.h     | 17 ++++++++++++++++
 unix_sock.c  | 38 ++++++++++++++++++++++++++++++++++
 vis/vis.c    |  2 +-
 7 files changed, 155 insertions(+), 29 deletions(-)
  

Comments

Simon Wunderlich Sept. 3, 2014, 11:50 a.m. UTC | #1
On Wednesday 03 September 2014 13:41:30 Simon Wunderlich wrote:
> From: Simon Wunderlich <simon@open-mesh.com>
> 
> This patch adds support for changing the interface alfreds listens to on
> the fly without restarting alfred.
> 
> Signed-off-by: Simon Wunderlich <simon@open-mesh.com>

Merged in revision babd772.

Cheers,
    Simon
  

Patch

diff --git a/alfred.h b/alfred.h
index 35ac4dd..c83f7f0 100644
--- a/alfred.h
+++ b/alfred.h
@@ -86,6 +86,7 @@  enum clientmode {
 	CLIENT_REQUEST_DATA,
 	CLIENT_SET_DATA,
 	CLIENT_MODESWITCH,
+	CLIENT_CHANGE_INTERFACE,
 };
 
 struct globals {
@@ -93,7 +94,7 @@  struct globals {
 	struct in6_addr address;
 	uint32_t scope_id;
 	struct server *best_server;	/* NULL if we are a server ourselves */
-	const char *interface;
+	char *interface;
 	const char *mesh_iface;
 	enum opmode opmode;
 	enum clientmode clientmode;
@@ -125,6 +126,7 @@  int set_best_server(struct globals *globals);
 int alfred_client_request_data(struct globals *globals);
 int alfred_client_set_data(struct globals *globals);
 int alfred_client_modeswitch(struct globals *globals);
+int alfred_client_change_interface(struct globals *globals);
 /* recv.c */
 int recv_alfred_packet(struct globals *globals);
 struct transaction_head *
diff --git a/client.c b/client.c
index b868719..48313db 100644
--- a/client.c
+++ b/client.c
@@ -22,6 +22,7 @@ 
 #include <ctype.h>
 #include <errno.h>
 #include <netinet/in.h>
+#include <sys/ioctl.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <string.h>
@@ -218,3 +219,56 @@  int alfred_client_modeswitch(struct globals *globals)
 	unix_sock_close(globals);
 	return 0;
 }
+
+int alfred_client_change_interface(struct globals *globals)
+{
+	unsigned char buf[MAX_PAYLOAD];
+	struct alfred_change_interface_v0 *change_interface;
+	struct ifreq ifr;
+	int ret, len;
+	int sock = -1;
+
+	if (unix_sock_open_client(globals))
+		return -1;
+
+	if (strlen(globals->interface) > IFNAMSIZ) {
+		fprintf(stderr, "%s: interface name too long, not changing\n",
+			__func__);
+		return 0;
+	}
+
+	sock = socket(PF_INET6, SOCK_DGRAM, 0);
+	if (sock < 0) {
+		perror("can't open socket");
+		return -1;
+	}
+
+	strncpy(ifr.ifr_name, globals->interface, IFNAMSIZ);
+	ifr.ifr_name[IFNAMSIZ - 1] = '\0';
+	if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
+		fprintf(stderr, "%s: can't find interface, not changing\n",
+			__func__);
+		close(sock);
+		return -1;
+	}
+
+	close(sock);
+
+	change_interface = (struct alfred_change_interface_v0 *)buf;
+	len = sizeof(*change_interface);
+
+	change_interface->header.type = ALFRED_CHANGE_INTERFACE;
+	change_interface->header.version = ALFRED_VERSION;
+	change_interface->header.length = htons(len - sizeof(change_interface->header));
+	memcpy(change_interface->iface, globals->interface,
+	       sizeof(change_interface->iface));
+
+	ret = write(globals->unix_sock, buf, len);
+	if (ret != len)
+		fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+			__func__, ret, len, strerror(errno));
+
+	unix_sock_close(globals);
+
+	return 0;
+}
diff --git a/main.c b/main.c
index 1add44e..5a4f1e6 100644
--- a/main.c
+++ b/main.c
@@ -33,25 +33,29 @@  static void alfred_usage(void)
 {
 	printf("Usage: alfred [options]\n");
 	printf("client mode options:\n");
-	printf("  -s, --set-data [data type]  sets new data to distribute from stdin\n");
-	printf("                              for the supplied data type (0-255)\n");
-	printf("  -r, --request [data type]   collect data from the network and prints\n");
-	printf("                              it on the network\n");
-	printf("  -V, --req-version           specify the data version set for -s\n");
-	printf("  -M, --modeswitch master     switch daemon to mode master\n");
-	printf("                   slave      switch daemon to mode slave\n");
+	printf("  -s, --set-data [data type]          sets new data to distribute from stdin\n");
+	printf("                                      for the supplied data type (0-255)\n");
+	printf("  -r, --request [data type]           collect data from the network and prints\n");
+	printf("                                      it on the network\n");
+	printf("  -V, --req-version                   specify the data version set for -s\n");
+	printf("  -M, --modeswitch master             switch daemon to mode master\n");
+	printf("                   slave              switch daemon to mode slave\n");
+	printf("  -I, --change-interface [interface]  change to the specified interface\n");
 	printf("\n");
 	printf("server mode options:\n");
-	printf("  -i, --interface             specify the interface to listen on\n");
-	printf("  -b                          specify the batman-adv interface configured on the system (default: bat0)\n");
-	printf("                              use 'none' to disable the batman-adv based best server selection\n");
-	printf("  -m, --master                start up the daemon in master mode, which\n");
-	printf("                              accepts data from slaves and synces it with\n");
-	printf("                              other masters\n");
+	printf("  -i, --interface                     specify the interface to listen on\n");
+	printf("  -b                                  specify the batman-adv interface\n");
+	printf("                                      configured on the system (default: bat0)\n");
+	printf("                                      use 'none' to disable the batman-adv\n");
+	printf("                                      based best server selection\n");
+	printf("  -m, --master                        start up the daemon in master mode, which\n");
+	printf("                                      accepts data from slaves and synces it with\n");
+	printf("                                      other masters\n");
 	printf("\n");
-	printf("  -u, --unix-path [path]      path to unix socket used for client-server communication (default: \""ALFRED_SOCK_PATH_DEFAULT"\")\n");
-	printf("  -v, --version               print the version\n");
-	printf("  -h, --help                  this help\n");
+	printf("  -u, --unix-path [path]              path to unix socket used for client-server\n");
+	printf("                                      communication (default: \""ALFRED_SOCK_PATH_DEFAULT"\")\n");
+	printf("  -v, --version                       print the version\n");
+	printf("  -h, --help                          this help\n");
 	printf("\n");
 }
 
@@ -60,16 +64,17 @@  static struct globals *alfred_init(int argc, char *argv[])
 	int opt, opt_ind, i;
 	struct globals *globals;
 	struct option long_options[] = {
-		{"set-data",	required_argument,	NULL,	's'},
-		{"request",	required_argument,	NULL,	'r'},
-		{"interface",	required_argument,	NULL,	'i'},
-		{"master",	no_argument,		NULL,	'm'},
-		{"help",	no_argument,		NULL,	'h'},
-		{"req-version", required_argument,	NULL,	'V'},
-		{"modeswitch",  required_argument,	NULL,	'M'},
-		{"unix-path", 	required_argument,	NULL,	'u'},
-		{"version",	no_argument,		NULL,	'v'},
-		{NULL,		0,			NULL,	0},
+		{"set-data",		required_argument,	NULL,	's'},
+		{"request",		required_argument,	NULL,	'r'},
+		{"interface",		required_argument,	NULL,	'i'},
+		{"master",		no_argument,		NULL,	'm'},
+		{"help",		no_argument,		NULL,	'h'},
+		{"req-version", 	required_argument,	NULL,	'V'},
+		{"modeswitch",  	required_argument,	NULL,	'M'},
+		{"change-interface",	required_argument,	NULL,	'I'},
+		{"unix-path",		required_argument,	NULL,	'u'},
+		{"version",		no_argument,		NULL,	'v'},
+		{NULL,			0,			NULL,	0},
 	};
 
 	globals = &alfred_globals;
@@ -85,7 +90,7 @@  static struct globals *alfred_init(int argc, char *argv[])
 
 	time_random_seed();
 
-	while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:u:", long_options,
+	while ((opt = getopt_long(argc, argv, "ms:r:hi:b:vV:M:I:u:", long_options,
 				  &opt_ind)) != -1) {
 		switch (opt) {
 		case 'r':
@@ -135,6 +140,10 @@  static struct globals *alfred_init(int argc, char *argv[])
 			}
 			globals->clientmode = CLIENT_MODESWITCH;
 			break;
+		case 'I':
+			globals->clientmode = CLIENT_CHANGE_INTERFACE;
+			globals->interface = strdup(optarg);
+			break;
 		case 'u':
 			globals->unix_path = optarg;
 			break;
@@ -176,6 +185,9 @@  int main(int argc, char *argv[])
 	case CLIENT_MODESWITCH:
 		return alfred_client_modeswitch(globals);
 		break;
+	case CLIENT_CHANGE_INTERFACE:
+		return alfred_client_change_interface(globals);
+		break;
 	}
 
 	return 0;
diff --git a/man/alfred.8 b/man/alfred.8
index c90caa8..35dee45 100644
--- a/man/alfred.8
+++ b/man/alfred.8
@@ -80,6 +80,9 @@  to 0 ('\fB\-V\fP 0').
 \fBslave\fP
     Switch daemon to mode slave
 .fi
+.TP
+\fB\-I\fP, \fB\-\-change\-interface\fP \fIinterface\fP
+Change the alfred server to use the new \fBinterface\fP
 .
 .SH SERVER OPTIONS
 .TP
diff --git a/packet.h b/packet.h
index ba8c5f6..dc06d65 100644
--- a/packet.h
+++ b/packet.h
@@ -20,6 +20,8 @@ 
 #ifndef _ALFRED_PACKET_H
 #define _ALFRED_PACKET_H
 
+#include <net/if.h>	/* IFNAMSIZ */
+
 #define __packed __attribute__ ((packed))
 
 /* basic blocks */
@@ -67,6 +69,7 @@  struct alfred_transaction_mgmt {
  * @ALFRED_STATUS_TXEND: Transaction was finished by sender
  * @ALFRED_STATUS_ERROR: Error was detected during the transaction
  * @ALFRED_MODESWITCH: Switch between different operation modes
+ * @ALFRED_CHANGE_INTERFACE: Change the listening interface
  */
 enum alfred_packet_type {
 	ALFRED_PUSH_DATA = 0,
@@ -75,6 +78,7 @@  enum alfred_packet_type {
 	ALFRED_STATUS_TXEND = 3,
 	ALFRED_STATUS_ERROR = 4,
 	ALFRED_MODESWITCH = 5,
+	ALFRED_CHANGE_INTERFACE = 6,
 };
 
 /* packets */
@@ -143,6 +147,19 @@  struct alfred_modeswitch_v0 {
 } __packed;
 
 /**
+ * struct alfred_change_interface_v0 - Request to change the interface
+ * @header: TLV header describing the complete packet
+ * @iface: interface name to be changed to
+ *
+ * Sent to the daemon by client
+ */
+struct alfred_change_interface_v0 {
+	struct alfred_tlv header;
+	char iface[IFNAMSIZ];
+} __packed;
+
+
+/**
  * struct alfred_status_v0 - Status info of a transaction
  * @header: TLV header describing the complete packet
  * @tx: Transaction identificator and sequence number of packet
diff --git a/unix_sock.c b/unix_sock.c
index cc0d25c..516c0a5 100644
--- a/unix_sock.c
+++ b/unix_sock.c
@@ -298,6 +298,38 @@  err:
 	return ret;
 }
 
+static int
+unix_sock_change_iface(struct globals *globals,
+		       struct alfred_change_interface_v0 *change_iface,
+		       int client_sock)
+{
+	int len, ret = -1;
+	char *iface;
+
+	len = ntohs(change_iface->header.length);
+
+	if (len < (int)(sizeof(*change_iface) - sizeof(change_iface->header)))
+		goto err;
+
+	iface = malloc(IFNAMSIZ + 1);
+	if (!iface)
+		goto err;
+
+	memcpy(iface, change_iface->iface, IFNAMSIZ);
+	iface[IFNAMSIZ] = 0;
+
+	netsock_close(globals->netsock);
+
+	free(globals->interface);
+	globals->interface = iface;
+	netsock_open(globals);
+
+	ret = 0;
+err:
+	close(client_sock);
+	return ret;
+}
+
 int unix_sock_read(struct globals *globals)
 {
 	int client_sock;
@@ -350,6 +382,12 @@  int unix_sock_read(struct globals *globals)
 				       (struct alfred_modeswitch_v0 *)packet,
 					client_sock);
 		break;
+	case ALFRED_CHANGE_INTERFACE:
+		ret = unix_sock_change_iface(globals,
+					     (struct alfred_change_interface_v0 *)packet,
+					     client_sock);
+		break;
+
 	default:
 		/* unknown packet type */
 		ret = -1;
diff --git a/vis/vis.c b/vis/vis.c
index 00372ab..3dd5c8c 100644
--- a/vis/vis.c
+++ b/vis/vis.c
@@ -23,7 +23,7 @@ 
 #include <dirent.h>
 #include <errno.h>
 #include <getopt.h>
-#include <linux/if.h>
+#include <net/if.h>
 #include <netinet/in.h>
 #include <signal.h>
 #include <stdbool.h>