tinc is using a separate thread to read from the TAP device on Windows.
The rationale was that the notification mechanism for packets arriving
on the virtual network device is based on Win32 events, and the event
loop did not support listening to these events.
Thanks to recent improvements, this event loop limitation has been
lifted. Therefore we can get rid of the separate thread and simply add
the Win32 "incoming packet" event to the event loop, just like a socket.
The result is cleaner code that's easier to reason about.
DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
if (!event_count) {
DWORD timeout_ms = tv ? (tv->tv_sec * 1000 + tv->tv_usec / 1000 + 1) : WSA_INFINITE;
if (!event_count) {
- LeaveCriticalSection(&mutex);
- EnterCriticalSection(&mutex);
- LeaveCriticalSection(&mutex);
DWORD result = WSAWaitForMultipleEvents(event_count, events, FALSE, timeout_ms, FALSE);
DWORD result = WSAWaitForMultipleEvents(event_count, events, FALSE, timeout_ms, FALSE);
- EnterCriticalSection(&mutex);
WSAEVENT event;
if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + event_count)
WSAEVENT event;
if (result >= WSA_WAIT_EVENT_0 && result < WSA_WAIT_EVENT_0 + event_count)
-void event_flush_output(void) {
- for splay_each(io_t, io, &io_tree)
- if(io->flags & IO_WRITE)
- io->cb(io->data, IO_WRITE);
-}
-
void event_exit(void) {
running = false;
}
void event_exit(void) {
running = false;
}
extern void signal_del(signal_t *sig);
extern bool event_loop(void);
extern void signal_del(signal_t *sig);
extern bool event_loop(void);
-extern void event_flush_output(void);
extern void event_exit(void);
#endif
extern void event_exit(void);
#endif
int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE;
int device_fd = -1;
static HANDLE device_handle = INVALID_HANDLE_VALUE;
+static io_t device_read_io;
+static OVERLAPPED device_read_overlapped;
+static vpn_packet_t device_read_packet;
char *device = NULL;
char *iface = NULL;
static char *device_info = NULL;
char *device = NULL;
char *iface = NULL;
static char *device_info = NULL;
-static DWORD WINAPI tapreader(void *bla) {
- int status;
- DWORD len;
- OVERLAPPED overlapped;
- vpn_packet_t packet;
-
- logger(DEBUG_ALWAYS, LOG_DEBUG, "Tap reader running");
-
- /* Read from tap device and send to parent */
+static void device_issue_read() {
+ device_read_overlapped.Offset = 0;
+ device_read_overlapped.OffsetHigh = 0;
- overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ int status = ReadFile(device_handle, (void *)device_read_packet.data, MTU, NULL, &device_read_overlapped);
- for(;;) {
- overlapped.Offset = 0;
- overlapped.OffsetHigh = 0;
- ResetEvent(overlapped.hEvent);
-
- status = ReadFile(device_handle, (void *)packet.data, MTU, &len, &overlapped);
+ if(!status && GetLastError() != ERROR_IO_PENDING) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
+ device, strerror(errno));
+ }
+}
- if(!status) {
- if(GetLastError() == ERROR_IO_PENDING) {
- WaitForSingleObject(overlapped.hEvent, INFINITE);
- if(!GetOverlappedResult(device_handle, &overlapped, &len, FALSE))
- continue;
- } else {
- logger(DEBUG_ALWAYS, LOG_ERR, "Error while reading from %s %s: %s", device_info,
- device, strerror(errno));
- return -1;
- }
- }
+static void device_handle_read(void *data) {
+ ResetEvent(device_read_overlapped.hEvent);
- EnterCriticalSection(&mutex);
- packet.len = len;
- packet.priority = 0;
- route(myself, &packet);
- event_flush_output();
- LeaveCriticalSection(&mutex);
+ DWORD len;
+ if (!GetOverlappedResult(device_handle, &device_read_overlapped, &len, FALSE)) {
+ logger(DEBUG_ALWAYS, LOG_ERR, "Error getting read result from %s %s: %s", device_info,
+ device, strerror(errno));
+ return;
+
+ device_read_packet.len = len;
+ device_read_packet.priority = 0;
+ route(myself, &device_read_packet);
+ device_issue_read();
}
static bool setup_device(void) {
}
static bool setup_device(void) {
/* Start the tap reader */
/* Start the tap reader */
- thread = CreateThread(NULL, 0, tapreader, NULL, 0, NULL);
-
- if(!thread) {
- logger(DEBUG_ALWAYS, LOG_ERR, "System call `%s' failed: %s", "CreateThread", winerror(GetLastError()));
- return false;
- }
+ io_add_event(&device_read_io, device_handle_read, NULL, CreateEvent(NULL, TRUE, FALSE, NULL));
+ device_read_overlapped.hEvent = device_read_io.event;
+ device_issue_read();
device_info = "Windows tap device";
device_info = "Windows tap device";
}
static void close_device(void) {
}
static void close_device(void) {
+ io_del(&device_read_io);
+ CancelIo(device_handle);
+ CloseHandle(device_read_overlapped.hEvent);
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
free(device); device = NULL;
CloseHandle(device_handle); device_handle = INVALID_HANDLE_VALUE;
free(device); device = NULL;
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
#ifndef HAVE_MINGW
#define closesocket(s) close(s)
-#else
-extern CRITICAL_SECTION mutex;
#endif
#endif /* __TINC_NET_H__ */
#endif
#endif /* __TINC_NET_H__ */
#ifdef HAVE_MINGW
static struct WSAData wsa_state;
#ifdef HAVE_MINGW
static struct WSAData wsa_state;
int main2(int argc, char **argv);
#endif
int main2(int argc, char **argv);
#endif
}
int main2(int argc, char **argv) {
}
int main2(int argc, char **argv) {
- InitializeCriticalSection(&mutex);
- EnterCriticalSection(&mutex);
#endif
char *priority = NULL;
#endif
char *priority = NULL;