Last active
December 7, 2020 00:20
-
-
Save dechamps/c4e9adb432c09dc3f1c8 to your computer and use it in GitHub Desktop.
TAP-Win32 trivial test program
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <Windows.h> | |
#include "tap-windows.h" | |
static void winerror(const char* message) | |
{ | |
int err = GetLastError(); | |
fprintf(stderr, "%s: (%d) ", message, err); | |
char buf[1024]; | |
if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof buf, NULL)) | |
strncpy_s(buf, sizeof buf, "(unable to format errormessage)", _TRUNCATE); | |
fprintf(stderr, "%s", buf); | |
exit(1); | |
} | |
static void sync(HANDLE device) | |
{ | |
char packet[1518]; | |
DWORD packetlen; | |
printf("Reading one packet\n"); | |
if (ReadFile(device, packet, sizeof packet, &packetlen, NULL) == 0) | |
winerror("Unable to read packet"); | |
printf("Successfully read one packet of size %d\n", packetlen); | |
printf("Writing the packet back\n"); | |
DWORD writelen; | |
if (WriteFile(device, packet, packetlen, &writelen, NULL) == 0) | |
winerror("Unable to write packet"); | |
printf("Successfully wrote %d bytes\n", writelen); | |
} | |
static void async(HANDLE device) | |
{ | |
char packet[1518]; | |
DWORD packetlen; | |
{ | |
printf("Reading one packet\n"); | |
OVERLAPPED overlapped = {0}; | |
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
if (ReadFile(device, packet, sizeof packet, &packetlen, &overlapped) == 0) | |
{ | |
if (GetLastError() != ERROR_IO_PENDING) | |
winerror("Unable to read packet"); | |
printf("Waiting for read event\n"); | |
if (WaitForSingleObject(overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) | |
winerror("Unable to wait on read event"); | |
printf("Done waiting for read event, getting overlapped status\n"); | |
if (GetOverlappedResult(device, &overlapped, &packetlen, FALSE) == 0) | |
winerror("Unable to get overlapped result"); | |
} | |
printf("Successfully read one packet of size %d\n", packetlen); | |
CloseHandle(overlapped.hEvent); | |
} | |
{ | |
printf("Writing the packet back\n"); | |
OVERLAPPED overlapped = {0}; | |
overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
DWORD writelen; | |
if (WriteFile(device, packet, packetlen, &writelen, &overlapped) == 0) | |
{ | |
if (GetLastError() != ERROR_IO_PENDING) | |
winerror("Unable to write packet"); | |
printf("Waiting for write event\n"); | |
if (WaitForSingleObject(overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) | |
winerror("Unable to wait on write event"); | |
printf("Done waiting for write event, getting overlapped status\n"); | |
if (GetOverlappedResult(device, &overlapped, &writelen, FALSE) == 0) | |
winerror("Unable to get overlapped result"); | |
} | |
printf("Successfully wrote %d bytes\n", writelen); | |
CloseHandle(overlapped.hEvent); | |
} | |
} | |
static void event_loop(HANDLE device) | |
{ | |
char packet_read[1518]; | |
char packet_write[1518]; | |
DWORD packetlen = 0; | |
DWORD writelen; | |
HANDLE event_read = CreateEvent(NULL, FALSE, FALSE, NULL); | |
HANDLE event_write = CreateEvent(NULL, FALSE, FALSE, NULL); | |
OVERLAPPED overlapped_read = {0}; | |
OVERLAPPED overlapped_write = {0}; | |
overlapped_read.hEvent = INVALID_HANDLE_VALUE; | |
overlapped_write.hEvent = INVALID_HANDLE_VALUE; | |
for (;;) | |
{ | |
if (packetlen > 0 && overlapped_write.hEvent == INVALID_HANDLE_VALUE) | |
{ | |
printf("Writing the packet back\n"); | |
memcpy(packet_write, packet_read, packetlen); | |
memset(&overlapped_write, 0, sizeof overlapped_write); | |
overlapped_write.hEvent = event_write; | |
if (WriteFile(device, packet_write, packetlen, &writelen, &overlapped_write) != 0) | |
{ | |
printf("Successfully wrote %d bytes\n", writelen); | |
break; | |
} | |
else if (GetLastError() != ERROR_IO_PENDING) | |
winerror("Unable to write packet"); | |
} | |
if (overlapped_read.hEvent == INVALID_HANDLE_VALUE) | |
{ | |
printf("Reading one packet\n"); | |
packetlen = 0; | |
memset(&overlapped_read, 0, sizeof overlapped_read); | |
overlapped_read.hEvent = event_read; | |
if (ReadFile(device, packet_read, sizeof packet_read, &packetlen, &overlapped_read) != 0) | |
{ | |
printf("Successfully read one packet of size %d\n", packetlen); | |
overlapped_read.hEvent = INVALID_HANDLE_VALUE; | |
continue; | |
} | |
else if (GetLastError() != ERROR_IO_PENDING) | |
winerror("Unable to read packet"); | |
} | |
printf("Waiting for events\n"); | |
HANDLE events[] = { event_read, event_write }; | |
const size_t event_count = sizeof(events) / sizeof(HANDLE); | |
DWORD result = WaitForMultipleObjects(event_count, events, FALSE, INFINITE); | |
if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0 + event_count) | |
winerror("Unable to wait for multiple objects"); | |
result -= WAIT_OBJECT_0; | |
if (events[result] == event_read) | |
{ | |
printf("Read event fired, getting overlapped results\n"); | |
if (GetOverlappedResult(device, &overlapped_read, &packetlen, FALSE) == 0) | |
winerror("Unable to get overlapped result"); | |
printf("Successfully read one packet of size %d\n", packetlen); | |
overlapped_read.hEvent = INVALID_HANDLE_VALUE; | |
} | |
if (events[result] == event_write) | |
{ | |
printf("Write event fired, getting overlapped results\n"); | |
if (GetOverlappedResult(device, &overlapped_write, &writelen, FALSE) == 0) | |
winerror("Unable to get overlapped result"); | |
printf("Successfully wrote %d bytes\n", writelen); | |
break; | |
} | |
} | |
CloseHandle(overlapped_read.hEvent); | |
CloseHandle(overlapped_write.hEvent); | |
} | |
int main(int argc, char** argv) | |
{ | |
if (argc != 3) | |
{ | |
fprintf(stderr, "usage: tap-win32-test <mode> <adapter ID>\n"); | |
fprintf(stderr, "mode can be:\n"); | |
fprintf(stderr, " sync: synchronous I/O\n"); | |
fprintf(stderr, " async: asynchronous I/O\n"); | |
fprintf(stderr, " event_loop: event loop simulation\n"); | |
fprintf(stderr, "adapter ID is the key name below HKEY_LOCAL_MACHINE\\%s\n", NETWORK_CONNECTIONS_KEY); | |
return 1; | |
} | |
const char* mode = argv[1]; | |
const char* adapterid = argv[2]; | |
DWORD open_flags = 0; | |
void(*proc)(HANDLE); | |
if (strcmp(mode, "sync") == 0) | |
proc = sync; | |
else if (strcmp(mode, "async") == 0) | |
{ | |
proc = async; | |
open_flags |= FILE_FLAG_OVERLAPPED; | |
} | |
else if (strcmp(mode, "eventloop") == 0) | |
{ | |
proc = event_loop; | |
open_flags |= FILE_FLAG_OVERLAPPED; | |
} | |
else | |
{ | |
fprintf(stderr, "invalid mode\n"); | |
return 1; | |
} | |
char path[1024]; | |
_snprintf_s(path, sizeof path, _TRUNCATE, "%s%s%s", USERMODEDEVICEDIR, adapterid, TAP_WIN_SUFFIX); | |
printf("Opening device with path: %s\n", path); | |
HANDLE device = CreateFile(path, GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | open_flags, 0); | |
if (device == INVALID_HANDLE_VALUE) | |
winerror("Unable to open device"); | |
printf("Device successfully opened\n", path); | |
{ | |
ULONG status = 1; | |
DWORD len; | |
printf("Setting media status to connected\n"); | |
if (DeviceIoControl(device, TAP_WIN_IOCTL_SET_MEDIA_STATUS, &status, sizeof status, &status, sizeof status, &len, NULL) == 0) | |
winerror("Unable to set media status"); | |
printf("Media status set\n"); | |
} | |
proc(device); | |
printf("Closing device"); | |
if (CloseHandle(device) == 0) | |
winerror("Unable to close device"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment