剖析WinPcap之(三)——所涉及的Windows驱动基础知识(2)

本文转自http://eslxf.blog.51cto.com/918801/196913

 

1.5.1        同步处理

    Windows 是个多任务抢占式的操作系统,如果没有同步机制的控制,所有的线程会任意运行。如果多个线程要求操作同一个资源,这时就需要同步处理。如果驱动程序没有很好地处理同步问题,程序会出错误、操作系统的性能下降、甚至出现死锁等现象。
1.5.1.1     自旋锁
     自旋锁是一种同步处理机制,它能保证某个资源只能被一个线程所拥有,可用于驱动程序的同步处理。自旋锁的作用一般是使各派遣函数之间同步。
初始化的自旋锁处于解锁状态,这时它可以被程序“获取”。“获取”后的自旋锁处于锁住状态,不能被再次“获取”。锁住的自旋锁必须被“释放”后,才能再次被“获取”。如果自旋锁已被锁住,这时有程序申请“获取”这个自旋锁,程序则处于“自旋”状态。所谓自旋状态,就是不停地询问是否可以“获取”自旋锁。
自旋锁不同于线程中的等待事件。在线程中如果等待某个事件,操作系统会使这个线程进入休眠状态,CPU会运行其它的线程。而自旋锁则不同,CPU不会切换到别的线程,而是让这个线程一直“自旋”等待。因此,对自旋锁占用时间不宜过长,否则会导致申请自旋锁的其它线程处于自旋,浪费CPU的处理时间。
NDIS库提供的自旋锁可用来在相同IRQL的线程之间同步访问共享资源,当共享资源的两个线程运行在不同的IRQL时,NDIS库提供一种机制临时提升低IRQL代码的IRQL,从而达到对共享资源的串行访问。
NDIS库的自旋锁用 NDIS_SPIN_LOCK 数据结构表示。
使用自旋锁前,首先对其初始化,可使用NdisAllocateSpinLock函数。
VOID  NdisAllocateSpinLock(  IN PNDIS_SPIN_LOCK  SpinLock  );
申请获得自旋锁可以使用 NdisAcquireSpinLock函数。
VOID   NdisAcquireSpinLock( IN PNDIS_SPIN_LOCK  SpinLock  );
释放自旋锁使用NdisReleaseSpinLock内核函数,
VOID NdisReleaseSpinLock(IN PNDIS_SPIN_LOCK  SpinLock );
下面的代码为WinPcap中使用自旋锁的实例:
NDIS_SPIN_LOCK      WriteLock; //在_OPEN_INSTANCE声明自旋锁
 
NdisAllocateSpinLock(&Open->WriteLock); //初始化自旋所
 
NdisAcquireSpinLock(&Open->WriteLock); // 申请获得自旋锁
        if(Open->WriteInProgress)
        {
            NdisReleaseSpinLock(&Open->WriteLock);  // 释放自旋锁
            SET_FAILURE_UNSUCCESSFUL();
            break;
        }
        else
        {
            Open->WriteInProgress = TRUE;
        }
    NdisReleaseSpinLock(&Open->WriteLock); // 释放自旋锁
 
1.1.5.2     用户模式的等待
在应用程序中,可以使用 WaitForSingleObject 等待一个同步对象。 WaitForSingleObject 函数声明如下:
DWORD WaitForSingleObject( 
    HANDLE hHandle,      //同步对象句柄
DWORD  dwMilliseconds  //等待时间
);
第二个参数 dwMiUiseconds 是等待时间,单位为毫秒。同步对象有两种状态,一种是激发状态,一种是未激发状态。如果同步对象处于未激发状态, WaitForSingleObject 则进入休眠,等待同步对象被激发。如果同步对象在指定的等待时间内,还没有处于激发状态,则自动停止休眠。 dwMilliseconds 也可以设定为 INFINITE .这表示无限期地等待下去。另外, dwMilliseconds 也可以为 0 ,其作用是强迫操作系统将当前线程切换到其他线程。
 
