10.2.2 Packet.dll库中相应函数的实现
PacketReceivePacket函数用于从NPF驱动程序中读取数据,其原型如下:
BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,
LPPACKET lpPacket,BOOLEAN Sync)
上述函数中,参数AdapterObject指向一个_ADAPTER结构体,它标识接收数据的网络适配器;参数lpPacket指向一个包含所需读取数据的PACKET结构体;参数Sync主要是用来兼容以前版本的应用程序,现在并不使用。
如果PacketReceivePacket函数执行成功则返回非0值。
该函数所接收的数据可能包含一组数据包数据或一组网络统计信息,这取决于驱动程序的工作模式,该工作模式可采用PacketSetMode函数设置。此处我们不关注统计信息的格式(若想了解相关信息,可参见第11章),只关注在数据包捕获模式下返回的数据格式。图10-5所示为驱动程序传递给用户空间的数据格式。
图 10-5 NPF驱动程序传递给用户空间的数据格式
驱动程序给每一个数据包添加一个头信息(由bpf_hdr结构体描述),该头信息中包含数据包的长度与数据包被接收的时间。结构体bpf_hdr的具体定义如下:
struct bpf_hdr{
struct timeval bh_tstamp;/数据包被接收的时间/
bpf_u_int32 bh_caplen;/所捕获的数据包长度/
bpf_u_int32 bh_datalen;/原始数据包长度/
u_short bh_hdrlen;/结构体bpf_hdr的长度(该结构体编译对齐后的大小)/
};
图10-5所示中填充内容的作用是实现缓冲区内数据的字对齐(为了加速数据包的访问)。
数据包存储在与lpPacket参数(_PACKET结构体)相关联的缓冲区中,由该结构体的Buffer成员指定该缓冲区,_PACKET结构体的Length成员随复制到该缓冲区的数据量而更新。PacketReceivePacket函数所接收的数据包个数是可变的,这与当前存储在驱动程序缓冲区中的数据包个数、这些数据包的大小以及与lpPacket参数相关联的缓冲区的大小有关。
PacketReceivePacket函数的具体实现代码如下:
BOOLEAN PacketReceivePacket(LPADAPTER AdapterObject,
LPPACKET lpPacket,BOOLEAN Sync)
{
BOOLEAN res;
if(AdapterObject->Flags==INFO_FLAG_NDIS_ADAPTER)
{
if((int)AdapterObject->ReadTimeOut!=-1)
{
//等待读取事件
WaitForSingleObject(
AdapterObject->ReadEvent,
(AdapterObject->ReadTimeOut==0)?
INFINITE:AdapterObject->ReadTimeOut);
}
/读取数据/
res=(BOOLEAN)ReadFile(
AdapterObject->hFile,
lpPacket->Buffer,
lpPacket->Length,
&lpPacket->ulBytesReceived,
NULL);
}
return res;
}
在上面的代码中,如果AdapterObject->ReadTimeOut的值为0,那么就给WaitForSingleObject函数传递INFINITE参数值,表示永远等待,只有当读取事件被激活时才结束等待。函数最终通过ReadFile系统调用实现数据包的读取功能。