From 0871c3095151bce6a4031a2662aa51b7193b855c Mon Sep 17 00:00:00 2001
From: Fufu Fang <fangfufu2003@gmail.com>
Date: Tue, 10 Aug 2021 01:53:00 +0100
Subject: [PATCH] Reduce pointer indirection for global list_t variables

Converted cmdline_conf, connection_list, outgoing_list from
pointer-to-structs to structs.

Created list_empty_list for these structs. This is necessary,
because list_delete_list frees the supplied list_t pointer.

Part of https://github.com/gsliepen/tinc/issues/294
---
 src/autoconnect.c  | 22 +++++++++++-----------
 src/conf.c         | 15 +++++++++------
 src/conf.h         |  2 +-
 src/connection.c   | 18 +++++++++++-------
 src/connection.h   |  2 +-
 src/control.c      |  2 +-
 src/graph.c        |  2 +-
 src/list.c         |  9 ++++++++-
 src/list.h         |  1 +
 src/logger.c       |  4 ++--
 src/meta.c         |  2 +-
 src/net.c          |  8 ++++----
 src/net.h          |  2 +-
 src/net_packet.c   |  2 +-
 src/net_setup.c    |  6 ++----
 src/net_socket.c   | 38 ++++++++++++++++++++------------------
 src/protocol_key.c |  2 +-
 src/route.c        |  6 +++---
 src/tincd.c        |  9 +++------
 19 files changed, 82 insertions(+), 70 deletions(-)