1.1.5.3   用户模式的事件
     事件是一种典型的同步对象。用户模式下的事件和内核模式的事件对象紧密相连。在使用事件之前,需要对事件进行初始化,使用 CreateEvent 函数。
HANDLE CreateEvent(
  LPSECURITY_ATTRIBUTES lpEventAttributes // 安全属性
  BOOL bManualReset,                        // 复位方式
  BOOL bInitialState,                       // 初始化状态
  LPCTSTR lpName                            // 对象名称
);
CreateEvent 函数会使操作系统创建一个内核事件对象。 CreateEvent 返回的句柄值就代表了这个内核事件对象。应用程序无法获得这个内核事件对象的指针,而用一个句柄(一个 32 位的无符号整数)代表事件对象。一般情况下, CreateEvent 的安全属性设置为 NULL 。它的第二个参数 bManualReset ,表示创建的事件是否是手动模式。如果是手动模式的事件,事件处于激发状态后,需要手动设置才能回到未激发状态。如果是自动模式,当事件处于激发状态后,遇到任意一个等待 (WaitForSingleObject) ,则自动变回未激发状态。
下面的代码为WinPcap中 创建一个事件 的实例:
HANDLE hEvent;
    hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
1.1.5.4 NDIS库提供的事件
NDIS 库的事件用 NDIS_EVENT 数据结构表示。
使用事件前,首先对其初始化,可使用 NdisInitializeEvent 函数。
VOID NdisInitializeEvent(IN PNDIS_EVENT  Event);
 
把调用者置为等待状态,直到给定的事件为信号状态,或等待超时,可以使用  NdisWaitEvent 函数。
BOOLEAN NdisWaitEvent(IN PNDIS_EVENT  Event,IN UINT  MsToWait); 
 
把一个给定的事件设为信号状态  ,可使用 NdisSetEvent 函数,
VOID NdisSetEvent(IN PNDIS_EVENT  Event);
 
清除一个给定的事件的信号状态,可使用 NdisResetEvent 函数,
VOID NdisResetEvent(IN PNDIS_EVENT  Event);
 
下面的代码为WinPcap中使用NDIS库事件的实例:
NDIS_EVENT         NdisWriteCompleteEvent;
 
NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NdisInitializeEvent(&Open->NdisWriteCompleteEvent);
}
 
NTSTATUS NPF_Write(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
NdisResetEvent(&Open->NdisWriteCompleteEvent);
NdisWaitEvent(&Open->NdisWriteCompleteEvent, 0);
    …
}
VOID NPF_SendComplete(IN NDIS_HANDLE   ProtocolBindingContext,
                   IN PNDIS_PACKET  pPacket,IN NDIS_STATUS   Status)
                  
{
    NdisSetEvent(&Open->NdisWriteCompleteEvent);
}
 
1.1.5.5     用户模式的互斥体
     互斥体也是一种常用的同步对象。互斥体可以避免多个线程争夺同一个资源。例如,多线程环境中,只能有一个线程占有互斥体。获得互斥体的线程如果不释放互斥体,其他线程永远不会获得这个互斥体。互斥体的概念类似于同步事件,所不同的是同一个线程可以递归获得互斥体。递归获得互斥体的意思是,得到互斥体的线程还可以再次获得这个互斥体,或者说互斥体对于已经获得互斥体的线程不产生“互斥”关系。而同步事件不能递归获取。
     互斥体也有两种状态,激发态和未激发态。如果线程获得互斥体时,此时的状态是未激发态,当释放互斥体时,互斥体的状态为激发态。
初始化互斥体的函数是 CreateMutex ,其函数声明如下;
HANDLE CreateMutex(
  LPSECURITY_ATTRIBUTES lpMutexAttributes,  //安全属性
  BOOL bInitialOwner,                       //初始化的占有状态
  LPCTSTR lpName                            //对象名称
);
     其中第二个参数 blIutialOwner 表明初始化时是否被占有。如果没有被占有,则为激发态,否则为未激发态。另外,获得互斥体的函数是 WaitForSingleObject 函数,而释放互斥体的函数是 ReleaseMutex 函数。
