Use a mutex to allow the TAP reader to process packets faster on Windows.
The TAP-Win32 device is not a socket, and select() under Windows only works with sockets. Tinc used a separate thread to read from the TAP-Win32 device, and passed this via a local socket to the main thread which could then select() from it. We now use a global mutex, which is only unlocked when the main thread is waiting for select(), to allow the TAP reader thread to process packets directly.
This commit is contained in:
		
							parent
							
								
									802a50ffcd
								
							
						
					
					
						commit
						b47c17bcde
					
				
					 4 changed files with 25 additions and 117 deletions
				
			
		| 
						 | 
				
			
			@ -34,7 +34,7 @@
 | 
			
		|||
 | 
			
		||||
#include "mingw/common.h"
 | 
			
		||||
 | 
			
		||||
int device_fd = 0;
 | 
			
		||||
int device_fd = -1;
 | 
			
		||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
 | 
			
		||||
char *device = NULL;
 | 
			
		||||
char *iface = NULL;
 | 
			
		||||
| 
						 | 
				
			
			@ -45,63 +45,24 @@ static int device_total_out = 0;
 | 
			
		|||
 | 
			
		||||
extern char *myport;
 | 
			
		||||
 | 
			
		||||
static struct packetbuf {
 | 
			
		||||
	uint8_t data[MTU];
 | 
			
		||||
	length_t len;
 | 
			
		||||
} *bufs;
 | 
			
		||||
 | 
			
		||||
static int nbufs = 64;
 | 
			
		||||
 | 
			
		||||
