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.2.2 Packet.dll库中相应函数的实现 - 图1

图 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系统调用实现数据包的读取功能。