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"
|
#include "mingw/common.h"
|
||||||
|
|
||||||
int device_fd = 0;
|
int device_fd = -1;
|
||||||
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
static HANDLE device_handle = INVALID_HANDLE_VALUE;
|
||||||
char *device = NULL;
|
char *device = NULL;
|
||||||
char *iface = NULL;
|
char *iface = NULL;
|
||||||
|
@ -45,63 +45,24 @@ static int device_total_out = 0;
|
||||||
|
|
||||||
extern char *myport;
|
extern char *myport;
|
||||||
|
|
||||||
static struct packetbuf {
|
|
||||||
uint8_t data[MTU];
|
|
||||||
length_t len;
|
|
||||||
} *bufs;
|
|
||||||
|
|
||||||
static int nbufs = 64;
|
|
||||||
|
|
||||||
static DWORD WINAPI tapreader(void *bla) {
|
static DWORD WINAPI tapreader(void *bla) {
|
||||||
int sock, err, status;
|
int 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;
|
|
||||||
long len;
|
long len;
|
||||||
OVERLAPPED overlapped;
|
OVERLAPPED overlapped;
|
||||||
|
vpn_packet_t packet;
|
||||||
/* 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);
|
|
||||||
|
|
||||||
logger(LOG_DEBUG, _("Tap reader running"));
|
logger(LOG_DEBUG, _("Tap reader running"));
|
||||||
|
|
||||||
/* Read from tap device and send to parent */
|
/* Read from tap device and send to parent */
|
||||||
|
|
||||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
overlapped.Offset = 0;
|
overlapped.Offset = 0;
|
||||||
overlapped.OffsetHigh = 0;
|
overlapped.OffsetHigh = 0;
|
||||||
ResetEvent(overlapped.hEvent);
|
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(!status) {
|
||||||
if(GetLastError() == ERROR_IO_PENDING) {
|
if(GetLastError() == ERROR_IO_PENDING) {
|
||||||
|
@ -115,11 +76,11 @@ static DWORD WINAPI tapreader(void *bla) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bufs[bufno].len = len;
|
EnterCriticalSection(&mutex);
|
||||||
if(send(sock, &bufno, 1, 0) <= 0)
|
packet.len = len;
|
||||||
return -1;
|
packet.priority = 0;
|
||||||
if(++bufno >= nbufs)
|
route(myself, &packet);
|
||||||
bufno = 0;
|
LeaveCriticalSection(&mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,44 +201,6 @@ bool setup_device(void)
|
||||||
overwrite_mac = 1;
|
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 */
|
/* Start the tap reader */
|
||||||
|
|
||||||
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
|
||||||
|
@ -287,15 +210,6 @@ bool setup_device(void)
|
||||||
return false;
|
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 */
|
/* Set media status for newer TAP-Win32 devices */
|
||||||
|
|
||||||
status = true;
|
status = true;
|
||||||
|
@ -320,25 +234,7 @@ void close_device(void)
|
||||||
|
|
||||||
bool read_packet(vpn_packet_t *packet)
|
bool read_packet(vpn_packet_t *packet)
|
||||||
{
|
{
|
||||||
unsigned char bufno;
|
return false;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool write_packet(vpn_packet_t *packet)
|
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;
|
max = listen_socket[i].udp;
|
||||||
}
|
}
|
||||||
|
|
||||||
FD_SET(device_fd, readset);
|
if(device_fd >= 0)
|
||||||
|
FD_SET(device_fd, readset);
|
||||||
if(device_fd > max)
|
if(device_fd > max)
|
||||||
max = device_fd;
|
max = device_fd;
|
||||||
|
|
||||||
|
@ -294,7 +295,7 @@ static void check_network_activity(fd_set * readset, fd_set * writeset)
|
||||||
cp();
|
cp();
|
||||||
|
|
||||||
/* check input from kernel */
|
/* check input from kernel */
|
||||||
if(FD_ISSET(device_fd, readset)) {
|
if(device_fd >= 0 && FD_ISSET(device_fd, readset)) {
|
||||||
if(read_packet(&packet)) {
|
if(read_packet(&packet)) {
|
||||||
packet.priority = 0;
|
packet.priority = 0;
|
||||||
route(myself, &packet);
|
route(myself, &packet);
|
||||||
|
@ -378,7 +379,13 @@ int main_loop(void)
|
||||||
|
|
||||||
maxfd = build_fdset(&readset, &writeset);
|
maxfd = build_fdset(&readset, &writeset);
|
||||||
|
|
||||||
|
#ifdef HAVE_MINGW
|
||||||
|
LeaveCriticalSection(&mutex);
|
||||||
|
#endif
|
||||||
r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
|
r = select(maxfd + 1, &readset, &writeset, NULL, &tv);
|
||||||
|
#ifdef HAVE_MINGW
|
||||||
|
EnterCriticalSection(&mutex);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(r < 0) {
|
if(r < 0) {
|
||||||
if(errno != EINTR && errno != EAGAIN) {
|
if(errno != EINTR && errno != EAGAIN) {
|
||||||
|
|
|
@ -143,6 +143,8 @@ extern void send_mtu_probe(struct node_t *);
|
||||||
|
|
||||||
#ifndef HAVE_MINGW
|
#ifndef HAVE_MINGW
|
||||||
#define closesocket(s) close(s)
|
#define closesocket(s) close(s)
|
||||||
|
#else
|
||||||
|
extern CRITICAL_SECTION mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __TINC_NET_H__ */
|
#endif /* __TINC_NET_H__ */
|
||||||
|
|
|
@ -115,6 +115,7 @@ static struct option const long_options[] = {
|
||||||
|
|
||||||
#ifdef HAVE_MINGW
|
#ifdef HAVE_MINGW
|
||||||
static struct WSAData wsa_state;
|
static struct WSAData wsa_state;
|
||||||
|
CRITICAL_SECTION mutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void usage(bool status)
|
static void usage(bool status)
|
||||||
|
@ -568,6 +569,8 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
int main2(int argc, char **argv)
|
int main2(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
InitializeCriticalSection(&mutex);
|
||||||
|
EnterCriticalSection(&mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(!detach())
|
if(!detach())
|
||||||
|
|
Loading…
Reference in a new issue