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…
Reference in a new issue