diff --git a/src/autoconnect.c b/src/autoconnect.c
index d819ee46..5651f54d 100644
--- a/src/autoconnect.c
+++ b/src/autoconnect.c
@@ -53,7 +53,7 @@ static void make_new_connection() {
 
 		bool found = false;
 
-		for list_each(outgoing_t, outgoing, outgoing_list) {
+		for list_each(outgoing_t, outgoing, &outgoing_list) {
 			if(outgoing->node == n) {
 				found = true;
 				break;
@@ -64,7 +64,7 @@ static void make_new_connection() {
 			logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
 			outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
 			outgoing->node = n;
-			list_insert_tail(outgoing_list, outgoing);
+			list_insert_tail(&outgoing_list, outgoing);
 			setup_outgoing_connection(outgoing, false);
 		}
 
@@ -93,7 +93,7 @@ static void connect_to_unreachable() {
 		}
 
 		/* Are we already trying to make an outgoing connection to it? If so, return. */
-		for list_each(outgoing_t, outgoing, outgoing_list) {
+		for list_each(outgoing_t, outgoing, &outgoing_list) {
 			if(outgoing->node == n) {
 				return;
 			}
@@ -102,7 +102,7 @@ static void connect_to_unreachable() {
 		logger(DEBUG_CONNECTIONS, LOG_INFO, "Autoconnecting to %s", n->name);
 		outgoing_t *outgoing = xzalloc(sizeof(*outgoing));
 		outgoing->node = n;
-		list_insert_tail(outgoing_list, outgoing);
+		list_insert_tail(&outgoing_list, outgoing);
 		setup_outgoing_connection(outgoing, false);
 
 		return;
@@ -113,7 +113,7 @@ static void drop_superfluous_outgoing_connection() {
 	/* Choose a random outgoing connection to a node that has at least one other connection. */
 	int count = 0;
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
 			continue;
 		}
@@ -127,7 +127,7 @@ static void drop_superfluous_outgoing_connection() {
 
 	int r = rand() % count;
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(!c->edge || !c->outgoing || !c->node || c->node->edge_tree->count < 2) {
 			continue;
 		}
@@ -137,7 +137,7 @@ static void drop_superfluous_outgoing_connection() {
 		}
 
 		logger(DEBUG_CONNECTIONS, LOG_INFO, "Autodisconnecting from %s", c->name);
-		list_delete(outgoing_list, c->outgoing);
+		list_delete(&outgoing_list, c->outgoing);
 		c->outgoing = NULL;
 		terminate_connection(c, c->edge);
 		break;
@@ -145,11 +145,11 @@ static void drop_superfluous_outgoing_connection() {
 }
 
 static void drop_superfluous_pending_connections() {
-	for list_each(outgoing_t, o, outgoing_list) {
+	for list_each(outgoing_t, o, &outgoing_list) {
 		/* Only look for connections that are waiting to be retried later. */
 		bool found = false;
 
-		for list_each(connection_t, c, connection_list) {
+		for list_each(connection_t, c, &connection_list) {
 			if(c->outgoing == o) {
 				found = true;
 				break;
@@ -161,7 +161,7 @@ static void drop_superfluous_pending_connections() {
 		}
 
 		logger(DEBUG_CONNECTIONS, LOG_INFO, "Cancelled outgoing connection to %s", o->node->name);
-		list_delete_node(outgoing_list, node);
+		list_delete_node(&outgoing_list, node);
 	}
 }
 
@@ -169,7 +169,7 @@ void do_autoconnect() {
 	/* Count number of active connections. */
 	int nc = 0;
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(c->edge) {
 			nc++;
 		}
diff --git a/src/conf.c b/src/conf.c
index a0107d02..90bd3697 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -38,7 +38,14 @@ splay_tree_t *config_tree = NULL;
 
 int pinginterval = 0;           /* seconds between pings */
 int pingtimeout = 0;            /* seconds to wait for response */
-list_t *cmdline_conf = NULL;    /* global/host configuration values given at the command line */
+
+/* global/host configuration values given at the command line */
+list_t cmdline_conf = {
+	.head = NULL,
+	.tail = NULL,
+	.count = 0,
+	.delete = (list_action_t)free_config,
+};
 
 static int config_compare(const config_t *a, const config_t *b) {
 	int result;
@@ -334,13 +341,9 @@ bool read_config_file(splay_tree_t *config_tree, const char *fname, bool verbose
 }
 
 void read_config_options(splay_tree_t *config_tree, const char *prefix) {
-	if(!cmdline_conf) {
-		return;
-	}
-
 	size_t prefix_len = prefix ? strlen(prefix) : 0;
 
-	for(const list_node_t *node = cmdline_conf->tail; node; node = node->prev) {
+	for(const list_node_t *node = cmdline_conf.tail; node; node = node->prev) {
 		const config_t *cfg = node->data;
 		config_t *new;
 
diff --git a/src/conf.h b/src/conf.h
index d6479a2e..07db631c 100644
--- a/src/conf.h
+++ b/src/conf.h
@@ -39,7 +39,7 @@ extern int pinginterval;
 extern int pingtimeout;
 extern int maxtimeout;
 extern bool bypass_security;
-extern list_t *cmdline_conf;
+extern list_t cmdline_conf;
 
 extern void init_configuration(splay_tree_t **config_tree);
 extern void exit_configuration(splay_tree_t **config_tree);
diff --git a/src/connection.c b/src/connection.c
index 5a7c43b8..0c5e7ef0 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -31,19 +31,23 @@
 #include "utils.h"
 #include "xalloc.h"
 
-list_t *connection_list;
+list_t connection_list = {
+	.head = NULL,
+	.tail = NULL,
+	.count = 0,
+	.delete = (list_action_t) free_connection,
+};
+
 connection_t *everyone;
 
 void init_connections(void) {
-	connection_list = list_alloc((list_action_t) free_connection);
 	everyone = new_connection();
 	everyone->name = xstrdup("everyone");
 	everyone->hostname = xstrdup("BROADCAST");
 }
 
 void exit_connections(void) {
-	list_delete_list(connection_list);
-	connection_list = NULL;
+	list_empty_list(&connection_list);
 
 	free_connection(everyone);
 	everyone = NULL;
@@ -96,15 +100,15 @@ void free_connection(connection_t *c) {
 }
 
 void connection_add(connection_t *c) {
-	list_insert_tail(connection_list, c);
+	list_insert_tail(&connection_list, c);
 }
 
 void connection_del(connection_t *c) {
-	list_delete(connection_list, c);
+	list_delete(&connection_list, c);
 }
 
 bool dump_connections(connection_t *cdump) {
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		send_request(cdump, "%d %d %s %s %x %d %x",
 		             CONTROL, REQ_DUMP_CONNECTIONS,
 		             c->name, c->hostname, c->options, c->socket,
diff --git a/src/connection.h b/src/connection.h
index 4a9ef446..b23e02b7 100644
--- a/src/connection.h
+++ b/src/connection.h
@@ -107,7 +107,7 @@ typedef struct connection_t {
 	splay_tree_t *config_tree;      /* Pointer to configuration tree belonging to him */
 } connection_t;
 
-extern list_t *connection_list;
+extern list_t connection_list;
 extern connection_t *everyone;
 
 extern void init_connections(void);
diff --git a/src/control.c b/src/control.c
index 6e2a7f32..175f2bd0 100644
--- a/src/control.c
+++ b/src/control.c
@@ -108,7 +108,7 @@ bool control_h(connection_t *c, const char *request) {
 			return control_return(c, REQ_DISCONNECT, -1);
 		}
 
-		for list_each(connection_t, other, connection_list) {
+		for list_each(connection_t, other, &connection_list) {
 			if(strcmp(other->name, name)) {
 				continue;
 			}
diff --git a/src/graph.c b/src/graph.c
index 4de9181c..3a843063 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -64,7 +64,7 @@
 static void mst_kruskal(void) {
 	/* Clear MST status on connections */
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		c->status.mst = false;
 	}
 
diff --git a/src/list.c b/src/list.c
index 27494c89..50f3fdbb 100644
--- a/src/list.c
+++ b/src/list.c
@@ -184,11 +184,18 @@ void *list_get_tail(list_t *list) {
 
 /* Fast list deletion */
 
-void list_delete_list(list_t *list) {
+void list_empty_list(list_t *list) {
 	for(list_node_t *node = list->head, *next; next = node ? node->next : NULL, node; node = next) {
 		list_free_node(list, node);
 	}
 
+	list->head = NULL;
+	list->tail = NULL;
+	list->count = 0;
+}
+
+void list_delete_list(list_t *list) {
+	list_empty_list(list);
 	list_free(list);
 }
 
diff --git a/src/list.h b/src/list.h
index 3806495c..511b64a4 100644
--- a/src/list.h
+++ b/src/list.h
@@ -57,6 +57,7 @@ extern list_node_t *list_insert_tail(list_t *list, void *data);
 extern list_node_t *list_insert_after(list_t *list, list_node_t *node, void *data);
 extern list_node_t *list_insert_before(list_t *list, list_node_t *node, void *data);
 
+extern void list_empty_list(list_t *list);
 extern void list_delete(list_t *list, const void *data);
 
 extern void list_unlink_node(list_t *list, list_node_t *node);
diff --git a/src/logger.c b/src/logger.c
index 55616fba..1a2e95ff 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -96,11 +96,11 @@ static void real_logger(debug_t level, int priority, const char *message) {
 		}
 	}
 
-	if(logcontrol && connection_list) {
+	if(logcontrol) {
 		suppress = true;
 		logcontrol = false;
 
-		for list_each(connection_t, c, connection_list) {
+		for list_each(connection_t, c, &connection_list) {
 			if(!c->status.log) {
 				continue;
 			}
diff --git a/src/meta.c b/src/meta.c
index afc98ab2..7a8baac4 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -109,7 +109,7 @@ void send_meta_raw(connection_t *c, const void *buffer, size_t length) {
 }
 
 void broadcast_meta(connection_t *from, const char *buffer, size_t length) {
-	for list_each(connection_t, c, connection_list)
+	for list_each(connection_t, c, &connection_list)
 		if(c != from && c->edge) {
 			send_meta(c, buffer, length);
 		}
diff --git a/src/net.c b/src/net.c
index 33870f1e..dffe0b47 100644
--- a/src/net.c
+++ b/src/net.c
@@ -209,7 +209,7 @@ static void timeout_handler(void *data) {
 
 	last_periodic_run_time = now;
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		// control connections (eg. tinc ctl) do not have any timeout
 		if(c->status.control) {
 			continue;
@@ -434,7 +434,7 @@ int reload_configuration(void) {
 
 	/* Close connections to hosts that have a changed or deleted host config file */
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(c->status.control) {
 			continue;
 		}
@@ -455,7 +455,7 @@ int reload_configuration(void) {
 
 void retry(void) {
 	/* Reset the reconnection timers for all outgoing connections */
-	for list_each(outgoing_t, outgoing, outgoing_list) {
+	for list_each(outgoing_t, outgoing, &outgoing_list) {
 		outgoing->timeout = 0;
 
 		if(outgoing->ev.cb)
@@ -465,7 +465,7 @@ void retry(void) {
 	}
 
 	/* Check for outgoing connections that are in progress, and reset their ping timers */
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(c->outgoing && !c->node) {
 			c->last_ping_time = 0;
 		}
diff --git a/src/net.h b/src/net.h
index 28f8cb5e..f945a1f9 100644
--- a/src/net.h
+++ b/src/net.h
@@ -120,7 +120,7 @@ typedef struct outgoing_t {
 	timeout_t ev;
 } outgoing_t;
 
-extern list_t *outgoing_list;
+extern list_t outgoing_list;
 
 extern int maxoutbufsize;
 extern int seconds_till_retry;
diff --git a/src/net_packet.c b/src/net_packet.c
index dab74e5d..3f2fb489 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -1623,7 +1623,7 @@ void broadcast_packet(const node_t *from, vpn_packet_t *packet) {
 	// This guarantees all nodes receive the broadcast packet, and
 	// usually distributes the sending of broadcast packets over all nodes.
 	case BMODE_MST:
-		for list_each(connection_t, c, connection_list)
+		for list_each(connection_t, c, &connection_list)
 			if(c->edge && c->status.mst && c != from->nexthop->connection) {
 				send_packet(c->node, packet);
 			}
diff --git a/src/net_setup.c b/src/net_setup.c
index c2e0825e..4e1f2b81 100644
--- a/src/net_setup.c
+++ b/src/net_setup.c
@@ -1149,7 +1149,7 @@ bool setup_network(void) {
   close all open network connections
 */
 void close_network_connections(void) {
-	for(list_node_t *node = connection_list->head, *next; node; node = next) {
+	for(list_node_t *node = connection_list.head, *next; node; node = next) {
 		next = node->next;
 		connection_t *c = node->data;
 
@@ -1162,9 +1162,7 @@ void close_network_connections(void) {
 		terminate_connection(c, false);
 	}
 
-	if(outgoing_list) {
-		list_delete_list(outgoing_list);
-	}
+	list_empty_list(&outgoing_list);
 
 	if(myself && myself->connection) {
 		subnet_update(myself, NULL, false);
diff --git a/src/net_socket.c b/src/net_socket.c
index 40671db0..a29398d3 100644
--- a/src/net_socket.c
+++ b/src/net_socket.c
@@ -49,7 +49,18 @@ int listen_sockets;
 #ifndef HAVE_MINGW
 io_t unix_socket;
 #endif
-list_t *outgoing_list = NULL;
+
+static void free_outgoing(outgoing_t *outgoing) {
+	timeout_del(&outgoing->ev);
+	free(outgoing);
+}
+
+list_t outgoing_list = {
+	.head = NULL,
+	.tail = NULL,
+	.count = 0,
+	.delete = (list_action_t)free_outgoing,
+};
 
 /* Setup sockets */
 
@@ -675,7 +686,7 @@ void setup_outgoing_connection(outgoing_t *outgoing, bool verbose) {
 	return;
 
 remove:
-	list_delete(outgoing_list, outgoing);
+	list_delete(&outgoing_list, outgoing);
 }
 
 /*
@@ -809,20 +820,11 @@ void handle_new_unix_connection(void *data, int flags) {
 }
 #endif
 
-static void free_outgoing(outgoing_t *outgoing) {
-	timeout_del(&outgoing->ev);
-	free(outgoing);
-}
-
 void try_outgoing_connections(void) {
 	/* If there is no outgoing list yet, create one. Otherwise, mark all outgoings as deleted. */
 
-	if(!outgoing_list) {
-		outgoing_list = list_alloc((list_action_t)free_outgoing);
-	} else {
-		for list_each(outgoing_t, outgoing, outgoing_list) {
-			outgoing->timeout = -1;
-		}
+	for list_each(outgoing_t, outgoing, &outgoing_list) {
+		outgoing->timeout = -1;
 	}
 
 	/* Make sure there is one outgoing_t in the list for each ConnectTo. */
@@ -846,7 +848,7 @@ void try_outgoing_connections(void) {
 
 		bool found = false;
 
-		for list_each(outgoing_t, outgoing, outgoing_list) {
+		for list_each(outgoing_t, outgoing, &outgoing_list) {
 			if(!strcmp(outgoing->node->name, name)) {
 				found = true;
 				outgoing->timeout = 0;
@@ -867,14 +869,14 @@ void try_outgoing_connections(void) {
 			free(name);
 
 			outgoing->node = n;
-			list_insert_tail(outgoing_list, outgoing);
+			list_insert_tail(&outgoing_list, outgoing);
 			setup_outgoing_connection(outgoing, true);
 		}
 	}
 
 	/* Terminate any connections whose outgoing_t is to be deleted. */
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(c->outgoing && c->outgoing->timeout == -1) {
 			c->outgoing = NULL;
 			logger(DEBUG_CONNECTIONS, LOG_INFO, "No more outgoing connection to %s", c->name);
@@ -884,8 +886,8 @@ void try_outgoing_connections(void) {
 
 	/* Delete outgoing_ts for which there is no ConnectTo. */
 
-	for list_each(outgoing_t, outgoing, outgoing_list)
+	for list_each(outgoing_t, outgoing, &outgoing_list)
 		if(outgoing->timeout == -1) {
-			list_delete_node(outgoing_list, node);
+			list_delete_node(&outgoing_list, node);
 		}
 }
diff --git a/src/protocol_key.c b/src/protocol_key.c
index 29fe5090..b69d5adc 100644
--- a/src/protocol_key.c
+++ b/src/protocol_key.c
@@ -39,7 +39,7 @@ void send_key_changed(void) {
 
 	/* Immediately send new keys to directly connected nodes to keep UDP mappings alive */
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(c->edge && c->node && c->node->status.reachable && !c->node->status.sptps) {
 			send_ans_key(c->node);
 		}
diff --git a/src/route.c b/src/route.c
index e11a7922..559cf2fc 100644
--- a/src/route.c
+++ b/src/route.c
@@ -504,7 +504,7 @@ static void age_subnets(void *data) {
 				}
 			}
 
-			for list_each(connection_t, c, connection_list)
+			for list_each(connection_t, c, &connection_list)
 				if(c->edge) {
 					send_del_subnet(c, s);
 				}
@@ -543,7 +543,7 @@ static void learn_mac(mac_t *address) {
 
 		/* And tell all other tinc daemons it's our MAC */
 
-		for list_each(connection_t, c, connection_list)
+		for list_each(connection_t, c, &connection_list)
 			if(c->edge) {
 				send_add_subnet(c, subnet);
 			}
@@ -1111,7 +1111,7 @@ static void route_mac(node_t *source, vpn_packet_t *packet) {
 static void send_pcap(vpn_packet_t *packet) {
 	pcap = false;
 
-	for list_each(connection_t, c, connection_list) {
+	for list_each(connection_t, c, &connection_list) {
 		if(!c->status.pcap) {
 			continue;
 		}
diff --git a/src/tincd.c b/src/tincd.c
index 95872c34..dee38ef1 100644
--- a/src/tincd.c
+++ b/src/tincd.c
@@ -148,8 +148,6 @@ static bool parse_options(int argc, char **argv) {
 	int option_index = 0;
 	int lineno = 0;
 
-	cmdline_conf = list_alloc((list_action_t)free_config);
-
 	while((r = getopt_long(argc, argv, "c:DLd::n:so:RU:", long_options, &option_index)) != EOF) {
 		switch(r) {
 		case 0:   /* long option */
@@ -203,7 +201,7 @@ static bool parse_options(int argc, char **argv) {
 				goto exit_fail;
 			}
 
-			list_insert_tail(cmdline_conf, cfg);
+			list_insert_tail(&cmdline_conf, cfg);
 			break;
 
 #ifdef HAVE_MINGW
@@ -294,8 +292,7 @@ static bool parse_options(int argc, char **argv) {
 
 exit_fail:
 	free_names();
-	list_delete_list(cmdline_conf);
-	cmdline_conf = NULL;
+	list_empty_list(&cmdline_conf);
 	return false;
 }
 
@@ -386,7 +383,7 @@ static void cleanup() {
 		exit_configuration(&config_tree);
 	}
 
-	list_delete_list(cmdline_conf);
+	list_empty_list(&cmdline_conf);
 	free_names();
 }
 
-- 
2.39.5