From b107b10c4ef70bdf74d6d6ac57ff5ab2698b9cb2 Mon Sep 17 00:00:00 2001
From: Guus Sliepen <guus@tinc-vpn.org>
Date: Fri, 14 Jan 2011 16:00:22 +0100
Subject: [PATCH] Use threads for UDP sockets.

---
 src/net.h        |  4 +++-
 src/net_packet.c | 51 ++++++++++++++++++++++++++----------------------
 src/net_setup.c  |  9 +++------
 src/net_socket.c | 22 ---------------------
 src/threads.h    |  9 ++-------
 5 files changed, 36 insertions(+), 59 deletions(-)

diff --git a/src/net.h b/src/net.h
index 9b625a0d..a6d5cb96 100644
--- a/src/net.h
+++ b/src/net.h
@@ -24,6 +24,7 @@
 #include "ipv6.h"
 #include "cipher.h"
 #include "digest.h"
+#include "threads.h"
 
 #ifdef ENABLE_JUMBOGRAMS
 #define MTU 9018				/* 9000 bytes payload + 14 bytes ethernet header + 4 bytes VLAN tag */
@@ -88,6 +89,7 @@ typedef struct listen_socket_t {
 	struct event ev_udp;
 	int tcp;
 	int udp;
+	thread_t udp_thread;
 	sockaddr_t sa;
 } listen_socket_t;
 
@@ -125,7 +127,7 @@ extern int contradicting_del_edge;
 #include "node.h"
 
 extern void retry_outgoing(outgoing_t *);
-extern void handle_incoming_vpn_data(int, short, void *);
+extern void handle_incoming_vpn_data(void *);
 extern void finish_connecting(struct connection_t *);
 extern void do_outgoing_connection(struct connection_t *);
 extern void handle_new_meta_connection(int, short, void *);
diff --git a/src/net_packet.c b/src/net_packet.c
index 7be46620..61a9f48e 100644
--- a/src/net_packet.c
+++ b/src/net_packet.c
@@ -576,7 +576,8 @@ static node_t *try_harder(const sockaddr_t *from, const vpn_packet_t *pkt) {
 	return found;
 }
 
