@ -1,254 +1,182 @@
// tun_windows.c - Windows Wintun implementation
// Uses Wintun.dll for TUN device access
# include "tun_if.h"
// tun_windows.c - Wintun implementation
# include "../lib/debug_config.h"
# include "../lib/wintun.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "../lib/u_async.h"
# include "tun_if.h"
# include "wintun.h"
# include "ll_queue.h" // ← добавлено
# include "etcp.h" // ← добавлено (struct ETCP_FRAGMENT)
# include <windows.h>
# include <iphlpapi.h>
# include <ws2tcpip.h>
# include <stdio.h>
// Wintun function pointers (wintun.h defines types as functions, need pointer syntax)
// Wintun function pointers
static HMODULE wintun_dll = NULL ;
static WINTUN_CREATE_ADAPTER_FUNC * WintunCreateAdapter = NULL ;
static WINTUN_CLOSE_ADAPTER_FUNC * WintunCloseAdapter = NULL ;
static WINTUN_OPEN_ADAPTER_FUNC * WintunOpenAdapter = NULL ;
static WINTUN_GET_ADAPTER_LUID_FUNC * WintunGetAdapterLUID = NULL ;
static WINTUN_START_SESSION_FUNC * WintunStartSession = NULL ;
static WINTUN_END_SESSION_FUNC * WintunEndSession = NULL ;
static WINTUN_GET_READ_WAIT_EVENT_FUNC * WintunGetReadWaitEvent = NULL ;
static WINTUN_RECEIVE_PACKET_FUNC * WintunReceivePacket = NULL ;
static WINTUN_RELEASE_RECEIVE_PACKET_FUNC * WintunReleaseReceivePacket = NULL ;
static WINTUN_ALLOCATE_SEND_PACKET_FUNC * WintunAllocateSendPacket = NULL ;
static WINTUN_SEND_PACKET_FUNC * WintunSendPacket = NULL ;
// Load Wintun.dll and resolve function pointers
static int wintun_load_dll ( void ) {
if ( wintun_dll ) {
return 0 ; // Already loaded
}
static WINTUN_CREATE_ADAPTER_FUNC * WintunCreateAdapter = NULL ;
static WINTUN_CLOSE_ADAPTER_FUNC * WintunCloseAdapter = NULL ;
static WINTUN_OPEN_ADAPTER_FUNC * WintunOpenAdapter = NULL ;
static WINTUN_GET_ADAPTER_LUID_FUNC * WintunGetAdapterLUID = NULL ;
static WINTUN_START_SESSION_FUNC * WintunStartSession = NULL ;
static WINTUN_END_SESSION_FUNC * WintunEndSession = NULL ;
static WINTUN_GET_READ_WAIT_EVENT_FUNC * WintunGetReadWaitEvent = NULL ;
static WINTUN_RECEIVE_PACKET_FUNC * WintunReceivePacket = NULL ;
static WINTUN_RELEASE_RECEIVE_PACKET_FUNC * WintunReleaseReceivePacket = NULL ;
static WINTUN_ALLOCATE_SEND_PACKET_FUNC * WintunAllocateSendPacket = NULL ;
static WINTUN_SEND_PACKET_FUNC * WintunSendPacket = NULL ;
static int wintun_load_dll ( void )
{
if ( wintun_dll ) return 0 ;
// Try to load from the same directory as executable
wchar_t path [ MAX_PATH ] ;
DWORD path_len = GetModuleFileNameW ( NULL , path , MAX_PATH ) ;
if ( path_len > 0 & & path_len < MAX_PATH ) {
// Find last backslash
for ( int i = path_len - 1 ; i > = 0 ; i - - ) {
if ( GetModuleFileNameW ( NULL , path , MAX_PATH ) ) {
for ( int i = ( int ) wcslen ( path ) - 1 ; i > = 0 ; i - - ) {
if ( path [ i ] = = L ' \\ ' | | path [ i ] = = L ' / ' ) {
path [ i + 1 ] = L ' \0 ' ;
path [ i + 1 ] = L ' \0 ' ;
wcscat ( path , L " wintun.dll " ) ;
wintun_dll = LoadLibraryW ( path ) ;
break ;
}
}
wcscat ( path , L " wintun.dll " ) ;
wintun_dll = LoadLibraryW ( path ) ;
}
if ( ! wintun_dll ) wintun_dll = LoadLibraryA ( " wintun.dll " ) ;
// If not found in executable directory, try system directories
if ( ! wintun_dll ) {
wintun_dll = LoadLibraryA ( " wintun.dll " ) ;
}
if ( ! wintun_dll ) {
// Try to construct full path for error message
wchar_t full_path [ MAX_PATH ] ;
GetCurrentDirectoryW ( MAX_PATH , full_path ) ;
wcscat ( full_path , L " \\ wintun.dll " ) ;
char path_utf8 [ MAX_PATH ] ;
WideCharToMultiByte ( CP_UTF8 , 0 , full_path , - 1 , path_utf8 , MAX_PATH , NULL , NULL ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to load wintun.dll from: %s " , path_utf8 ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Please ensure wintun.dll is in the same directory as the executable " ) ;
fprintf ( stderr , " FATAL ERROR: wintun.dll not found at: %s \n " , path_utf8 ) ;
fprintf ( stderr , " Please download Wintun from https://www.wintun.net/ \n " ) ;
fprintf ( stderr , " and place wintun.dll in the same directory as utun.exe \n " ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " wintun.dll not found " ) ;
return - 1 ;
}
// Resolve function pointers (cast to void* first to avoid errors)
WintunCreateAdapter = ( WINTUN_CREATE_ADAPTER_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunCreateAdapter " ) ;
WintunCloseAdapter = ( WINTUN_CLOSE_ADAPTER_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunCloseAdapter " ) ;
WintunOpenAdapter = ( WINTUN_OPEN_ADAPTER_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunOpenAdapter " ) ;
WintunGetAdapterLUID = ( WINTUN_GET_ADAPTER_LUID_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunGetAdapterLUID " ) ;
WintunStartSession = ( WINTUN_START_SESSION_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunStartSession " ) ;
WintunEndSession = ( WINTUN_END_SESSION_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunEndSession " ) ;
WintunGetReadWaitEvent = ( WINTUN_GET_READ_WAIT_EVENT_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunGetReadWaitEvent " ) ;
WintunReceivePacket = ( WINTUN_RECEIVE_PACKET_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunReceivePacket " ) ;
WintunReleaseReceivePacket = ( WINTUN_RELEASE_RECEIVE_PACKET_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunReleaseReceivePacket " ) ;
WintunAllocateSendPacket = ( WINTUN_ALLOCATE_SEND_PACKET_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunAllocateSendPacket " ) ;
WintunSendPacket = ( WINTUN_SEND_PACKET_FUNC * ) ( void * ) GetProcAddress ( wintun_dll , " WintunSendPacket " ) ;
// Check that all functions were resolved
WintunCreateAdapter = ( WINTUN_CREATE_ADAPTER_FUNC * ) GetProcAddress ( wintun_dll , " WintunCreateAdapter " ) ;
WintunCloseAdapter = ( WINTUN_CLOSE_ADAPTER_FUNC * ) GetProcAddress ( wintun_dll , " WintunCloseAdapter " ) ;
WintunOpenAdapter = ( WINTUN_OPEN_ADAPTER_FUNC * ) GetProcAddress ( wintun_dll , " WintunOpenAdapter " ) ;
WintunGetAdapterLUID = ( WINTUN_GET_ADAPTER_LUID_FUNC * ) GetProcAddress ( wintun_dll , " WintunGetAdapterLUID " ) ;
WintunStartSession = ( WINTUN_START_SESSION_FUNC * ) GetProcAddress ( wintun_dll , " WintunStartSession " ) ;
WintunEndSession = ( WINTUN_END_SESSION_FUNC * ) GetProcAddress ( wintun_dll , " WintunEndSession " ) ;
WintunGetReadWaitEvent = ( WINTUN_GET_READ_WAIT_EVENT_FUNC * ) GetProcAddress ( wintun_dll , " WintunGetReadWaitEvent " ) ;
WintunReceivePacket = ( WINTUN_RECEIVE_PACKET_FUNC * ) GetProcAddress ( wintun_dll , " WintunReceivePacket " ) ;
WintunReleaseReceivePacket = ( WINTUN_RELEASE_RECEIVE_PACKET_FUNC * ) GetProcAddress ( wintun_dll , " WintunReleaseReceivePacket " ) ;
WintunAllocateSendPacket = ( WINTUN_ALLOCATE_SEND_PACKET_FUNC * ) GetProcAddress ( wintun_dll , " WintunAllocateSendPacket " ) ;
WintunSendPacket = ( WINTUN_SEND_PACKET_FUNC * ) GetProcAddress ( wintun_dll , " WintunSendPacket " ) ;
if ( ! WintunCreateAdapter | | ! WintunCloseAdapter | | ! WintunOpenAdapter | |
! WintunGetAdapterLUID | | ! WintunStartSession | | ! WintunEndSession | |
! WintunGetReadWaitEvent | | ! WintunReceivePacket | | ! WintunReleaseReceivePacket | |
! WintunAllocateSendPacket | | ! WintunSendPacket ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to resolve some Wintun functions " ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to resolve Wintun functions " ) ;
FreeLibrary ( wintun_dll ) ;
wintun_dll = NULL ;
return - 1 ;
}
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Wintun.dll loaded successfully " ) ;
return 0 ;
}
// Unload Wintun.dll
static void wintun_unload_dll ( void ) {
if ( wintun_dll ) {
FreeLibrary ( wintun_dll ) ;
wintun_dll = NULL ;
WintunCreateAdapter = NULL ;
WintunCloseAdapter = NULL ;
WintunOpenAdapter = NULL ;
WintunGetAdapterLUID = NULL ;
WintunStartSession = NULL ;
WintunEndSession = NULL ;
WintunGetReadWaitEvent = NULL ;
WintunReceivePacket = NULL ;
WintunReleaseReceivePacket = NULL ;
WintunAllocateSendPacket = NULL ;
WintunSendPacket = NULL ;
}
}
// Set IP address and MTU using IP Helper API
static int wintun_set_ip_and_mtu ( const NET_LUID * luid , const char * ip_str , int mtu ) {
// Parse IP address (remove /32 suffix if present)
char ip_copy [ 64 ] ;
strncpy ( ip_copy , ip_str , sizeof ( ip_copy ) - 1 ) ;
ip_copy [ sizeof ( ip_copy ) - 1 ] = ' \0 ' ;
char * slash = strchr ( ip_copy , ' / ' ) ;
if ( slash ) * slash = ' \0 ' ;
// ===================================================================
// Helper: set IP + MTU + bring interface up
// ===================================================================
static int wintun_configure_interface ( WINTUN_ADAPTER_HANDLE adapter , const char * ip_str , int mtu )
{
NET_LUID luid ;
WintunGetAdapterLUID ( adapter , & luid ) ;
// Convert IP string to sockaddr
SOCKADDR_INET addr ;
memset ( & addr , 0 , sizeof ( addr ) ) ;
addr . si_family = AF_INET ;
char ip_only [ 64 ] = { 0 } ;
int prefix = 32 ;
if ( ip_str ) {
strncpy ( ip_only , ip_str , sizeof ( ip_only ) - 1 ) ;
char * slash = strchr ( ip_only , ' / ' ) ;
if ( slash ) {
* slash = ' \0 ' ;
prefix = atoi ( slash + 1 ) ;
if ( prefix < 0 | | prefix > 32 ) prefix = 32 ;
}
}
if ( inet_pton ( AF_INET , ip_copy , & addr . Ipv4 . sin_addr ) ! = 1 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to parse IP address: %s " , ip_copy ) ;
struct in_addr addr ;
if ( inet_pton ( AF_INET , ip_only , & addr ) ! = 1 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Invalid IP: %s " , ip_str ) ;
return - 1 ;
}
// Get interface index from LUID
NET_IFINDEX ifindex ;
if ( ConvertInterfaceLuidToIndex ( luid , & ifindex ) ! = NO_ERROR ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to convert LUID to interface index " ) ;
// IP address
MIB_UNICASTIPADDRESS_ROW row = { 0 } ;
InitializeUnicastIpAddressEntry ( & row ) ;
row . Address . si_family = AF_INET ;
row . Address . Ipv4 . sin_family = AF_INET ;
row . Address . Ipv4 . sin_addr . s_addr = addr . s_addr ;
row . InterfaceLuid = luid ;
row . OnLinkPrefixLength = ( UINT8 ) prefix ;
row . DadState = IpDadStatePreferred ;
row . SuffixOrigin = IpSuffixOriginManual ;
row . PrefixOrigin = IpPrefixOriginManual ;
DWORD err = CreateUnicastIpAddressEntry ( & row ) ;
if ( err ! = NO_ERROR & & err ! = ERROR_OBJECT_ALREADY_EXISTS ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " CreateUnicastIpAddressEntry failed: %lu " , err ) ;
return - 1 ;
}
// Set MTU first using MIB_IPINTERFACE_ROW (minimal required fields)
MIB_IPINTERFACE_ROW row ;
memset ( & row , 0 , sizeof ( row ) ) ;
row . Family = AF_INET ;
row . InterfaceLuid = * luid ;
row . NlMtu = mtu ;
DWORD ret = SetIpInterfaceEntry ( & row ) ;
if ( ret ! = NO_ERROR & & ret ! = ERROR_OBJECT_ALREADY_EXISTS ) {
DEBUG_WARN ( DEBUG_CATEGORY_TUN , " Failed to set MTU: %lu " , ret ) ;
// MTU
if ( mtu > 0 ) {
MIB_IPINTERFACE_ROW ifRow = { 0 } ;
InitializeIpInterfaceEntry ( & ifRow ) ;
ifRow . Family = AF_INET ;
ifRow . InterfaceLuid = luid ;
if ( GetIpInterfaceEntry ( & ifRow ) = = NO_ERROR ) {
ifRow . NlMtu = mtu ;
SetIpInterfaceEntry ( & ifRow ) ;
}
}
// Add unicast IP address
MIB_UNICASTIPADDRESS_ROW addr_row ;
InitializeUnicastIpAddressEntry ( & addr_row ) ;
addr_row . InterfaceLuid = * luid ;
addr_row . Address = addr ;
addr_row . OnLinkPrefixLength = 32 ; // /32 for point-to-point
addr_row . ValidLifetime = 0xffffffff ;
addr_row . PreferredLifetime = 0xffffffff ;
ret = CreateUnicastIpAddressEntry ( & addr_row ) ;
if ( ret ! = NO_ERROR ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to set IP address: %lu " , ret ) ;
return - 1 ;
// Bring UP
NET_IFINDEX idx = 0 ;
if ( ConvertInterfaceLuidToIndex ( & luid , & idx ) = = NO_ERROR ) {
MIB_IFROW ifr = { 0 } ;
ifr . dwIndex = idx ;
if ( GetIfEntry ( & ifr ) = = NO_ERROR ) {
ifr . dwAdminStatus = MIB_IF_ADMIN_STATUS_UP ;
SetIfEntry ( & ifr ) ;
}
}
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " IP address %s and MTU %d configured successfully " , ip_copy , mtu ) ;
return 0 ;
}
// Platform-specific initialization for Windows
int tun_platform_init ( struct tun_if * tun , const char * ifname , const char * ip_str , int mtu ) {
// Load Wintun.dll
if ( wintun_load_dll ( ) ! = 0 ) {
return - 1 ;
}
// Generate adapter name
const WCHAR * adapter_name = L " utun " ;
const WCHAR * tunnel_type = L " utun " ;
// ===================================================================
// Platform functions
// ===================================================================
int tun_platform_init ( struct tun_if * tun , const char * ifname , const char * ip_str , int mtu )
{
if ( wintun_load_dll ( ) ! = 0 ) return - 1 ;
// Use provided name or default
wchar_t wname [ 128 ] ;
if ( ifname & & ifname [ 0 ] ! = ' \0 ' ) {
wchar_t wname [ 128 ] = L " utun " ;
if ( ifname & & ifname [ 0 ] )
MultiByteToWideChar ( CP_UTF8 , 0 , ifname , - 1 , wname , 128 ) ;
adapter_name = wname ;
}
// Try to open existing adapter first
WINTUN_ADAPTER_HANDLE adapter = WintunOpenAdapter ( adapter_name ) ;
WINTUN_ADAPTER_HANDLE adapter = WintunCreateAdapter ( wname , L " utun " , NULL ) ;
if ( ! adapter ) {
DWORD err = GetLastError ( ) ;
if ( err = = ERROR_NOT_FOUND | | err = = ERROR_FILE_NOT_FOUND ) { // 1168 or 2
// Adapter does not exist → safe to create a new one
adapter = WintunCreateAdapter ( adapter_name , tunnel_type , NULL ) ;
if ( ! adapter ) {
err = GetLastError ( ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to create new Wintun adapter: %lu " , err ) ;
return - 1 ;
}
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Created new Wintun adapter: %s " , tun - > ifname ) ;
} else {
// Some other real failure (e.g. access denied, driver not loaded, etc.)
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to open existing Wintun adapter: %lu " , err ) ;
return - 1 ;
}
} else {
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Opened existing Wintun adapter: %s " , tun - > ifname ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " WintunCreateAdapter failed: %lu " , GetLastError ( ) ) ;
return - 1 ;
}
// Get adapter LUID for IP configuration
NET_LUID luid ;
WintunGetAdapterLUID ( adapter , & luid ) ;
// Start Wintun session
WINTUN_SESSION_HANDLE session = WintunStartSession ( adapter , WINTUN_MIN_RING_CAPACITY ) ;
WINTUN_SESSION_HANDLE session = WintunStartSession ( adapter , 0x400000 ) ; // 4 MiB ring
if ( ! session ) {
DWORD err = GetLastError ( ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to start Wintun session: %lu " , err ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " WintunStartSession failed: %lu " , GetLastError ( ) ) ;
WintunCloseAdapter ( adapter ) ;
return - 1 ;
}
// Store handles
tun - > adapter_handle = adapter ;
tun - > platform_handle = session ;
// Set IP and MTU
if ( wintun_set_ip_and_mtu ( & luid , ip_str , mtu ) ! = 0 ) {
if ( wintun_configure_interface ( adapter , ip_str , mtu ) ! = 0 ) {
WintunEndSession ( session ) ;
WintunCloseAdapter ( adapter ) ;
tun - > adapter_handle = NULL ;
tun - > platform_handle = NULL ;
return - 1 ;
}
// Store interface name
strncpy ( tun - > ifname , ifname & & ifname [ 0 ] ? ifname : " utun " , sizeof ( tun - > ifname ) - 1 ) ;
tun - > ifname [ sizeof ( tun - > ifname ) - 1 ] = ' \0 ' ;
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Wintun adapter created: %s " , tun - > ifname ) ;
tun - > platform_handle = session ;
tun - > adapter_handle = adapter ;
strncpy ( tun - > ifname , ifname & & ifname [ 0 ] ? ifname : " utun " , sizeof ( tun - > ifname ) - 1 ) ;
return 0 ;
}
// Platform-specific cleanup for Windows
void tun_platform_cleanup ( struct tun_if * tun ) {
void tun_platform_cleanup ( struct tun_if * tun )
{
if ( tun - > platform_handle ) {
WintunEndSession ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle ) ;
tun - > platform_handle = NULL ;
@ -259,81 +187,101 @@ void tun_platform_cleanup(struct tun_if* tun) {
}
}
// Platform-specific read for Windows
ssize_t tun_platform_read ( struct tun_if * tun , uint8_t * buf , size_t len ) {
( void ) len ; // Wintun handles packet size
if ( ! tun - > platform_handle ) {
ssize_t tun_platform_read ( struct tun_if * tun , uint8_t * buf , size_t len )
{
if ( ! tun - > platform_handle ) return - 1 ;
DWORD size ;
BYTE * pkt = WintunReceivePacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , & size ) ;
if ( ! pkt ) {
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS ) return 0 ;
return - 1 ;
}
if ( size > len ) size = ( DWORD ) len ;
memcpy ( buf , pkt , size ) ;
WintunReleaseReceivePacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , pkt ) ;
return ( ssize_t ) size ;
}
DWORD packet_size ;
BYTE * packet = WintunReceivePacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , & packet_size ) ;
if ( ! packet ) {
DWORD err = GetLastError ( ) ;
if ( err = = ERROR_NO_MORE_ITEMS ) {
return 0 ; // No data available (non-blocking)
}
if ( err = = ERROR_HANDLE_EOF ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Wintun adapter closed " ) ;
return - 1 ;
}
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Wintun receive error: %lu " , err ) ;
return - 1 ;
}
ssize_t tun_platform_write ( struct tun_if * tun , const uint8_t * buf , size_t len )
{
if ( ! tun - > platform_handle ) return - 1 ;
BYTE * pkt = WintunAllocateSendPacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , ( DWORD ) len ) ;
if ( ! pkt ) return - 1 ;
memcpy ( pkt , buf , len ) ;
WintunSendPacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , pkt ) ;
return ( ssize_t ) len ;
}
// Copy packet data
if ( packet_size > len ) {
packet_size = ( DWORD ) len ; // Truncate if buffer too small
int tun_platform_get_poll_fd ( struct tun_if * tun )
{
( void ) tun ;
return - 1 ;
}
// ===================================================================
// Windows-only notify
// ===================================================================
static void tun_output_notify ( void * arg )
{
struct tun_if * tun = ( struct tun_if * ) arg ;
if ( tun ) {
DEBUG_DEBUG ( DEBUG_CATEGORY_TUN , " TUN read notify → output_queue (%s) " , tun - > ifname ) ;
}
memcpy ( buf , packet , packet_size ) ;
}
// Release packet back to Wintun
WintunReleaseReceivePacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , packet ) ;
// ===================================================================
// Read thread
// ===================================================================
DWORD WINAPI tun_read_thread_proc ( LPVOID arg )
{
struct tun_if * tun = ( struct tun_if * ) arg ;
HANDLE event = WintunGetReadWaitEvent ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle ) ;
if ( ! event ) return 1 ;
return ( ssize_t ) packet_size ;
}
HANDLE handles [ 2 ] = { event , tun - > stop_event } ;
// Platform-specific write for Windows
ssize_t tun_platform_write ( struct tun_if * tun , const uint8_t * buf , size_t len ) {
if ( ! tun - > platform_handle ) {
return - 1 ;
}
while ( tun - > running ) {
if ( WaitForMultipleObjects ( 2 , handles , FALSE , INFINITE ) ! = WAIT_OBJECT_0 )
break ;
// Allocate packet from Wintun ring
BYTE * packet = WintunAllocateSendPacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , ( DWORD ) len ) ;
if ( ! packet ) {
DWORD err = GetLastError ( ) ;
if ( err = = ERROR_HANDLE_EOF ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Wintun adapter closed " ) ;
return - 1 ;
}
if ( err = = ERROR_BUFFER_OVERFLOW ) {
DEBUG_WARN ( DEBUG_CATEGORY_TUN , " Wintun send buffer overflow " ) ;
return - 1 ;
}
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Wintun allocate packet failed: %lu " , err ) ;
return - 1 ;
}
uint8_t buf [ TUN_MAX_PACKET_SIZE ] ;
int got_packet = 0 ;
// Copy data and send
memcpy ( packet , buf , len ) ;
WintunSendPacket ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle , packet ) ;
ssize_t n ;
while ( ( n = tun_platform_read ( tun , buf , sizeof ( buf ) ) ) > 0 ) {
got_packet = 1 ;
return ( ssize_t ) len ;
}
uint8_t * data = malloc ( n ) ;
if ( ! data ) { tun - > read_errors + + ; continue ; }
memcpy ( data , buf , n ) ;
// Get poll fd for uasync
int tun_platform_get_poll_fd ( struct tun_if * tun ) {
if ( ! tun - > platform_handle ) {
return - 1 ;
}
struct ETCP_FRAGMENT * pkt = ( struct ETCP_FRAGMENT * ) queue_entry_new_from_pool ( tun - > pool ) ;
if ( ! pkt ) {
free ( data ) ;
tun - > read_errors + + ;
continue ;
}
HANDLE event = WintunGetReadWaitEvent ( ( WINTUN_SESSION_HANDLE ) tun - > platform_handle ) ;
if ( event = = NULL | | event = = INVALID_HANDLE_VALUE ) {
return - 1 ;
}
pkt - > ll . dgram = data ;
pkt - > ll . len = n ;
EnterCriticalSection ( & tun - > output_queue_lock ) ;
int ok = queue_data_put ( tun - > output_queue , ( struct ll_entry * ) pkt , 0 ) ;
LeaveCriticalSection ( & tun - > output_queue_lock ) ;
// Cast HANDLE to int for uasync (Windows specific)
return ( int ) ( intptr_t ) event ;
if ( ok ! = 0 ) {
free ( data ) ;
memory_pool_free ( tun - > pool , pkt ) ;
tun - > read_errors + + ;
} else {
tun - > bytes_read + = n ;
tun - > packets_read + + ;
}
}
if ( got_packet ) {
uasync_post ( tun - > ua , tun_output_notify , tun ) ;
}
}
return 0 ;
}