api: upgrade ring management
- Return pointer to ring buffer with packet data allowing clients to read/write directly. This eliminates one memcpy(). - Make sending/receiving packets thread-safe. Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
parent
202f1dc9b8
commit
2439b05212
26
README.md
26
README.md
@ -59,8 +59,10 @@ Once adapter is created, use the following functions to start a session and tran
|
|||||||
- `WintunEndSession()` ends and frees the session.
|
- `WintunEndSession()` ends and frees the session.
|
||||||
- `WintunIsPacketAvailable()` checks if there is a receive packet available.
|
- `WintunIsPacketAvailable()` checks if there is a receive packet available.
|
||||||
- `WintunWaitForPacket()` waits for a receive packet to become available.
|
- `WintunWaitForPacket()` waits for a receive packet to become available.
|
||||||
- `WintunReceivePackets()` receives one or more packets.
|
- `WintunReceivePacket()` receives one packet.
|
||||||
- `WintunSendPackets()` sends one or more packets.
|
- `WintunReceiveRelease()` releases internal buffer after client processed the receive packet.
|
||||||
|
- `WintunAllocateSendPacket()` allocates memory for send packet.
|
||||||
|
- `WintunSendPacket()` sends the packet.
|
||||||
|
|
||||||
#### Writing to and from rings
|
#### Writing to and from rings
|
||||||
|
|
||||||
@ -73,12 +75,13 @@ for (;;) {
|
|||||||
WintunWaitForPacket(Session, INFINITE);
|
WintunWaitForPacket(Session, INFINITE);
|
||||||
for (WINTUN_PACKET *p = Queue; p && p->Size <= WINTUN_MAX_IP_PACKET_SIZE; p = p->Next)
|
for (WINTUN_PACKET *p = Queue; p && p->Size <= WINTUN_MAX_IP_PACKET_SIZE; p = p->Next)
|
||||||
p->Size = DWORD_MAX;
|
p->Size = DWORD_MAX;
|
||||||
DWORD Result = WintunReceivePackets(Session, Queue);
|
BYTE *Packet;
|
||||||
if (Result != ERROR_SUCCESS && Result != ERROR_NO_MORE_ITEMS)
|
DWORD PacketSize;
|
||||||
|
DWORD Result = WintunReceivePacket(Session, &Packet, &PacketSize);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
return Result;
|
return Result;
|
||||||
for (WINTUN_PACKET *p = Queue; p && p->Size <= WINTUN_MAX_IP_PACKET_SIZE; p = p->Next) {
|
// TODO: Process packet.
|
||||||
// TODO: Process packet p.
|
WintunReceiveRelease(Session, Packet);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -87,8 +90,13 @@ It may be desirable to spin on `WintunIsPacketAvailable()` for some time under h
|
|||||||
Writing packets to the adapter may be done as:
|
Writing packets to the adapter may be done as:
|
||||||
|
|
||||||
```C
|
```C
|
||||||
// TODO: Prepare WINTUN_PACKET *Queue linked list with packets.
|
// TODO: Calculate packet size.
|
||||||
DWORD Result = WintunSendPackets(Session, Queue);
|
BYTE *Packet;
|
||||||
|
DWORD Result = WintunAllocateSendPacket(Session, PacketSize, &Packet);
|
||||||
|
if (Result != ERROR_SUCCESS)
|
||||||
|
return Result;
|
||||||
|
// TODO: Fill the packet.
|
||||||
|
WintunSendPacket(Session, Packet);
|
||||||
```
|
```
|
||||||
|
|
||||||
### Misc functions
|
### Misc functions
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
EXPORTS
|
EXPORTS
|
||||||
|
WintunAllocateSendPacket
|
||||||
WintunCreateAdapter
|
WintunCreateAdapter
|
||||||
WintunDeleteAdapter
|
WintunDeleteAdapter
|
||||||
WintunEndSession
|
WintunEndSession
|
||||||
@ -11,8 +12,9 @@ EXPORTS
|
|||||||
WintunGetAdapterName
|
WintunGetAdapterName
|
||||||
WintunGetVersion
|
WintunGetVersion
|
||||||
WintunIsPacketAvailable
|
WintunIsPacketAvailable
|
||||||
WintunReceivePackets
|
WintunReceivePacket
|
||||||
WintunSendPackets
|
WintunReceiveRelease
|
||||||
|
WintunSendPacket
|
||||||
WintunSetAdapterName
|
WintunSetAdapterName
|
||||||
WintunSetLogger
|
WintunSetLogger
|
||||||
WintunStartSession
|
WintunStartSession
|
||||||
|
197
api/session.c
197
api/session.c
@ -14,12 +14,13 @@
|
|||||||
#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
|
#define TUN_RING_CAPACITY(Size) ((Size) - sizeof(TUN_RING) - (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
|
||||||
#define TUN_RING_SIZE(Capacity) (sizeof(TUN_RING) + (Capacity) + (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
|
#define TUN_RING_SIZE(Capacity) (sizeof(TUN_RING) + (Capacity) + (TUN_MAX_PACKET_SIZE - TUN_ALIGNMENT))
|
||||||
#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))
|
#define TUN_RING_WRAP(Value, Capacity) ((Value) & (Capacity - 1))
|
||||||
|
#define LOCK_SPIN_COUNT 0x10000
|
||||||
|
#define TUN_PACKET_RELEASE ((DWORD)0x80000000)
|
||||||
|
|
||||||
typedef struct _TUN_PACKET
|
typedef struct _TUN_PACKET
|
||||||
{
|
{
|
||||||
ULONG Size;
|
ULONG Size;
|
||||||
UCHAR _Field_size_bytes_(Size)
|
UCHAR Data[];
|
||||||
Data[];
|
|
||||||
} TUN_PACKET;
|
} TUN_PACKET;
|
||||||
|
|
||||||
typedef struct _TUN_RING
|
typedef struct _TUN_RING
|
||||||
@ -45,6 +46,20 @@ typedef struct _TUN_REGISTER_RINGS
|
|||||||
typedef struct _TUN_SESSION
|
typedef struct _TUN_SESSION
|
||||||
{
|
{
|
||||||
ULONG Capacity;
|
ULONG Capacity;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ULONG Tail;
|
||||||
|
ULONG TailRelease;
|
||||||
|
ULONG PacketsToRelease;
|
||||||
|
CRITICAL_SECTION Lock;
|
||||||
|
} Receive;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
ULONG Head;
|
||||||
|
ULONG HeadRelease;
|
||||||
|
ULONG PacketsToRelease;
|
||||||
|
CRITICAL_SECTION Lock;
|
||||||
|
} Send;
|
||||||
TUN_REGISTER_RINGS Descriptor;
|
TUN_REGISTER_RINGS Descriptor;
|
||||||
HANDLE Handle;
|
HANDLE Handle;
|
||||||
} TUN_SESSION;
|
} TUN_SESSION;
|
||||||
@ -52,7 +67,7 @@ typedef struct _TUN_SESSION
|
|||||||
WINTUN_STATUS WINAPI
|
WINTUN_STATUS WINAPI
|
||||||
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out_ TUN_SESSION **Session)
|
WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out_ TUN_SESSION **Session)
|
||||||
{
|
{
|
||||||
*Session = HeapAlloc(ModuleHeap, 0, sizeof(TUN_SESSION));
|
*Session = HeapAlloc(ModuleHeap, HEAP_ZERO_MEMORY, sizeof(TUN_SESSION));
|
||||||
if (!*Session)
|
if (!*Session)
|
||||||
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
return LOG(WINTUN_LOG_ERR, L"Out of memory"), ERROR_OUTOFMEMORY;
|
||||||
const ULONG RingSize = TUN_RING_SIZE(Capacity);
|
const ULONG RingSize = TUN_RING_SIZE(Capacity);
|
||||||
@ -102,6 +117,8 @@ WintunStartSession(_In_ const WINTUN_ADAPTER *Adapter, _In_ DWORD Capacity, _Out
|
|||||||
goto cleanupHandle;
|
goto cleanupHandle;
|
||||||
}
|
}
|
||||||
(*Session)->Capacity = Capacity;
|
(*Session)->Capacity = Capacity;
|
||||||
|
(void)InitializeCriticalSectionAndSpinCount(&(*Session)->Receive.Lock, LOCK_SPIN_COUNT);
|
||||||
|
(void)InitializeCriticalSectionAndSpinCount(&(*Session)->Send.Lock, LOCK_SPIN_COUNT);
|
||||||
return ERROR_SUCCESS;
|
return ERROR_SUCCESS;
|
||||||
cleanupHandle:
|
cleanupHandle:
|
||||||
CloseHandle((*Session)->Handle);
|
CloseHandle((*Session)->Handle);
|
||||||
@ -121,6 +138,8 @@ void WINAPI
|
|||||||
WintunEndSession(_In_ TUN_SESSION *Session)
|
WintunEndSession(_In_ TUN_SESSION *Session)
|
||||||
{
|
{
|
||||||
SetEvent(Session->Descriptor.Send.TailMoved); // wake the reader if it's sleeping
|
SetEvent(Session->Descriptor.Send.TailMoved); // wake the reader if it's sleeping
|
||||||
|
DeleteCriticalSection(&Session->Send.Lock);
|
||||||
|
DeleteCriticalSection(&Session->Receive.Lock);
|
||||||
CloseHandle(Session->Handle);
|
CloseHandle(Session->Handle);
|
||||||
CloseHandle(Session->Descriptor.Send.TailMoved);
|
CloseHandle(Session->Descriptor.Send.TailMoved);
|
||||||
CloseHandle(Session->Descriptor.Receive.TailMoved);
|
CloseHandle(Session->Descriptor.Receive.TailMoved);
|
||||||
@ -131,8 +150,7 @@ WintunEndSession(_In_ TUN_SESSION *Session)
|
|||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
WintunIsPacketAvailable(_In_ TUN_SESSION *Session)
|
WintunIsPacketAvailable(_In_ TUN_SESSION *Session)
|
||||||
{
|
{
|
||||||
return InterlockedGetU(&Session->Descriptor.Send.Ring->Head) !=
|
return Session->Send.Head != InterlockedGetU(&Session->Descriptor.Send.Ring->Tail);
|
||||||
InterlockedGetU(&Session->Descriptor.Send.Ring->Tail);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
WINTUN_STATUS WINAPI
|
||||||
@ -142,71 +160,126 @@ WintunWaitForPacket(_In_ TUN_SESSION *Session, _In_ DWORD Milliseconds)
|
|||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
WINTUN_STATUS WINAPI
|
||||||
WintunReceivePackets(_In_ TUN_SESSION *Session, _Inout_ WINTUN_PACKET *Queue)
|
WintunReceivePacket(_In_ TUN_SESSION *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize)
|
||||||
{
|
{
|
||||||
ULONG BuffHead = InterlockedGetU(&Session->Descriptor.Send.Ring->Head);
|
DWORD Result;
|
||||||
if (BuffHead >= Session->Capacity)
|
EnterCriticalSection(&Session->Send.Lock);
|
||||||
return ERROR_HANDLE_EOF;
|
if (Session->Send.Head >= Session->Capacity)
|
||||||
|
|
||||||
for (; Queue; Queue = Queue->Next)
|
|
||||||
{
|
{
|
||||||
const ULONG BuffTail = InterlockedGetU(&Session->Descriptor.Send.Ring->Tail);
|
Result = ERROR_HANDLE_EOF;
|
||||||
if (BuffTail >= Session->Capacity)
|
goto cleanup;
|
||||||
return ERROR_HANDLE_EOF;
|
|
||||||
|
|
||||||
if (BuffHead == BuffTail)
|
|
||||||
return ERROR_NO_MORE_ITEMS;
|
|
||||||
|
|
||||||
const ULONG BuffContent = TUN_RING_WRAP(BuffTail - BuffHead, Session->Capacity);
|
|
||||||
if (BuffContent < sizeof(TUN_PACKET))
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
|
|
||||||
const TUN_PACKET *Packet = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[BuffHead];
|
|
||||||
if (Packet->Size > WINTUN_MAX_IP_PACKET_SIZE)
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
|
|
||||||
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + Packet->Size);
|
|
||||||
if (AlignedPacketSize > BuffContent)
|
|
||||||
return ERROR_INVALID_DATA;
|
|
||||||
|
|
||||||
Queue->Size = Packet->Size;
|
|
||||||
memcpy(Queue->Data, Packet->Data, Packet->Size);
|
|
||||||
BuffHead = TUN_RING_WRAP(BuffHead + AlignedPacketSize, Session->Capacity);
|
|
||||||
InterlockedSetU(&Session->Descriptor.Send.Ring->Head, BuffHead);
|
|
||||||
}
|
}
|
||||||
|
const ULONG BuffTail = InterlockedGetU(&Session->Descriptor.Send.Ring->Tail);
|
||||||
|
if (BuffTail >= Session->Capacity)
|
||||||
|
{
|
||||||
|
Result = ERROR_HANDLE_EOF;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (Session->Send.Head == BuffTail)
|
||||||
|
{
|
||||||
|
Result = ERROR_NO_MORE_ITEMS;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
const ULONG BuffContent = TUN_RING_WRAP(BuffTail - Session->Send.Head, Session->Capacity);
|
||||||
|
if (BuffContent < sizeof(TUN_PACKET))
|
||||||
|
{
|
||||||
|
Result = ERROR_INVALID_DATA;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.Head];
|
||||||
|
if (BuffPacket->Size > WINTUN_MAX_IP_PACKET_SIZE)
|
||||||
|
{
|
||||||
|
Result = ERROR_INVALID_DATA;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
|
||||||
|
if (AlignedPacketSize > BuffContent)
|
||||||
|
{
|
||||||
|
Result = ERROR_INVALID_DATA;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
*PacketSize = BuffPacket->Size;
|
||||||
|
*Packet = BuffPacket->Data;
|
||||||
|
Session->Send.Head = TUN_RING_WRAP(Session->Send.Head + AlignedPacketSize, Session->Capacity);
|
||||||
|
Session->Send.PacketsToRelease++;
|
||||||
|
Result = ERROR_SUCCESS;
|
||||||
|
cleanup:
|
||||||
|
LeaveCriticalSection(&Session->Send.Lock);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
return ERROR_SUCCESS;
|
void WINAPI
|
||||||
|
WintunReceiveRelease(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&Session->Send.Lock);
|
||||||
|
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
|
||||||
|
ReleasedBuffPacket->Size |= TUN_PACKET_RELEASE;
|
||||||
|
while (Session->Send.PacketsToRelease)
|
||||||
|
{
|
||||||
|
const TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Send.Ring->Data[Session->Send.HeadRelease];
|
||||||
|
if ((BuffPacket->Size & TUN_PACKET_RELEASE) == 0)
|
||||||
|
break;
|
||||||
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + (BuffPacket->Size & ~TUN_PACKET_RELEASE));
|
||||||
|
Session->Send.HeadRelease = TUN_RING_WRAP(Session->Send.HeadRelease + AlignedPacketSize, Session->Capacity);
|
||||||
|
Session->Send.PacketsToRelease--;
|
||||||
|
}
|
||||||
|
InterlockedSetU(&Session->Descriptor.Send.Ring->Head, Session->Send.HeadRelease);
|
||||||
|
LeaveCriticalSection(&Session->Send.Lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
WINTUN_STATUS WINAPI
|
WINTUN_STATUS WINAPI
|
||||||
WintunSendPackets(_In_ TUN_SESSION *Session, _In_ const WINTUN_PACKET *Queue)
|
WintunAllocateSendPacket(_In_ TUN_SESSION *Session, _In_ DWORD PacketSize, _Out_bytecapcount_(PacketSize) BYTE **Packet)
|
||||||
{
|
{
|
||||||
ULONG BuffTail = InterlockedGetU(&Session->Descriptor.Receive.Ring->Tail);
|
DWORD Result;
|
||||||
if (BuffTail >= Session->Capacity)
|
EnterCriticalSection(&Session->Receive.Lock);
|
||||||
return ERROR_HANDLE_EOF;
|
if (Session->Receive.Tail >= Session->Capacity)
|
||||||
|
|
||||||
for (; Queue; Queue = Queue->Next)
|
|
||||||
{
|
{
|
||||||
const ULONG PacketSize = Queue->Size;
|
Result = ERROR_HANDLE_EOF;
|
||||||
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
|
goto cleanup;
|
||||||
|
|
||||||
const ULONG BuffHead = InterlockedGetU(&Session->Descriptor.Receive.Ring->Head);
|
|
||||||
if (BuffHead >= Session->Capacity)
|
|
||||||
return ERROR_HANDLE_EOF;
|
|
||||||
|
|
||||||
const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - BuffTail - TUN_ALIGNMENT, Session->Capacity);
|
|
||||||
if (AlignedPacketSize > BuffSpace)
|
|
||||||
return ERROR_BUFFER_OVERFLOW; /* Dropping when ring is full. */
|
|
||||||
|
|
||||||
TUN_PACKET *Packet = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[BuffTail];
|
|
||||||
Packet->Size = PacketSize;
|
|
||||||
memcpy(Packet->Data, Queue->Data, PacketSize);
|
|
||||||
BuffTail = TUN_RING_WRAP(BuffTail + AlignedPacketSize, Session->Capacity);
|
|
||||||
InterlockedSetU(&Session->Descriptor.Receive.Ring->Tail, BuffTail);
|
|
||||||
|
|
||||||
if (InterlockedGet(&Session->Descriptor.Receive.Ring->Alertable))
|
|
||||||
SetEvent(Session->Descriptor.Receive.TailMoved);
|
|
||||||
}
|
}
|
||||||
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + PacketSize);
|
||||||
return ERROR_SUCCESS;
|
const ULONG BuffHead = InterlockedGetU(&Session->Descriptor.Receive.Ring->Head);
|
||||||
|
if (BuffHead >= Session->Capacity)
|
||||||
|
{
|
||||||
|
Result = ERROR_HANDLE_EOF;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
const ULONG BuffSpace = TUN_RING_WRAP(BuffHead - Session->Receive.Tail - TUN_ALIGNMENT, Session->Capacity);
|
||||||
|
if (AlignedPacketSize > BuffSpace)
|
||||||
|
{
|
||||||
|
Result = ERROR_BUFFER_OVERFLOW;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
TUN_PACKET *BuffPacket = (TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.Tail];
|
||||||
|
BuffPacket->Size = PacketSize | TUN_PACKET_RELEASE;
|
||||||
|
*Packet = BuffPacket->Data;
|
||||||
|
Session->Receive.Tail = TUN_RING_WRAP(Session->Receive.Tail + AlignedPacketSize, Session->Capacity);
|
||||||
|
Session->Receive.PacketsToRelease++;
|
||||||
|
Result = ERROR_SUCCESS;
|
||||||
|
cleanup:
|
||||||
|
LeaveCriticalSection(&Session->Receive.Lock);
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WINAPI
|
||||||
|
WintunSendPacket(_In_ TUN_SESSION *Session, _In_ const BYTE *Packet)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&Session->Receive.Lock);
|
||||||
|
TUN_PACKET *ReleasedBuffPacket = (TUN_PACKET *)(Packet - offsetof(TUN_PACKET, Data));
|
||||||
|
ReleasedBuffPacket->Size &= ~TUN_PACKET_RELEASE;
|
||||||
|
while (Session->Receive.PacketsToRelease)
|
||||||
|
{
|
||||||
|
const TUN_PACKET *BuffPacket =
|
||||||
|
(TUN_PACKET *)&Session->Descriptor.Receive.Ring->Data[Session->Receive.TailRelease];
|
||||||
|
if (BuffPacket->Size & TUN_PACKET_RELEASE)
|
||||||
|
break;
|
||||||
|
const ULONG AlignedPacketSize = TUN_ALIGN(sizeof(TUN_PACKET) + BuffPacket->Size);
|
||||||
|
Session->Receive.TailRelease =
|
||||||
|
TUN_RING_WRAP(Session->Receive.TailRelease + AlignedPacketSize, Session->Capacity);
|
||||||
|
Session->Receive.PacketsToRelease--;
|
||||||
|
}
|
||||||
|
InterlockedSetU(&Session->Descriptor.Receive.Ring->Tail, Session->Receive.TailRelease);
|
||||||
|
if (InterlockedGet(&Session->Descriptor.Receive.Ring->Alertable))
|
||||||
|
SetEvent(Session->Descriptor.Receive.TailMoved);
|
||||||
|
LeaveCriticalSection(&Session->Receive.Lock);
|
||||||
}
|
}
|
||||||
|
92
api/wintun.h
92
api/wintun.h
@ -260,27 +260,6 @@ typedef void(WINAPI *WINTUN_END_SESSION_FUNC)(_In_ WINTUN_SESSION_HANDLE Session
|
|||||||
*/
|
*/
|
||||||
#define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF
|
#define WINTUN_MAX_IP_PACKET_SIZE 0xFFFF
|
||||||
|
|
||||||
/**
|
|
||||||
* Packet with data
|
|
||||||
*/
|
|
||||||
typedef struct _WINTUN_PACKET
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Pointer to next packet in queue
|
|
||||||
*/
|
|
||||||
struct _WINTUN_PACKET *Next;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of packet (max WINTUN_MAX_IP_PACKET_SIZE).
|
|
||||||
*/
|
|
||||||
DWORD Size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pointer to layer 3 IPv4 or IPv6 packet
|
|
||||||
*/
|
|
||||||
BYTE *Data;
|
|
||||||
} WINTUN_PACKET;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Peeks if there is a packet available for reading.
|
* Peeks if there is a packet available for reading.
|
||||||
*
|
*
|
||||||
@ -302,42 +281,67 @@ BOOL(WINAPI *WINTUN_IS_PACKET_AVAILABLE_FUNC)(_In_ WINTUN_SESSION_HANDLE Session
|
|||||||
*
|
*
|
||||||
* @return See WaitForSingleObject() for return values.
|
* @return See WaitForSingleObject() for return values.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS(WINAPI *WINTUN_WAIT_FOR_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD Milliseconds);
|
typedef WINTUN_STATUS(WINAPI *WINTUN_WAIT_FOR_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ DWORD Milliseconds);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads one or more packets.
|
* Retrieves one or packet. After the packet content is consumed, call WintunReceiveRelease with Packet returned
|
||||||
|
* from this function to release internal buffer. This function is thread-safe.
|
||||||
*
|
*
|
||||||
* @param Session Wintun session handle obtained with WintunStartSession
|
* @param Session Wintun session handle obtained with WintunStartSession
|
||||||
*
|
*
|
||||||
* @param Queue A linked list of nodes to fill with packets read. The list must be NULL terminated. May
|
* @param Packet Pointer to receive pointer to layer 3 IPv4 or IPv6 packet. Client may modify its content at
|
||||||
* contain only one node to read one packet at a time. All nodes should be big enough to
|
* will.
|
||||||
* accommodate WINTUN_MAX_IP_PACKET_SIZE packet. The Size field of every node should be
|
|
||||||
* initialized to something bigger than WINTUN_MAX_IP_PACKET_SIZE allowing post-festum
|
|
||||||
* detection which nodes were actually filled with packets.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @param PacketSize Pointer to receive Packet size.
|
||||||
* ERROR_HANDLE_EOF Wintun adapter is terminating.
|
*
|
||||||
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted.
|
* @return Returns one of the following values:
|
||||||
* ERROR_INVALID_DATA Wintun buffer is corrupt.
|
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
||||||
* ERROR_SUCCESS Requested amount of packets was read successfully.
|
* ERROR_NO_MORE_ITEMS Wintun buffer is exhausted;
|
||||||
|
* ERROR_INVALID_DATA Wintun buffer is corrupt;
|
||||||
|
* ERROR_SUCCESS on success.
|
||||||
* Regardless, if the error was returned, some packets might have been read nevertheless.
|
* Regardless, if the error was returned, some packets might have been read nevertheless.
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS(WINAPI *WINTUN_RECEIVE_PACKETS_FUNC)
|
typedef WINTUN_STATUS(WINAPI *WINTUN_RECEIVE_PACKETS_FUNC)
|
||||||
(_In_ WINTUN_SESSION_HANDLE Session, _Inout_ WINTUN_PACKET *Queue);
|
(_In_ WINTUN_SESSION_HANDLE *Session, _Out_bytecapcount_(*PacketSize) BYTE **Packet, _Out_ DWORD *PacketSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends packets.
|
* Releases internal buffer after the received packet has been processed by the client. This function is thread-safe.
|
||||||
*
|
*
|
||||||
* @param Session Wintun session handle obtained with WintunStartSession
|
* @param Session Wintun session handle obtained with WintunStartSession
|
||||||
*
|
*
|
||||||
* @param Queue Linked list of packets to send. The list must be NULL terminated.
|
* @param Packet Packet obtained with WintunReceivePacket
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* ERROR_HANDLE_EOF Wintun adapter is terminating.
|
|
||||||
* ERROR_BUFFER_OVERFLOW Wintun buffer is full. One or more packets were dropped.
|
|
||||||
* ERROR_SUCCESS All packets were sent successfully.
|
|
||||||
*/
|
*/
|
||||||
WINTUN_STATUS(WINAPI *WINTUN_SEND_PACKETS_FUNC)(_In_ WINTUN_SESSION_HANDLE Session, _In_ const WINTUN_PACKET *Queue);
|
typedef void(WINAPI *WINTUN_RECEIVE_RELEASE_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _In_ const BYTE *Packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates memory for a packet to send. After the memory is filled with packet data, call WintunSendPacket to send
|
||||||
|
* and release internal buffer. WintunAllocateSendPacket is thread-safe and the WintunAllocateSendPacket order of
|
||||||
|
* calls define the packet sending order.
|
||||||
|
*
|
||||||
|
* @param Session Wintun session handle obtained with WintunStartSession
|
||||||
|
*
|
||||||
|
* @param PacketSize Exact packet size. Must be less or equal to WINTUN_MAX_IP_PACKET_SIZE.
|
||||||
|
*
|
||||||
|
* @param Packet Pointer to receive pointer to memory where to prepare layer 3 IPv4 or IPv6 packet for sending.
|
||||||
|
*
|
||||||
|
* @return Returns one of the following values:
|
||||||
|
* ERROR_HANDLE_EOF Wintun adapter is terminating;
|
||||||
|
* ERROR_BUFFER_OVERFLOW Wintun buffer is full;
|
||||||
|
* ERROR_SUCCESS on success.
|
||||||
|
*/
|
||||||
|
typedef WINTUN_STATUS(WINAPI *WINTUN_ALLOCATE_SEND_PACKET_FUNC)
|
||||||
|
(_In_ WINTUN_SESSION_HANDLE *Session, _In_ DWORD PacketSize, _Out_bytecapcount_(PacketSize) BYTE **Packet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the packet and releases internal buffer. WintunSendPacket is thread-safe, but the WintunAllocateSendPacket
|
||||||
|
* order of calls define the packet sending order. This means the packet is not guaranteed to be sent in the
|
||||||
|
* WintunSendPacket yet.
|
||||||
|
*
|
||||||
|
* @param Session Wintun session handle obtained with WintunStartSession
|
||||||
|
*
|
||||||
|
* @param Packet Packet obtained with WintunAllocateSendPacket
|
||||||
|
*/
|
||||||
|
typedef void(WINAPI *WINTUN_SEND_PACKET_FUNC)(_In_ WINTUN_SESSION_HANDLE *Session, _In_ const BYTE *Packet);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user