下面的代码为WinPcap中使用 使用互斥体 的实例:
HANDLE g_AdaptersInfoMutex = NULL;
g_AdaptersInfoMutex = CreateMutex(NULL, FALSE, NULL);
 
WaitForSingleObject(g_AdaptersInfoMutex, INFINITE);
ReleaseMutex(g_AdaptersInfoMutex);
 
1.1.5.6   变量的原子操作
内核提供了对一个变量进行原子操作,如递增、递减或设置指定的值,的函数。
对一个变量进行原子递增操作,可使用InterlockedIncrement函数。
LONG InterlockedIncrement(IN PLONG  Addend);
参数Addend指向一个  LONG型的变量。
函数返回递增了的值。
 
对一个变量进行原子递减操作,可使用InterlockedDecrement函数。
LONG InterlockedDecrement (IN PLONG  Addend);
参数Addend指向一个  LONG型的变量。
函数返回递减了的值。
 
对一个变量进行原子设置指定值的操作,可使用InterlockedExchange函数。
LONG InterlockedExchange(IN OUT PLONG  Target,IN LONG  Value);
参数Target指向一个  需要进行设置的LONG型变量,参数Value 为需要设置的值。
函数返回 参数Target所指的初始值。
 
下面的代码为WinPcap中使用原子操作的实例:
ULONG g_NumOpenedInstances = 0;
 
NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
localNumOpenedInstances =
InterlockedIncrement(&g_NumOpenedInstances);
    …
}
 
NTSTATUS NPF_Cleanup(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
{
localNumOpenInstances =
InterlockedDecrement(&g_NumOpenedInstances);
    …
}

什么是WinPcap WinPcap是一个基于Win32平台的,用于捕获网络数据包并进行分析的开源库. 大多数网络应用程序通过被广泛使用的操作系统元件来访问网络,比如sockets。 这是一种简单的实现方式,因为操作系统已经妥善处理了底层具体实现细节(比如协议处理,封装数据包等等),并且提供了一个与读写文件类似的,令人熟悉的接口。 然而,有些时候,这种“简单的方式”并不能满足任务的需求,因为有些应用程序需要直接访问网络中的数据包。也就是说,那些应用程序需要访问原始数据包,即没有被操作系统利用网络协议处理过的数据包。 WinPcap产生的目的,就是为Win32应用程序提供这种访问方式; WinPcap提供了以下功能 捕获原始数据包,无论它是发往某台机器的,还是在其他设备(共享媒介)上进行交换的 在数据包发送给某应用程序前,根据用户指定的规则过滤数据包 将原始数据包通过网络发送出去 收集并统计网络流量信息 以上这些功能需要借助安装在Win32内核中的网络设备驱动程序才能实现,再加上几个动态链接库DLL。 所有这些功能都能通过一个强大的编程接口来表现出来,易于开发,并能在不同的操作系统上使用。这本手册的主要目标是在一些程序范例的帮助下,叙述这些编程接口的使用。 如果您现在就想开始摸索这些功能,您可以直接进入 WinPcap用户手册. 哪些程序在使用WinPcap WinPcap可以被用来制作许多类型的网络工具,比如具有分析,解决纷争,安全和监视功能的工具。特别地,一些基于WinPcap的典型应用有: 网络与协议分析器 (network and protocol analyzers) 网络监视器 (network monitors) 网络流量记录器 (traffic loggers) 网络流量发生器 (traffic generators) 用户级网桥及路由 (user-level bridges and routers) 网络入侵检测系统 (network intrusion detection systems (NIDS)) 网络扫描器 (network scanners) 安全工具 (security tools) 什么是WinPcap做不到的 WinPcap能 独立地 通过主机协议发送和接受数据,如同TCP-IP。这就意味着WinPcap不能阻止、过滤或操纵同一机器上的其他应用程序的通讯:它仅仅能简单地"监视"在网络上传输的数据包。所以,它不能提供类似网络流量控制、服务质量调度和个人防火墙之类的支持
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值