unit RIO_RAW_GetPacket;
//chatGPT写的
uses
Winapi.WinSock, Winapi.Windows;
const
IPPROTO_RIO = 0x6F;
TCP_PROTOCOL = 6;
RIO_RECV = 0;
RIO_SEND = 1;
RIO_BUF_SIZE = 1024;
type
PRIO_BUFFER = ^RIO_BUFFER;
RIO_BUFFER = packed record
Length: ULONG;
BufferId: ULONG;
end;
var
WSAData: TWSAData;
Socket: TSocket;
SockAddr: TSockAddr;
Buffer: array[0..RIO_BUF_SIZE - 1] of Byte;
function LoadRioExtensionFunctions(Socket: TSocket): Boolean;
var
Rio: RIO_EXTENSION_FUNCTION_TABLE;
RioBuffer: array[0..MAX_PATH] of Byte;
BytesReturned: DWORD;
begin
// 将 WSAIoctl 函数用于 SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER 命令以获取 RIO 扩展功能表
Result := (WSAIoctl(Socket, SIO_GET_MULTIPLE_EXTENSION_FUNCTION_POINTER,
@RioBuffer, SizeOf(RioBuffer), @Rio, SizeOf(Rio), @BytesReturned, nil, nil) = 0);
end;
function GetProcessId(const SockAddr: TSockAddr): DWORD;//TSocket转TSockAddr用getsockname
var
dwProcessId: DWORD;
begin
// 从地址中获取套接字所属进程的 ID
GetOwnerModule(SockAddr, dwProcessId);//function GetOwnerModule(SockAddr: PSockAddr; var dwProcessId: DWORD): HMODULE; stdcall; external 'iphlpapi.dll';
Result := dwProcessId;
end;
function RioGetCompletionStatus(const CQ: PRIO_CQ; const Entries: ULONG;
const NotificationCount: ULONG; const Timeout: ULONG;
out Results: PRIORESULT): ULONG;
begin
// 获取 RIO 完成队列中的完成结果
Result := RIOGetCompletionStatus(CQ, Results, Entries, NotificationCount, Timeout);
end;
procedure RioPostRecv(const Rio: RIO_EXTENSION_FUNCTION_TABLE; const RQ: PRIO_RQ;
const Buffer: PRIO_BUFFER; const DataBufferCount: ULONG; const RequestContext: Pointer);
begin
// 向 RIO 请求队列中提交接收请求
Rio.RIOReceiveEx(RQ, @Buffer, DataBufferCount, nil, nil, nil, 0, 0, RequestContext);
end;
procedure RioPostSend(const Rio: RIO_EXTENSION_FUNCTION_TABLE; const RQ: PRIO_RQ;
const Buffer: PRIO_BUFFER; const DataBufferCount: ULONG; const RequestContext: Pointer);
begin
// 向 RIO 请求队列中提交发送请求
Rio.RIOSendEx(RQ, @Buffer, DataBufferCount, nil, nil, nil, 0, 0, RequestContext);
end;
procedure ProcessPacket(const Packet: PByte; const PacketLength: DWORD);
begin
// 处理收到的网络封包
// ...
end;
procedure Main;
var
Rio: RIO_EXTENSION_FUNCTION_TABLE;
CQ: RIO_CQ;
RQ: RIO_RQ;
Buffer: array[0..RIO_BUF_SIZE - 1] of RIO_BUFFER;
RequestContext: array[0..RIO_BUF_SIZE - 1] of Pointer;
ProcessId: DWORD;
NumEntries: ULONG;
Results: array[0..RIO_BUF_SIZE - 1] of RIORESULT;
PacketLength: DWORD;
CompletionResult: ULONG;
i: Integer;
begin
// 初始化 Winsock
if WSAStartup(MAKEWORD(2, 2), WSAData) <> 0 then
begin
Exit;
end;
// 创建原始套接字并启用 RIO 扩展
Socket := WSASocket(AF_INET, SOCK_RAW, IPPROTO_RIO, nil, 0, WSA_FLAG_REGISTERED_IO);
if Socket = INVALID_SOCKET then
begin
WSACleanup;
Exit;
end;
// 绑定套接字并设置过滤器以便只接收指定进程 ID 的数据包
SockAddr.sin_family := AF_INET;
SockAddr.sin_port := htons(0);
SockAddr.sin_addr.s_addr := INADDR_ANY;
if bind(Socket, PSockAddr(@SockAddr)^, SizeOf(SockAddr)) = SOCKET_ERROR then
begin
closesocket(Socket);
WSACleanup;
Exit;
end;
ProcessId := GetCurrentProcessId;
if setsockopt(Socket, IPPROTO_IP, IP_PKTINFO, PAnsiChar(@ProcessId), SizeOf(ProcessId)) = SOCKET_ERROR then
begin
closesocket(Socket);
WSACleanup;
Exit;
end;
// 加载 RIO 扩展功能表
if not LoadRioExtensionFunctions(Socket) then
begin
closesocket(Socket);
WSACleanup;
Exit;
end;
// 创建 RIO 完成队列和请求队列
if not Rio.RIOCreateCompletionQueue(RIO_BUF_SIZE, nil, nil, 0, @CQ) then
begin
closesocket(Socket);
WSACleanup;
Exit;
end;
if not Rio.RIOCreateRequestQueue(CQ, RIO_BUF_SIZE, 1, RIO_BUF_SIZE, 1, nil, nil, nil, @RQ) then
begin
Rio.RIOCloseCompletionQueue(CQ);
closesocket(Socket);
WSACleanup;
Exit;
end;
// 向 RIO 请求队列中提交接收请求
for i := 0 to RIO_BUF_SIZE - 1 do
begin
Buffer[i].Length := RIO_BUF_SIZE;
Buffer[i].BufferId := i;
RioPostRecv(Rio, RQ, @Buffer[i], 1, @RequestContext[i]);
end;
// 循环处理网络数据包
while True do
begin
// 等待 RIO 完成队列中有完成的请求
if Rio.RIOGetCompletionStatusEx(CQ, @Results, RIO_BUF_SIZE, INFINITE, nil) = 0 then
begin
Break;
end;
// 处理完成请求
NumEntries := RioGetCompletionStatus(CQ, RIO_BUF_SIZE, 0, INFINITE, @Results);
for i := 0 to NumEntries - 1 do
begin
if Results[i].BytesTransferred > 0 then
begin
// 如果是接收请求,则处理接收到的网络数据包
if Results[i].Type_ = RIO_RECV then
begin
PacketLength := Results[i].BytesTransferred;
ProcessPacket(PByte(RequestContext[Results[i].RequestContext]), PacketLength);
// 将接收缓冲区重新提交到请求队列,等待下一次接收请求
RioPostRecv(Rio, RQ, @Buffer[Results[i].BufferId], 1, RequestContext[Results[i].RequestContext]);
end;
end else begin
// 如果是发送请求,则处理发送完成事件
if Results[i].Type_ = RIO_SEND then
begin
// 发送完成事件不需要做任何处理
end;
end;
end;
end;
// 关闭 RIO 对象和套接字
Rio.RIOCloseRequestQueue(RQ);
Rio.RIOCloseCompletionQueue(CQ);
closesocket(Socket);
WSACleanup;
end;
Windows新异步网络编程模型4 RIO-RAW封包拦截
于 2023-02-26 01:07:15 首次发布