-void handle_incoming_vpn_data(int sock, short events, void *data) {
+void handle_incoming_vpn_data(void *arg) {
+	listen_socket_t *l = arg;
 	vpn_packet_t pkt;
 	char *hostname;
 	sockaddr_t from;
@@ -584,35 +585,39 @@ void handle_incoming_vpn_data(int sock, short events, void *data) {
 	node_t *n;
 	int len;
 
-	len = recvfrom(sock, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
+	while(true) {
+		len = recvfrom(l->udp, (char *) &pkt.seqno, MAXSIZE, 0, &from.sa, &fromlen);
 
-	if(len <= 0 || len > MAXSIZE) {
-		if(!sockwouldblock(sockerrno))
-			logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
-		return;
-	}
+		if(len <= 0 || len > MAXSIZE) {
+			if(!sockwouldblock(sockerrno)) {
+				logger(LOG_ERR, "Receiving packet failed: %s", sockstrerror(sockerrno));
+				return;
+			}
+			continue;
+		}
 
-	pkt.len = len;
+		pkt.len = len;
 
-	sockaddrunmap(&from);		/* Some braindead IPv6 implementations do stupid things. */
+		sockaddrunmap(&from);		/* Some braindead IPv6 implementations do stupid things. */
 
-	n = lookup_node_udp(&from);
+		n = lookup_node_udp(&from);
 
-	if(!n) {
-		n = try_harder(&from, &pkt);
-		if(n)
-			update_node_udp(n, &from);
-		else ifdebug(PROTOCOL) {
-			hostname = sockaddr2hostname(&from);
-			logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
-			free(hostname);
-			return;
+		if(!n) {
+			n = try_harder(&from, &pkt);
+			if(n)
+				update_node_udp(n, &from);
+			else ifdebug(PROTOCOL) {
+				hostname = sockaddr2hostname(&from);
+				logger(LOG_WARNING, "Received UDP packet from unknown source %s", hostname);
+				free(hostname);
+				continue;
+			}
+			else
+				continue;
 		}
-		else
-			return;
-	}
 
-	receive_udppacket(n, &pkt);
+		receive_udppacket(n, &pkt);
+	}
 }
 
 void handle_device_data(int sock, short events, void *data) {
diff --git a/src/net_setup.c b/src/net_setup.c
index b31bed73..dc1d665d 100644
--- a/src/net_setup.c
+++ b/src/net_setup.c
@@ -529,12 +529,8 @@ bool setup_myself(void) {
 			abort();
 		}
 
-		event_set(&listen_socket[listen_sockets].ev_udp,
-				  listen_socket[listen_sockets].udp,
-				  EV_READ|EV_PERSIST,
-				  handle_incoming_vpn_data, NULL);
-		if(event_add(&listen_socket[listen_sockets].ev_udp, NULL) < 0) {
-			logger(LOG_ERR, "event_add failed: %s", strerror(errno));
+		if(!thread_create(&listen_socket[listen_sockets].udp_thread, handle_incoming_vpn_data, &listen_socket[listen_sockets])) {
+			logger(LOG_ERR, "thread_create failed: %s", strerror(errno));
 			abort();
 		}
 
@@ -625,6 +621,7 @@ void close_network_connections(void) {
 		event_del(&listen_socket[i].ev_udp);
 		close(listen_socket[i].tcp);
 		close(listen_socket[i].udp);
+		thread_destroy(&listen_socket[i].udp_thread);
 	}
 
 	xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
diff --git a/src/net_socket.c b/src/net_socket.c
index e20076fb..7c4463ea 100644
--- a/src/net_socket.c
+++ b/src/net_socket.c
@@ -237,28 +237,6 @@ int setup_vpn_in_socket(const sockaddr_t *sa) {
 		return -1;
 	}
 
-#ifdef O_NONBLOCK
-	{
-		int flags = fcntl(nfd, F_GETFL);
-
-		if(fcntl(nfd, F_SETFL, flags | O_NONBLOCK) < 0) {
-			closesocket(nfd);
-			logger(LOG_ERR, "System call `%s' failed: %s", "fcntl",
-				   strerror(errno));
-			return -1;
-		}
-	}
-#elif defined(WIN32)
-	{
-		unsigned long arg = 1;
-		if(ioctlsocket(nfd, FIONBIO, &arg) != 0) {
-			closesocket(nfd);
-			logger(LOG_ERR, "Call to `%s' failed: %s", "ioctlsocket", sockstrerror(sockerrno));
-			return -1;
-		}
-	}
-#endif
-
 	option = 1;
 	setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (void *)&option, sizeof option);
 
diff --git a/src/threads.h b/src/threads.h
index 3243907d..d2ef4a64 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -1,11 +1,6 @@
 #ifndef __THREADS_H__
 #define __THREADS_H__
 
-typedef struct event {
-	int foo;
-} event_t;
-	
-
 #ifdef HAVE_MINGW
 typedef HANDLE thread_t;
 typedef CRITICAL_SECTION mutex_t;
@@ -33,11 +28,11 @@ static inline void mutex_unlock(mutex_t *mutex) {
 typedef pthread_t thread_t;
 typedef pthread_mutex_t mutex_t;
 
-static inline void thread_create(thread_t *tid, void (*func)(void *), void *arg) {
+static inline bool thread_create(thread_t *tid, void (*func)(void *), void *arg) {
 	return !pthread_create(tid, NULL, (void *(*)(void *))func, arg);
 }
 static inline void thread_destroy(thread_t *tid) {
-	pthread_join(tid);
+	pthread_join(*tid, NULL);
 }
 static inline void mutex_create(mutex_t *mutex) {
 	pthread_mutex_init(mutex, NULL);
-- 
2.39.5