Skip to content

Instantly share code, notes, and snippets.

@dechamps
Last active December 7, 2020 00:20
Show Gist options
  • Save dechamps/c4e9adb432c09dc3f1c8 to your computer and use it in GitHub Desktop.
Save dechamps/c4e9adb432c09dc3f1c8 to your computer and use it in GitHub Desktop.
TAP-Win32 trivial test program
#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