static DWORD WINAPI tapreader(void *bla) {
 | 
			
		||||
	int sock, err, status;
 | 
			
		||||
	struct addrinfo *ai;
 | 
			
		||||
	struct addrinfo hint = {
 | 
			
		||||
		.ai_family = AF_UNSPEC,
 | 
			
		||||
		.ai_socktype = SOCK_STREAM,
 | 
			
		||||
		.ai_protocol = IPPROTO_TCP,
 | 
			
		||||
		.ai_flags = 0,
 | 
			
		||||
	};
 | 
			
		||||
	unsigned char bufno = 0;
 | 
			
		||||
	int status;
 | 
			
		||||
	long len;
 | 
			
		||||
	OVERLAPPED overlapped;
 | 
			
		||||
 | 
			
		||||
	/* Open a socket to the parent process */
 | 
			
		||||
 | 
			
		||||
	err = getaddrinfo(NULL, myport, &hint, &ai);
 | 
			
		||||
 | 
			
		||||
	if(err || !ai) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
 | 
			
		||||
 | 
			
		||||
	if(sock < 0) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
 | 
			
		||||
		freeaddrinfo(ai);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(connect(sock, ai->ai_addr, ai->ai_addrlen)) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "connect", strerror(errno));
 | 
			
		||||
		freeaddrinfo(ai);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	freeaddrinfo(ai);
 | 
			
		||||
	vpn_packet_t packet;
 | 
			
		||||
 | 
			
		||||
	logger(LOG_DEBUG, _("Tap reader running"));
 | 
			
		||||
 | 
			
		||||
	/* Read from tap device and send to parent */
 | 
			
		||||
 | 
			
		||||
	overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 | 
			
		||||
	
 | 
			
		||||
 | 
			
		||||
	for(;;) {
 | 
			
		||||
		overlapped.Offset = 0;
 | 
			
		||||
		overlapped.OffsetHigh = 0;
 | 
			
		||||
		ResetEvent(overlapped.hEvent);
 | 
			
		||||
 | 
			
		||||
		status = ReadFile(device_handle, bufs[bufno].data, MTU, &len, &overlapped);
 | 
			
		||||
		status = ReadFile(device_handle, packet.data, MTU, &len, &overlapped);
 | 
			
		||||
 | 
			
		||||
		if(!status) {
 | 
			
		||||
			if(GetLastError() == ERROR_IO_PENDING) {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,11 +76,11 @@ static DWORD WINAPI tapreader(void *bla) {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bufs[bufno].len = len;
 | 
			
		||||
		if(send(sock, &bufno, 1, 0) <= 0)
 | 
			
		||||
			return -1;
 | 
			
		||||
		if(++bufno >= nbufs)
 | 
			
		||||
			bufno = 0;
 | 
			
		||||
		EnterCriticalSection(&mutex);
 | 
			
		||||
		packet.len = len;
 | 
			
		||||
		packet.priority = 0;
 | 
			
		||||
		route(myself, &packet);
 | 
			
		||||
		LeaveCriticalSection(&mutex);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -240,44 +201,6 @@ bool setup_device(void)
 | 
			
		|||
		overwrite_mac = 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Set up ringbuffer */
 | 
			
		||||
 | 
			
		||||
	get_config_int(lookup_config(config_tree, "RingBufferSize"), &nbufs);
 | 
			
		||||
	if(nbufs <= 1)
 | 
			
		||||
		nbufs = 1;
 | 
			
		||||
	else if(nbufs > 256)
 | 
			
		||||
		nbufs = 256;
 | 
			
		||||
	
 | 
			
		||||
	bufs = xmalloc_and_zero(nbufs * sizeof *bufs);
 | 
			
		||||
 | 
			
		||||
	/* Create a listening socket */
 | 
			
		||||
 | 
			
		||||
	err = getaddrinfo(NULL, myport, &hint, &ai);
 | 
			
		||||
 | 
			
		||||
	if(err || !ai) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "getaddrinfo", gai_strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sock = socket(ai->ai_family, SOCK_STREAM, IPPROTO_TCP);
 | 
			
		||||
 | 
			
		||||
	if(sock < 0) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "socket", strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(bind(sock, ai->ai_addr, ai->ai_addrlen)) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "bind", strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	freeaddrinfo(ai);
 | 
			
		||||
 | 
			
		||||
	if(listen(sock, 1)) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "listen", strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Start the tap reader */
 | 
			
		||||
 | 
			
		||||
	thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -287,15 +210,6 @@ bool setup_device(void)
 | 
			
		|||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Wait for the tap reader to connect back to us */
 | 
			
		||||
 | 
			
		||||
	if((device_fd = accept(sock, NULL, 0)) == -1) {
 | 
			
		||||
		logger(LOG_ERR, _("System call `%s' failed: %s"), "accept", strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	closesocket(sock);
 | 
			
		||||
 | 
			
		||||
	/* Set media status for newer TAP-Win32 devices */
 | 
			
		||||
 | 
			
		||||
	status = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -320,25 +234,7 @@ void close_device(void)
 | 
			
		|||
 | 
			
		||||
bool read_packet(vpn_packet_t *packet)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char bufno;
 | 
			
		||||
 | 
			
		||||
	cp();
 | 
			
		||||
 | 
			
		||||
	if((recv(device_fd, &bufno, 1, 0)) <= 0) {
 | 
			
		||||
		logger(LOG_ERR, _("Error while reading from %s %s: %s"), device_info,
 | 
			
		||||
			   device, strerror(errno));
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	packet->len = bufs[bufno].len;
 | 
			
		||||
	memcpy(packet->data, bufs[bufno].data, bufs[bufno].len);
 | 
			
		||||
 | 
			
		||||
	device_total_in += packet->len;
 | 
			
		||||
 | 
			
		||||
	ifdebug(TRAFFIC) logger(LOG_DEBUG, _("Read packet of %d bytes from %s"), packet->len,
 | 
			
		||||
			   device_info);
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool write_packet(vpn_packet_t *packet)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										11
									
								
								src/net.c
									
										
									
									
									
								
							
							
						
						
									
										11
									
								
								src/net.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -149,7 +149,8 @@ static int build_fdset(fd_set *readset, fd_set *writeset)
 | 
			
		|||
			max = listen_socket[i].udp;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	FD_SET(device_fd, readset);
 | 
			
		||||
	if(device_fd >= 0)
 | 
			
		||||
		FD_SET(device_fd, readset);
 | 
			
		||||
	if(device_fd > max)
 | 
			
		||||
		max = device_fd;
 | 
			
		||||
	
 | 
			
		||||
| 
						 | 
				
			
			@ -294,7 +295,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset)
 | 
			
		|||
	cp();
 | 
			
		||||
 | 
			
		||||
	/* check input from kernel */
 | 
			
		||||
	if(FD_ISSET(device_fd, readset)) {
 | 
			
		||||
	if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
 | 
			
		||||
		if(read_packet(&packet)) {
 | 
			
		||||
			packet.priority = 0;
 | 
			
		||||
			route(myself, &packet);
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +379,13 @@ int main_loop(void)
 | 
			
		|||
 | 
			
		||||
		maxfd = build_fdset(&readset, &writeset);
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_MINGW
 | 
			
		||||
		LeaveCriticalSection(&mutex);
 | 
			
		||||
#endif
 | 
			
		||||
		r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
 | 
			
		||||
#ifdef HAVE_MINGW
 | 
			
		||||
		EnterCriticalSection(&mutex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		if(r < 0) {
 | 
			
		||||
			if(errno != EINTR && errno != EAGAIN) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -143,6 +143,8 @@ extern void send_mtu_probe(struct node_t *);
 | 
			
		|||
 | 
			
		||||
#ifndef HAVE_MINGW
 | 
			
		||||
#define closesocket(s) close(s)
 | 
			
		||||
#else
 | 
			
		||||
extern CRITICAL_SECTION mutex;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif							/* __TINC_NET_H__ */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -115,6 +115,7 @@ static struct option const long_options[] = {
 | 
			
		|||
 | 
			
		||||
#ifdef HAVE_MINGW
 | 
			
		||||
static struct WSAData wsa_state;
 | 
			
		||||
CRITICAL_SECTION mutex;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void usage(bool status)
 | 
			
		||||
| 
						 | 
				
			
			@ -568,6 +569,8 @@ int main(int argc, char **argv)
 | 
			
		|||
 | 
			
		||||
int main2(int argc, char **argv)
 | 
			
		||||
{
 | 
			
		||||
	InitializeCriticalSection(&mutex);
 | 
			
		||||
	EnterCriticalSection(&mutex);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	if(!detach())
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue