深度剖析WinPcap之(八)――打开与关闭适配器(7)

1.5      packet.dll对应的函数接口

下面对各函数在 packet.dll 中的实现进行详细分析。

1.5.1        关键结构体

结构体_ADAPTER描述了一个打开的适配器,该结构体对packet.dll的函数非常重要,不过大部分成员对用户而言都可不用关心,因为该库原本就是为了避免用户处理底层的参数而设计的。该结构体的定义如下:
typedef struct _ADAPTER  {
    HANDLE hFile;               // 指向一个NPF驱动程序实例的句柄
    CHAR  SymbolicLink[MAX_LINK_NAME_LENGTH]; // 保存当前打开网络适配器的名称
    int NumWrites;              // 对每个数据包重复发送的次数
    HANDLE ReadEvent;           // 与适配器上读调用关联的通知事件
    UINT ReadTimeOut;           // 读超时时间
    CHAR Name[ADAPTER_NAME_LENGTH];
    PWAN_ADAPTER pWanAdapter;
    UINT Flags;                 // 适配器标识
}  ADAPTER, *LPADAPTER;
结构体_PACKET包含了从驱动程序来的一组数据包。该结构体定义了与每个递送给应用程序的数据包相关联的包头。结构体的定义如下:
typedef struct _PACKET { 
    PVOID        Buffer;        // 存储数据包的缓冲区。参见PacketReceivePacket()了解缓冲区中的数据组织形式。
    UINT         Length;        // 缓冲区的长度
    DWORD        ulBytesReceived;   // 缓冲区中的有效字节数,如最后调用PacketReceivePacket所接收的数据量
}  PACKET, *LPPACKET;
结构体_PACKET_OID_DATA包含一个OID请求。它被PacketRequest函数使用来发送一个OID请求给接口卡驱动程序。它也能被用来获取诸如适配器的错误计数、MAC地址、多播列表,等信息。结构体的定义如下:
struct _PACKET_OID_DATA {
    ULONG Oid;                  //OID 码。 参见Microsoft DDK文档或文件 ntddndis.h获得一个有效编码的完整列表。
    ULONG Length;               //Data 成员的长度。
UCHAR Data[1];              // 变长成员,包含传递到适配器或从适配器接收的信息
};
typedef struct _PACKET_OID_DATA PACKET_OID_DATA, *PPACKET_OID_DATA;

1.5.2        PacketOpenAdapter函数

在库wpcap.dllpcap_activate_win32()函数调用 PacketOpenAdapter() 函数打开适配器。函数PacketOpenAdapter()的作用就是打开一个适配器。函数原型如下:
LPADAPTER PacketOpenAdapter(PCHAR AdapterNameWA)
参数AdapterNameWA字符串包含待打开设备的名称。函数调用PacketOpenAdapterNPF()函数获取可用的设备列表。
函数如果成功,返回一个已经正确初始化的ADAPTER对象的指针。否则返回NULL
函数的主要代码如下:
LPADAPTER PacketOpenAdapter(PCHAR AdapterNameWA)
{
   
    /* 检查适配器的名称是否为ASCII码字符串,如果不是,执行转换*/
    if(AdapterNameWA[1]!=0)
    {   // ASCII码字符串
        bFreeAdapterNameA = FALSE;
        AdapterNameA = AdapterNameWA;
    }
    else
    {   // Unicode码字符串,转换为ASCII码字符串
        size_t bufferSize = wcslen((PWCHAR)AdapterNameWA) + 1;
        AdapterNameA = GlobalAllocPtr(GPTR, bufferSize);
 
        if (AdapterNameA == NULL)
        {// 分配错误,函数返回
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
            return NULL;
        }
 
        StringCchPrintfA(AdapterNameA, bufferSize, "%ws",
                            (PWCHAR)AdapterNameWA);
        bFreeAdapterNameA = TRUE;
    }
/* 获得g_AdaptersInfoMutex互斥信号*/
    WaitForSingleObject(g_AdaptersInfoMutex, INFINITE);
   
/* 查找适配器,并打开它*/
    do
    {  
        // 第一次查找给定适配器的PADAPTER_INFO结构体
        TAdInfo = PacketFindAdInfo(AdapterNameA);
        if(TAdInfo == NULL)
        {// 没有找到,更新链表,然后执行第二次查找
            PacketUpdateAdInfo(AdapterNameA);
            TAdInfo = PacketFindAdInfo(AdapterNameA);
        }
 
        if(TAdInfo == NULL)
        {// 出错处理,跳出do…while循环
            break;
        }
 
   
// 找到适配器,检查适配器的类型,查看它是否被正确的支持,
// 此处我们只考虑正常的NPF适配器
#ifdef HAVE_WANPACKET_API
        if(TAdInfo->Flags == INFO_FLAG_NDISWAN_ADAPTER)
        {
           
            break;
        }
#endif //HAVE_WANPACKET_API
 
        if(TAdInfo->Flags == INFO_FLAG_DONT_EXPORT)
        {
            // 该适配器不允许被导出,跳出循环
 
break ;
        }
       
        if (TAdInfo->Flags != INFO_FLAG_NDIS_ADAPTER)
        {// 打开不明标识的适配器,跳出循环
            break;
        }
 
        // 正常的NPF适配器,试图打开它   
        lpAdapter = PacketOpenAdapterNPF(AdapterNameA);
        if (lpAdapter == NULL)
        {// 打开失败
            dwLastError = GetLastError();
        }
 
    }while(FALSE);
 
/* 释放g_AdaptersInfoMutex互斥信号*/
    ReleaseMutex(g_AdaptersInfoMutex);
 
   /* 如果执行了Unicode转换,释放所用的内存*/
    if (bFreeAdapterNameA)
GlobalFree(AdapterNameA);
 
   /* 函数返回*/
    if (dwLastError != ERROR_SUCCESS)
    {// 函数失败,返回NULL
        SetLastError(dwLastError);
        return NULL;
    }
    else
    {// 函数成功,返回所打开的适配器关联的结构体指针
        return lpAdapter;
    }
}
函数首先检查适配器的名称是否为 ASCII 码字符串,如果不是,执行 Unicode 码到 ASCII 码的转换。
然后获得 g_AdaptersInfoMutex 互斥信号,调用 PacketFindAdInfo() 函数 开始在 g_AdaptersInfoList 链表中 查找适配器。如果第一次没有查到,调用 PacketUpdateAdInfo() 函数更新该链表,执行第二次查找。
如果找到适配器,检查适配器的类型,查看它是否被正确的支持,我们只考虑正常的 NPF 适配器。
如果是正常的 NPF 适配器,调用 PacketOpenAdapterNPF() 函数 打开它。  
然后释放 g_AdaptersInfoMutex 互斥信号,如果执行了 Unicode 转换,释放所用的内存。
最后,如果函数成功,则返回与打开适配器关联的结构体指针 lpAdapter ,否则返回NULL

你可能感兴趣的:(职场,休闲,winpcap)